I am looking to create a custom Deserializer in Jackson for set of Enum class. Since the behaviour of custom deserializer would be same for all enum. I want to make common Deserializer for all my enum class.
I tried making generic custom deserialize as follow:
class MyEnumDeserialize<T> extends JsonDeserializer<T> {
private Class beanClass;
public MyEnumDeserialize() {
}
public MyEnumDeserialize(Class beanClass) {
this.beanClass = beanClass;
}
#Override
public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
TreeNode node = jsonParser.getCodec().readTree(jsonParser);
T type = null;
try{
if(node.get("attr") != null){
// I don't know how to call ENUM static method here as I don't have context information here
if (type != null) {
return type;
}
}
}catch(Exception e){
type = null;
}
return null;
}
}
The problem is I want to call Enum static method inside the deserializer but unable to do so since I don't have any class/enum context information available.
Could you please help me know how could I achieve it.
I somehow managed to make following solution worked:
I created a module and modify EnumDeserializer as follow:
module.setDeserializerModifier(new BeanDeserializerModifier()
{
#Override public JsonDeserializer<?> modifyEnumDeserializer(DeserializationConfig config,
JavaType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer)
{
if (beanDesc.getBeanClass().isEnum()) {
return new MyEnumDeserialize<>(beanDesc.getBeanClass());
}
return deserializer;
}
});
class MyEnumDeserialize<T extends Enum> extends JsonDeserializer<T> {
private Class beanClass;
public MyEnumDeserialize() {
}
public MyEnumDeserialize(Class beanClass) {
this.beanClass = beanClass;
}
#Override
public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
TreeNode node = jsonParser.getCodec().readTree(jsonParser);
T type = null;
try{
if(node.isValueNode()){
ValueNode valueNode = (ValueNode)node;
Method method = this.beanClass.getDeclaredMethod("get",short.class);
type = (T)method.invoke(null, Short.parseShort(valueNode.asText()));
if (type != null) {
return type;
}
}
}catch(Exception e){
type = null;
}
return type;
}
}
Though now, I am unable to provide Strict type checking ( creating instance with "<>").
Related
I'm trying to deserialize a Json into an existing instance in my process. So it only creates a new instance if none exists. Alls objects contains an id to Identifiy them.
I used this answer: https://stackoverflow.com/a/18405958/11584969 and tried to create a custon Deserializer for this.
So far I have managed to create a custon Deserializer which checks for existing instances, but I was not able to fill the new instance or change the existing one.
My deserialize function is:
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
if (node instanceof NullNode) {
return null;
}
// get id from node
String strId = node.get("id").asText();
UUID id = UUID.fromString(strId);
// search for existing instance or create it
T mObject = ...
// fill/change instance
return (T) defaultDeserializer.deserialize(jp, ctxt, mObject);
}
The object mapper creation:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping();
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new JavaTimeModule());
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (beanDesc.getBeanClass() == Table.class)
return new ModelObjectDeserializer<>(Table.class, (JsonDeserializer<Table>) deserializer);
return deserializer;
}
});
objectMapper.registerModule(module);
The code above runs without any error or exception but the instance from mObject is not filled by defaultDeserializer.deserialize(jp, ctxt, mObject);
If I don't use my custom deserializer, the created instances are filled as expected.
It is not quite an answer to the question, but my initial goal was:
'm trying to deserialize a Json into an existing instance in my process. So it only creates a new instance if none exists. Alls objects contains an id to Identifiy them.
For everyone who tries to accomplish the same, here is how I implemented it:
public class ModelInstantiator extends StdValueInstantiator {
private static final long serialVersionUID = -7760885448565898117L;
private Class<? extends ModelObject> clazz;
/**
* #param config
* #param valueType
*/
public ModelInstantiator(DeserializationConfig config, Class<? extends ModelObject> clazz) {
super(config, config.constructType(clazz));
this.clazz = clazz;
}
#Override
public boolean canCreateFromObjectWith() {
return true;
}
#Override
public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) throws IOException, JsonProcessingException {
UUID id = (UUID) args[0];
// get local object
ModelObject object = ...
// if id was not found => create and add
if (object == null) {
try {
object = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new IOException(e);
}
object.setId(id);
// add to local list
...
}
return object;
}
#Override
public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig config) {
CreatorProperty idProp = new CreatorProperty(new PropertyName("id"), config.constructType(UUID.class), null, null, null, null,
0, null, PropertyMetadata.STD_REQUIRED);
return new SettableBeanProperty[] { idProp };
}
}
I had to split the local and json id. Ohterwise the id in the array is null.
I need help, here is the description of the task:
1. I have base interface
interface IPolymorphicModel
2. I have few nested interfaces:
interface IContentItem extends IPolymorphicModel
interface IAttachment extends IPolymorphicModel
3. I have few implementations:
public class MediaAttachment implements IAttachment
public class Article implements IContentItem {
private List<IAttachment> attachements;
}
I am using jackson (also I tried Gson using registerTypeAdapterFactory) to parse current json structure. I am using next approach for deserializing json using single Deserializer for all nested items:
Module module = new SimpleModule()
module.setDeserializerModifier(new BeanDeserializerModifier() {
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> deserializer){
if (IPolymorphicModel.class.isAssignableFrom(beanDesc.getBeanClass())){
return new PolymorphicJsonDeserializer()
}
return super.modifyDeserializer(config, beanDesc, deserializer);
})
But there is the problem with parsing inner items: as you can see inner object can contain object with the same super, and when jackson try to parse them it doesn't know anything about IPolymorphicModel and registering the same BeanDeserializerModifier is not possible because it will cause stack overflow.
I found the solution. And its quite easy at least in this case. To solve such kind of task, you need to use jackson TypeIdResolver. Here is an example:
1. First you need to annotate your base class, where modelType your field by which you can identify, which exactly child of base class you are using:
#JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM,
include = JsonTypeInfo.As.PROPERTY,
property = "modelType")
#JsonTypeIdResolver(IdResolver.class)
interface IPolymorphic
2. Implement your own IdResolver.class:
public class IdResolver implements TypeIdResolver {
private JavaType baseType = null;
#Override
public void init(JavaType baseType) {
this.baseType = baseType;
}
#Override
public String idFromValue(Object value) {
return idFromValueAndType(value, value.getClass());
}
#Override
public String idFromValueAndType(Object value, Class<?> suggestedType) {
String id = "";
for (Map.Entry<String, Class<? extends IPolymorphic>> entry : PolymorphicTypeRegistry.Companion.getInstance().getMap().entrySet()) {
if (entry.getValue() == suggestedType) return entry.getKey();
}
return id;
}
#Override
public String idFromBaseType() {
return idFromValueAndType(null, baseType.getRawClass());
}
#Override
public JavaType typeFromId(String id) {
Class clazz = PolymorphicTypeRegistry.Companion.getInstance().get(id);
JavaType javaType = TypeFactory.defaultInstance().constructSpecializedType(baseType, clazz);
return javaType;
}
#Override
public JavaType typeFromId(DatabindContext context, String id) {
return typeFromId(id);
}
#Override
public String getDescForKnownTypeIds() {
return "";
}
#Override
public JsonTypeInfo.Id getMechanism() {
return JsonTypeInfo.Id.CUSTOM;
}
}
In two previous steps we configure jackson to call the same deserialize behaviour for all nested classes of IPolymorphic, so the last step - we need to register deserializer for IPolymorphic:
public void configureJackson() {
ObjectMapper objectMapper = new ObjectMapper();
Module module = new SimpleModule();
module.addDeserializer(IPolymorphic.class, new PolymorphicJsonDeserializer());
objectMapper.registerModule(module);
}
We have a service which currently consumes JSON. We want to slightly restructure this JSON (move one property one level up) but also implement graceful migration so that our service could process old structure as well as new structure. We're using Jackson for JSON deserialization.
How do we restructure JSON prior to deserialization with Jackson?
Here's a MCVE.
Assume our old JSON looks as follows:
{"reference": {"number" : "one", "startDate" : [2016, 11, 16], "serviceId" : "0815"}}
We want to move serviceId one level up:
{"reference": {"number" : "one", "startDate" : [2016, 11, 16]}, "serviceId" : "0815"}
This are the classes we want to deserialize from both old an new JSONs:
public final static class Container {
public final Reference reference;
public final String serviceId;
#JsonCreator
public Container(#JsonProperty("reference") Reference reference, #JsonProperty("serviceId") String serviceId) {
this.reference = reference;
this.serviceId = serviceId;
}
}
public final static class Reference {
public final String number;
public final LocalDate startDate;
#JsonCreator
public Reference(#JsonProperty("number") String number, #JsonProperty("startDate") LocalDate startDate) {
this.number = number;
this.startDate = startDate;
}
}
We only want serviceId in Container, not in both classes.
What I've got working is the following deserializer:
public static class ServiceIdMigratingContainerDeserializer extends JsonDeserializer<Container> {
private final ObjectMapper objectMapper;
{
objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
#Override
public Container deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ObjectNode node = p.readValueAsTree();
migrate(node);
return objectMapper.treeToValue(node, Container.class);
}
private void migrate(ObjectNode containerNode) {
TreeNode referenceNode = containerNode.get("reference");
if (referenceNode != null && referenceNode.isObject()) {
TreeNode serviceIdNode = containerNode.get("serviceId");
if (serviceIdNode == null) {
TreeNode referenceServiceIdNode = referenceNode.get("serviceId");
if (referenceServiceIdNode != null && referenceServiceIdNode.isValueNode()) {
containerNode.set("serviceId", (ValueNode) referenceServiceIdNode);
}
}
}
}
}
This deserializer first retrieves the tree, manipulates it and then deserializers it using an own instance of ObjectMapper. It works but we really dislike the fact that we have another instance of ObjectMapper here. If we don't create it and somehow use the system-wide instance of ObjectMapper we get an infinite cycle because when we try to call objectMapper.treeToValue, our deserializer gets called recursively. So this works (with an own instance of ObjectMapper) but it is not an optimal solution.
Another method I've tried was using a BeanDeserializerModifier and a own JsonDeserializer which "wraps" the default serializer:
public static class ServiceIdMigrationBeanDeserializerModifier extends BeanDeserializerModifier {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc,
JsonDeserializer<?> defaultDeserializer) {
if (beanDesc.getBeanClass() == Container.class) {
return new ModifiedServiceIdMigratingContainerDeserializer((JsonDeserializer<Container>) defaultDeserializer);
} else {
return defaultDeserializer;
}
}
}
public static class ModifiedServiceIdMigratingContainerDeserializer extends JsonDeserializer<Container> {
private final JsonDeserializer<Container> defaultDeserializer;
public ModifiedServiceIdMigratingContainerDeserializer(JsonDeserializer<Container> defaultDeserializer) {
this.defaultDeserializer = defaultDeserializer;
}
#Override
public Container deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
ObjectNode node = p.readValueAsTree();
migrate(node);
return defaultDeserializer.deserialize(new TreeTraversingParser(node, p.getCodec()), ctxt);
}
private void migrate(ObjectNode containerNode) {
TreeNode referenceNode = containerNode.get("reference");
if (referenceNode != null && referenceNode.isObject()) {
TreeNode serviceIdNode = containerNode.get("serviceId");
if (serviceIdNode == null) {
TreeNode referenceServiceIdNode = referenceNode.get("serviceId");
if (referenceServiceIdNode != null && referenceServiceIdNode.isValueNode()) {
containerNode.set("serviceId", (ValueNode) referenceServiceIdNode);
}
}
}
}
}
"Wrapping" a default deserializer seems to be a better approach, but this fails with an NPE:
java.lang.NullPointerException
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:157)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150)
at de.db.vz.rikernpushadapter.migration.ServiceIdMigrationTest$ModifiedServiceIdMigratingContainerDeserializer.deserialize(ServiceIdMigrationTest.java:235)
at de.db.vz.rikernpushadapter.migration.ServiceIdMigrationTest$ModifiedServiceIdMigratingContainerDeserializer.deserialize(ServiceIdMigrationTest.java:1)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1623)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1217)
at ...
The whole MCVE code is in the following PasteBin. It is a single-class all-containing test case which demonstrates both approaches. The migratesViaDeserializerModifierAndUnmarshalsServiceId fails.
So this leaves me with a question:
How do we restructure JSON prior to deserialization with Jackson?
In the best traditions, right after posting the question, I've managed to solve this.
Two things:
I had to do newJsonParser.nextToken(); to avoid NPE.
Extend DelegatingDeserializer
Here's a working DelegatingDeserializer:
public static class ModifiedServiceIdMigratingContainerDeserializer
extends DelegatingDeserializer {
public ModifiedServiceIdMigratingContainerDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(defaultDeserializer);
}
#Override
protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
return new ModifiedServiceIdMigratingContainerDeserializer(newDelegatee);
}
#Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return super.deserialize(restructure(p), ctxt);
}
#Override
public Object deserialize(JsonParser p, DeserializationContext ctxt, Object intoValue) throws IOException,
JsonProcessingException {
return super.deserialize(restructure(p), ctxt, intoValue);
}
public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer)
throws IOException, JsonProcessingException {
return super.deserializeWithType(restructure(jp), ctxt, typeDeserializer);
}
public JsonParser restructure(JsonParser p) throws IOException, JsonParseException {
final ObjectNode node = p.readValueAsTree();
migrate(node);
final TreeTraversingParser newJsonParser = new TreeTraversingParser(node, p.getCodec());
newJsonParser.nextToken();
return newJsonParser;
}
private void migrate(ObjectNode containerNode) {
TreeNode referenceNode = containerNode.get("reference");
if (referenceNode != null && referenceNode.isObject()) {
TreeNode serviceIdNode = containerNode.get("serviceId");
if (serviceIdNode == null) {
TreeNode referenceServiceIdNode = referenceNode.get("serviceId");
if (referenceServiceIdNode != null && referenceServiceIdNode.isValueNode()) {
containerNode.set("serviceId", (ValueNode) referenceServiceIdNode);
}
}
}
}
}
I am using Jackson fasterxml for unmarshalling JSON. In my object there are two kinds of properties:Input properties and Calculated properties. In the input JSON, I get only input values.
The calculated values are actually dependent on input values. I have to populate these values before the object gets referred. So I am just checking if there are any hooks provided by Jackson so that I can do my calculations there. For example JAXB provides afterUnmarshal method to customize the unmarshaling behavior:
void afterUnmarshal(Unmarshaller u, Object parent)
But I could not find similar information about customizing Jackson. Are any such framework hooks provided by Jackson to customize the unmarshaling behavior?
I'd rather recommend to keep your model objects immutable by using constructor creators. That is, all the JSON values are passed to a constructor which would initialize the other calculated properties.
Anyway, if you want to customize an object after deserialization (without writing a deserializer for every type) you can modify the deserializer in a way that at the end it calls a special method(s) of a newly constructed instance. Here is an example which would work for all the classes that implements a special interface (one can consider using an annotation to mark the post construct methods).
public class JacksonPostConstruct {
public static interface PostConstructor {
void postConstruct();
}
public static class Bean implements PostConstructor {
private final String field;
#JsonCreator
public Bean(#JsonProperty("field") String field) {
this.field = field;
}
public void postConstruct() {
System.out.println("Post construct: " + toString());
}
#Override
public String toString() {
return "Bean{" +
"field='" + field + '\'' +
'}';
}
}
private static class PostConstructDeserializer extends DelegatingDeserializer {
private final JsonDeserializer<?> deserializer;
public PostConstructDeserializer(JsonDeserializer<?> deserializer) {
super(deserializer);
this.deserializer = deserializer;
}
#Override
protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
return deserializer;
}
#Override
public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
Object result = _delegatee.deserialize(jp, ctxt);
if (result instanceof PostConstructor) {
((PostConstructor) result).postConstruct();
}
return result;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc,
final JsonDeserializer<?> deserializer) {
return new PostConstructDeserializer(deserializer);
}
});
mapper.registerModule(module);
String json = "{\"field\":\"value\"}";
System.out.println(mapper.readValue(json, Bean.class));
}
}
Output:
Post construct: Bean{field='value'}
Bean{field='value'}
Let's assume that your JSON looks like this:
{
"input1" : "Input value",
"input2" : 3
}
And your POJO class looks like this:
class Entity {
private String input1;
private int input2;
private String calculated1;
private long calculated2;
...
}
In this case you can write a custom deserializer for your Entity class:
class EntityJsonDeserializer extends JsonDeserializer<Entity> {
#Override
public Entity deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
InnerEntity innerEntity = jp.readValueAs(InnerEntity.class);
Entity entity = new Entity();
entity.setInput1(innerEntity.input1);
entity.setInput2(innerEntity.input2);
entity.recalculate();
return entity;
}
public static class InnerEntity {
public String input1;
public int input2;
}
}
In above class you can see that Entity has a recalculate method. It could look like this:
public void recalculate() {
calculated1 = input1 + input2;
calculated2 = input1.length() + input2;
}
You can also move this logic to your deserializer class.
Now, you have to inform Jackson that you want to use your custom deserializer:
#JsonDeserialize(using = EntityJsonDeserializer.class)
class Entity {
...
}
The example below shows how to use these classes:
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(json, Entity.class));
This program prints:
Entity [input1=Input value, input2=3, calculated1=Input value3, calculated2=14]
I have a class hierarchy similar to this one:
public static class BaseConfiguration {
}
public abstract class Base {
private BaseConfiguration configuration;
public String id;
public BaseConfiguration getConfiguration() { ... }
public void setConfiguration(BaseConfiguration configuration) { ... }
}
public class A extends Base {
public static class CustomConfigurationA extends BaseConfiguration {
String filename;
String encoding;
}
CustomConfigurationA getConfiguration() { ... }
}
class B extends Base {
public static class CustomConfigurationB extends BaseConfiguration {
/* ... */
}
CustomConfigurationB getConfiguration() { ... }
}
And json input like this one (which I cannot change myself)
{
"id":"File1",
"configuration":{
"filename":"...",
"encoding":"UTF-8"
}
}
I am parsing the JSON in Java with Jackson like this
ObjectMapper mapper = new ObjectMapper();
value = mapper.readValue(in, nodeType);
I want to deserialize classes A, B and others from JSON using JAVA/Jackson. There are no type information embedded in JSON (and can't be). I can't use annotations on the classes (I don't own them) and I (believe) I can't use mixins since there are potentially arbitrary numbers of classes like A & B (and mixins are not dynamic). Good thing is that the deserializing code knows which is the correct custom class to use for deserializing (basically there is a known mapping from class to configuration class), but I do not know how make Jackson recognize this information when deserializing the JSON.
In short: I want to be able to resolve the deserialization type of the configuration object depending on the surrounding class type by setting whatever is necessary on ObjectMapper. How can this be achieved?
Apparently the answer was to implement something similar to the sixth solution posted at http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html, which uses unique JSON element names to identify the target type to deserialize to.
Good answer provided by Programmer Bruce!
I have a case of polymorphism in which I want to keep the domain objects as POJOs and not use dependencies on Jackson annotations.
Therefore I preffer to use a custom deserializer and a Factory for decising the type or intantiating the concrete classes.
Here is my code ...
(be aware that I have an Annotation Hierarchy which are in fact "User Tags" and not Java Annotations )
Here is the deserialization Method
public class AnnotationDeserializer extends StdDeserializer<Annotation> {
AnnotationDeserializer() {
super(Annotation.class);
}
#Override
public Annotation deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
Class<? extends Annotation> realClass = null;
Iterator<Entry<String, JsonNode>> elementsIterator = root.getFields();
while (elementsIterator.hasNext()) {
Entry<String, JsonNode> element = elementsIterator.next();
if ("type".equals(element.getKey())) {
realClass = AnnotationObjectFactory.getInstance()
.getAnnotationClass(element.getKey());
break;
}
}
if (realClass == null)
return null;
return mapper.readValue(root, realClass);
}
}
I had to do something similar, and ended up creating a generic polymorphic list serializer and deserialzer. Here is the deserialize that I think will work for you:
public class PolymorphicListDeserializer extends JsonDeserializer<List<?>> implements ContextualDeserializer {
private HashMap<String, Class> _typeMap = null;
private Class _elementType;
private static <T> List<T> getNewList(Class<T> clazz) {
return new ArrayList<T>();
}
#Override
public List<?> deserialize(final JsonParser jp, DeserializationContext ctxt) throws IOException {
final List list = getNewList(_elementType);
JsonToken nextToken = jp.getCurrentToken();
if (nextToken == JsonToken.START_OBJECT) {
if ( _typeMap.containsKey( currentFieldName )) {
list.add( _elementType.cast( ctxt.readValue( jp, _typeMap.get( currentFieldName ) ) ) );
}
nextToken = jp.nextToken();
} else if (currentFieldName != null && isEndToken(nextToken) && wrapperCount == 0) {
break;
} else {
nextToken = jp.nextToken();
}
}
return list;
}
public JsonDeserializer<List<?>> createContextual( DeserializationContext ctxt, BeanProperty property ) throws JsonMappingException {
//In Jackson 2.6.3, this method is called once per instance and the exception is never thrown
if ( _typeMap == null )
_typeMap = new HashMap<String, Class>();
else
throw new RuntimeException("Unsupported version of Jackson. Code assumes context is created once and only once.");
_elementType = property.getType().getContentType().getRawClass();
//For now, requiring XmlElements annotation to work. May add support for JsonElements (if needed) later.
for (XmlElement e : property.getAnnotation(XmlElements.class).value()) {
_typeMap.put(e.name(), e.type());
}
return this;
}
private static boolean isStartToken(JsonToken t) {
boolean result = false;
if (t == JsonToken.START_OBJECT) {
result = true;
} else if (t == JsonToken.START_ARRAY) {
result = true;
}
return result;
}
Above answers depicts a solution however lack what actually used annotations mean. If you are curious about what actually these annotation do, idea behind them & why they are required please go through the below link. Its explained very nicely in it. https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization