I am finding that instances with a JsonTypeInfo annotation are not written with a @class property when the instance is inside a HashMap.
Here is my test code:
------------------------------------------------------------------------------------------------
package test;
import java.util.HashMap;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS)
public class JsonAttributes {
public JsonSub subAsProperty;
@JsonIgnore
public HashMap<String,Object> dynamicAttrs = new HashMap<String,Object>();
@JsonInclude
public HashMap<String,Object> explicitAttrs = new HashMap<String,Object>();
@JsonAnyGetter
public HashMap<String,Object> jsonGet(){
return dynamicAttrs;
}
@JsonAnySetter
public void jsonSet(String key, Object value){
dynamicAttrs.put(key, value);
}
}
------------------------------------------------------------------------------------------------
package test;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS)
public class JsonSub {
public String str;
public JsonSub() {}
public JsonSub(String string) {
str = string;
}
}
------------------------------------------------------------------------------------------------
package test;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Test {
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
JsonAttributes json = new JsonAttributes();
json.dynamicAttrs.put("subInDynamic", new JsonSub("sub inside anyGetter"));
json.explicitAttrs.put("subInExplicit", new JsonSub("sub inside explicit map"));
json.subAsProperty = new JsonSub("sub as property");
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(json);
System.out.println(str);
JsonAttributes readJson = mapper.readValue(str, JsonAttributes.class); //this succeeds
//However, the subInDynamic JsonSub class is read as a HashMap
System.err.println("subInDynamic class type = "+readJson.dynamicAttrs.get("subInDynamic").getClass().getName());
}
}
------------------------------------------------------------------------------------------------
The result is:
{
"@class": "test.JsonAttributes",
"subAsProperty": {
"@class": "test.JsonSub",
"str": "sub as property"
},
"explicitAttrs": {
"subInExplicit": {
"str": "sub inside explicit map"
}
},
"subInDynamic": {
"str": "sub inside anyGetter"
}
}
And:
subInDynamic class type = java.util.LinkedHashMap
Note that the @class property for the JsonSub instance is only written when the property is explicitly of type JsonSub.
When the JsonSub instance is inside a Map, the @class property is not written.
And therefore, when the JsonAttributes is instantiated, the subInDynamic instance is now a LinkedHashMap, rather than a JsonSub.
This isn't my desired behavior.
I figured that jackson would inspect any instance it was serializing and would write the @class property if it found a JsonTypeInfo annotation.
Is there any way to get around this behavior, or have I made a mistake? TIA