I am using Jackson to serialize my Java POJO classes. In addition to fields, I have in Java POJO, I would like to add some additional information in JSON I am writing my own custom CustomClassSerializer
. If I use this class and register to ObjectMapper
then I get the error:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type org.acme.Tiger (by serializer of type org.acme.CustomModule$CustomClassSerializer)
I am unable to understand what might be going wrong here. If I remove the custom registered model then everything works perfectly.
Can someone please let me know what may be the cause of this issue? I am currently using Jackson 2.13.2 latest version dependencies: jackson-core, jackson-databind, jackson-annotations, jackson-datatype-jdk8
:
Following is the sample code:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.*;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = Bat.class, name = "Bat"),
@JsonSubTypes.Type(value = Tiger.class, name = "Tiger")})
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Animal {
private String type;
private String name;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeName("Tiger")
public class Tiger extends Animal {
private String livingType;
private String foundIn;
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonTypeName("Bat")
public class Bat extends Animal{
private String livingType;
private String foundIn;
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
import java.io.IOException;
public class CustomModule extends SimpleModule {
public CustomModule() {
addSerializer(Tiger.class, new CustomClassSerializer());
}
private static class CustomClassSerializer extends JsonSerializer {
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
jgen.writeObjectField("my_extra_field1", "some data");
jgen.writeObjectField("my_extra_field2", "some more data");
JavaType javaType = provider.constructType(Tiger.class);
BeanDescription beanDesc = provider.getConfig().introspect(javaType);
JsonSerializer<Object> serializer = BeanSerializerFactory.instance.createSerializer(provider, javaType);
serializer.unwrappingSerializer(null).serialize(value, jgen, provider);
jgen.writeEndObject();
}
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TestMain {
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.registerModule(new CustomModule());
Tiger tiger = new Tiger();
tiger.setType("Tiger");
tiger.setName("Shera");
tiger.setFoundIn("Ground");
tiger.setLivingType("Tree");
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(tiger));
}
}
I would like to know what are the causes for the above-mentioned exception.
I don't think I can write really efficient Jackson code while being a Gson-oriented guy, but I guess you could incorporate the following Q/As to resolve your question:
Also, I'd like to refactor your code (a lot) in order to make it flexible by using the strategy design pattern (where necessary), and demonstrate how it works using with simple unit tests.
I hope the code above is pretty self-explaining. You may also want to enhance the code in order to make
identityNameTransformer
injectable too, if you need to use extra property name transformations.Unrelated to the subject, but duplicating JSON object property names like
my_extra_field
in your question may be considered not recommended (not sure if vulnerable). See more: Does JSON syntax allow duplicate keys in an object? .