Jackson JSON Polymorphism

I am trying to apply what is on http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html ) \ and apply it to what I was working on. Although it works great for what I will call β€œexternal” elements in the JSON framework, I ran into a problem that didn't have much documentation.

At first, my code looks something like this:

interface Parameters { // Couple random properties -- no problem here SubTypeParameters getSubTypeParameters(); // where SubTypeParameters are polymorphic void setSubTypeParameters(SubTypeParameters value); } @JsonSubTypes({ @JsonSubTypes.Type(name = "a", value = ASubTypeParameters.class), @JsonSubTypes.Type(name = "b", value = BSubTypeParameters.class) }) interface SubTypeParameters { String getValue(); void setValue(String value); } @JsonTypeName(value = "a") class ASubTypeParameters implements SubTypeParameters { // getter/setter implemented } @JsonTypeName(value = "b") class BSubTypeParameters implements SubTypeParameters { // getter/setter implemented } 

What I'm trying to do is implement the 6th option in a related blog post so that JSON appears as follows (do not specify the type element - it is based on context):

 { // other properties corresponding to the Parameters object "a": { "value": "value for a" } } 

or

 { // other properties corresponding to the Parameters object "b": { "value": "value for b" } } 

What I'm trying to avoid introduces other type variables into the JSON object. Rather, I would rather use the context provided in any of the above JSON examples to know that I should build an ASubTypeParameters or BSubTypeParameters object based on the presence of "a" or "b".

Most interestingly, the Parameters class / object is also polymorphic, so I registered my own custom deserializer class, for example:

 ObjectMapper mapper = new ObjectMapper(); StdDeserializer<Parameters> parameterDeserializer = new ParameterDeserializer(); SimpleModule module = new SimpleModule ( ... ); // simplifying this--no problem here module.addDeserializer(Parameters.class, parameterDeserializer); mapper.registerModule(module); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 

However, when the aforementioned deserializer tries to deserialize any of the above JSON examples, it will fall into the part where it tries to deserialize "a" or "b", and indicates that it does not know how to handle these properties (UnrecognizedPropretyException if I delete a failure in the string of unknown properties). My question really comes down to: What am I missing (annotation or otherwise)?

I also tried adding:

 mapper.registerSubtypes(ASubTypeParameters.class, BSubTypeParameters.class) 

and

 mapper.registerSubtypes( new NamedType(ASubTypeParameters.class, "a"), new NamedType(BSubTypeParameters.class, "b") ); 

to no avail.

I know that I'm getting close enough, and I guess I need to write some kind of custom subtype handler, but the documentation doesn't seem to be enough for what I would like to do (especially when you deserialize a polymorphic type / class, which also contains a polymorphic element).

+4
source share
1 answer

With Jackson, you can configure saving type information as the name of a single field using the following annotation: @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT) . The result should look like an example of JSON.

I modified your code a bit to demonstrate it:

 public class JacksonPolymorphic2 { @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT) @JsonSubTypes({ @JsonSubTypes.Type(name = "a", value = ASubTypeParameters.class), @JsonSubTypes.Type(name = "b", value = BSubTypeParameters.class) }) interface SubTypeParameters { String getValue(); void setValue(String value); } @JsonTypeName(value = "a") static class ASubTypeParameters implements SubTypeParameters { ASubTypeParameters(String value) { this.value = value; } private String value; @Override public String getValue() { return value; } @Override public void setValue(String value) { this.value = value; } } @JsonTypeName(value = "b") static class BSubTypeParameters implements SubTypeParameters { BSubTypeParameters(String value) { this.value = value; } private String value; @Override public String getValue() { return value; } @Override public void setValue(String value) { this.value = value; } } public static void main(String[] args) throws JsonProcessingException { ASubTypeParameters a = new ASubTypeParameters("aType"); BSubTypeParameters b = new BSubTypeParameters("bType"); List<? super SubTypeParameters> list = new ArrayList<>(); list.add(a); list.add(b); ObjectMapper mapper = new ObjectMapper(); System.out.printf(mapper .writerWithType(new TypeReference<List<SubTypeParameters>>() {}) .withDefaultPrettyPrinter() .writeValueAsString(list)); } } 

Output:

 [ { "a" : { "value" : "aType" } }, { "b" : { "value" : "bType" } } ] 
+2
source

All Articles