Skip to content

Instantly share code, notes, and snippets.

@benjaminaaron
Last active June 17, 2016 09:10
Show Gist options
  • Save benjaminaaron/acb5a92d43667e20b54bf2ef7a733cb7 to your computer and use it in GitHub Desktop.
Save benjaminaaron/acb5a92d43667e20b54bf2ef7a733cb7 to your computer and use it in GitHub Desktop.
Jackson: strict parsing of json-string into Map<ModelType, Attributes>
public abstract class Attributes {}
public class AttributesExample1 extends Attributes {
private String str = "foo";
private double dbl = 0.8;
private boolean bool = false;
private AttributesExample2 attributesExample2 = new AttributesExample2();
public String toString() {
return str + ", " + dbl + ", " + bool + ", attributesExample2: " + attributesExample2;
}
}
public class AttributesExample2 extends Attributes {
private int inti = 5;
private boolean booli = false;
public String toString() {
return inti + ", " + booli;
}
}
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_FLOAT_AS_INT, false); // otherwise 4.7 will automatically be casted to 4 for integers, with this it throws an error
mapper.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION); // forbids duplicate keys
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); // otherwise private fields won't be usable
mapper.registerModule(new SimpleModule().addDeserializer(boolean.class, new JsonDeserializer<Boolean>() { // make boolean parsing more strict, otherwise integers are accepted with 0=false and all other integers=true
@Override
public Boolean deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
if (!jsonParser.getCurrentToken().isBoolean())
throw new JsonParseException(jsonParser, "Can't parse \"" + jsonParser.getValueAsString() + "\" as boolean");
return jsonParser.getValueAsBoolean();
}
}));
String json = "{" +
"\"MODEL1\": {" +
"\"str\": \"hi\", " +
"\"dbl\": 2.0, " +
"\"bool\": true, " +
"\"attributesExample2\": {" +
"\"inti\": 4, " +
"\"booli\": true" +
"}}," +
"\"MODEL2\": {" +
"\"inti\": 2, " +
"\"booli\": false" +
"}}";
Map<ModelType, Attributes> modelsMap = new HashMap<>();
Iterator<Map.Entry<String, JsonNode>> nodeIterator = mapper.readTree(json).fields(); // via stackoverflow.com/a/18342245
while (nodeIterator.hasNext()) {
Map.Entry<String, JsonNode> entry = nodeIterator.next();
ModelType modelType = ModelType.valueOf(entry.getKey());
Attributes attributes = (Attributes) mapper.treeToValue(entry.getValue(), modelType.getAttributesClass()); // via stackoverflow.com/a/28714523
modelsMap.put(modelType, attributes);
}
System.out.println(modelsMap); // prints --> {MODEL2=2, false, MODEL1=hi, 2.0, true, attributesExample2: 4, true}
// TODO syntactic checks are done, now check modelsMap for logical soundness (order & valid mix?) before passing it to the simulator...
//usage example:
AttributesExample1 ae1 = (AttributesExample1) modelsMap.get(ModelType.MODEL1);
}
}
public enum ModelType {
MODEL1(AttributesExample1.class),
MODEL2(AttributesExample2.class);
private Class<? extends Attributes> attributes;
private ModelType(Class<? extends Attributes> attributesClass) {
attributes = attributesClass;
}
public Class<? extends Attributes> getAttributesClass() {
return attributes;
}
}
@benjaminaaron
Copy link
Author

Danke, sieht besser aus, hab's übernommen 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment