jackson-databind
                                
                                 jackson-databind copied to clipboard
                                
                                    jackson-databind copied to clipboard
                            
                            
                            
                        Cannot use polymorphic type handling (DEDUCTION) with "POJO as Array" notation
Problem (excuses for the long description) - Version: 2.13
I am trying to use the JsonTypeInfo.Id.DEDUCTION method which is described here and in a lot of other sources with JSON inputs which are an array, can have 3 different forms and looks like the following:
Form 1
[2, 
"Form1Text", 
"Form1MoreText",
{
"field": "value",
"nested": {
"nest1": "nest1_value,
"nest2": "nest2_value
}
}
]
Form 2
[3,
"Form2Text",
{
"form2Field1": "2013-02-01T20:53:32.486Z",
"form2Field2": 300,
"form2Field3": "Accepted"
}
]
Form 3
[4,
"Form3Text",
"Form3MoreText",
"Form3SomeMoreText",
{}
]
The content does not matter but the structure of the above messages and the fact that the root JSON element is not the classic JSON format (object with {}) but an array matter and I think here is the bug. Note that this is a perfect valid JSON message based on the JSON specification.
Structure of Form1
array with int, string, string, object (with property, property with object)
Structure of Form2
array with int, string, object (with properties)
Structure of Form3
array with int, string, string, string, empty object
Based on that input and the 3 possible structures I created the following classes
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
        @Type(value=Form1.class),
        @Type(value=Form2.class),
        @Type(value=Form3.class)
})
public abstract class CommonForm {
    public int formNumber;
    public String formText;
   // getter, setter, allArgConstructor, noArgConstructor
}
public class Form1 extends CommonForm {
    public String form1Text;
    public Map<String, Object> form1Map;
    // getter, setter, allArgConstructor, noArgConstructor
}
public class Form2 extends CommonForm {
    private  Map<String, Object> form2Map;
    // getter, setter, allArgConstructor, noArgConstructor
}
public class Form3 extends CommonForm {
    private String form3Text1;
    private String form3Text2;
    private String form3Text3;
    // getter, setter, allArgConstructor, noArgConstructor
}
The code to deserialize the input is the following
ObjectMapper mapper= new ObjectMapper();
String form1 = "[2,\"Form1Text\",\"Form1MoreText\",{\"field\": \"value\",\"nested\": {\"nest1\": \"nest1_value,\"nest2\": \"nest2_value}}]"; 
CommonForm cf = mapper.readValue(form1 , CommonForm.class);
By doing all the above and based on the deduction mechanism, I was expecting that the mapper will understand the inheritance and will read the JSON input (Form1 specifically in the above example) and return the object of class Form1 (the input JSON is a Form1). However, it does not recognize the inheritance (deduction) even though the classes can be uniquely distinguished and the following error occurs:
om.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_NUMBER_INT), expected VALUE_STRING: need JSON String that contains type id (for subtype of com.example.form.CommonForm)
 at [Source: (String)"[2,"Form1Text","Form1MoreText",{"field": "value","nested": {"nest1": "nest1_value,"nest2": "nest2_value}}]"; line: 1, column: 2]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
	at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1939)
	at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1673)
	at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:164)
	at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:96)
	at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71)
	at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedUsingDefaultImpl(AsPropertyTypeDeserializer.java:170)
	at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:96)
	at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:263)
	at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74)
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4675)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3630)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3598)
Based on the error message, it expects to have a field with the value type id. However, the purpose of the DEDUCTION mechanism is the opposite. The JSON input does not have a property/field that declares the value type id.
Is the problem the fact that the JSON input has a root element which is not the classic object({}) but an array([])? something else? or am I doing something wrong here regarding the use of the DEDUCTION mechanism?
Cheers, Platon
I assume somewhere in code there is a setting to force use of Shape.ARRAY for POJOs? Otherwise JSON Array could not be serialization for POJOs.
If so, the simple answer is that use of Array serialization will limit support for all kinds of features, including (but not limited to) Object Id and Type Id handling. Polymorphic types do not (and probably can not) be supported with positional notation.
So: you can not use "POJO-as-array" along with Polymorphic Deserialization: this does not and will not work.
The main question is that of how to document this limitation: I don't think it can ever be changed.
And possibly producing better exception message if attempt is made to use the combination.
This limitation is not specific to deduction  but all modes of @JsonTypeInfo handling.