I'm currently migrating some code from Jackson 1.x to Jackson 2.5 json mapper and came a long a problem that wasn't there in 1.x.
This is the setup (see code below):
- interface IPet
- class Dog implements IPet
- IPet is annotated with @JsonTypeInfo and @JsonSubTypes
- class Human has a property of type IPet that is annotated with @JsonSerialize(using=CustomPetSerializer.class)
The problem: If I serialize an instance of Dog it works as expected (also the type info is added to the json string by Jackson). However when I serialize an instance of the Human class an exception is thrown saying:
com.fasterxml.jackson.databind.JsonMappingException: Type id handling not implemented for type com.pet.Dog (through reference chain: com.Human["pet"])
The serialize(...) method of the CustomPetSerializer class is not invoked (tested using a breakpoint).
The code:
IPet implementation:
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
@JsonSubTypes({
@JsonSubTypes.Type(value=Dog.class, name="dog")
//,@JsonSubTypes.Type(value=Cat.class, name="cat")
//more subtypes here...
})
public interface IPet
{
public Long getId();
public String getPetMakes();
}
Dog implementation:
public class Dog implements IPet
{
@Override
public String getPetMakes()
{
return "Wuff!";
}
@Override
public Long getId()
{
return 777L;
}
}
Human who owns a dog:
public class Human
{
private IPet pet = new Dog();
@JsonSerialize(using=CustomPetSerializer.class)
public IPet getPet()
{
return pet;
}
}
CustomPetSerializer implementation:
public class CustomPetSerializer extends JsonSerializer<IPet>
{
@Override
public void serialize(IPet value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException
{
if(value != null && value.getId() != null)
{
Map<String,Object> style = new HashMap<String,Object>();
style.put("age", "7");
gen.writeObject(style);
}
}
}
JUnit test method:
@Test
public void testPet() throws JsonProcessingException
{
ObjectMapper mapper = new ObjectMapper();
Human human = new Human();
//works as expcected
String json = mapper.writeValueAsString(human.getPet());
Assert.assertNotNull(json);
Assert.assertTrue(json.equals("{\"type\":\"dog\",\"id\":777,\"petMakes\":\"Wuff!\"}"));
//throws exception: Type id handling not implemented for type com.pet.Dog (through reference chain: com.Human["pet"])
json = mapper.writeValueAsString(human); //exception is thrown here
Assert.assertNotNull(json);
Assert.assertTrue(json.contains("\"age\":\"7\""));
}