Description
Search before asking
- I searched in the issues and found nothing similar.
Describe the bug
When using Jackson with frameworks such as Immutables where users are expected to write bean definitions as abstract types and let the framework generate concrete implementations, Jackson annotations on the abstract type sometimes have no effect, or worse, trigger bugs. This appears to be due to the assumption in BeanDeserializerFactory.addBeanProps
that creator properties do not need to be considered for abstract types. In particular, deserialisation fails with a bizarre exception in in the following situation:
- The type to be deserialised is abstract but with a defined
ValueInstantiator
(e.g. from a@JsonCreator
annotated factory method). - The property to be deserialised has a getter but no setter.
- The type of the property to be deserialised is also abstract.
- The getter has a
@JsonTypeInfo
annotation withinclude = JsonTypeInfo.As.EXTERNAL_PROPERTY
.
Version Information
2.17.1
Reproduction
See attached: example.zip
Expected behavior
No response
Additional context
Deserialisation fails with the following exception:
Unexpected token (VALUE_STRING), expected START_ARRAY: need Array value to contain `As.WRAPPER_ARRAY` type information for class example.TypedData$Value
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 2, column: 20] (through reference chain: example.TypedData["value"])
com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_STRING), expected START_ARRAY: need Array value to contain `As.WRAPPER_ARRAY` type information for class example.TypedData$Value
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 2, column: 20] (through reference chain: papaya.struct.jackson.TypedData["value"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.wrongTokenException(DeserializationContext.java:1913)
at com.fasterxml.jackson.databind.DeserializationContext.reportWrongTokenException(DeserializationContext.java:1699)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._locateTypeId(AsArrayTypeDeserializer.java:141)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:96)
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromObject(AsArrayTypeDeserializer.java:61)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:263)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:542)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:440)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1493)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4905)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3848)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3816)
Notice that the call chain goes through BeanDeserializer.deserializeFromObjectUsingNonDefault
rather than the expected BeanDeserializer.deserializeWithExternalTypeId
. This is because _externalTypeIdHandler
is null
, which is because when BeanDeserializerBase.resolve
is called, _beanProperties
is empty (!), which is because BeanDeserializerFactory.addBeanProps
ignores creator properties when the type is abstract. Changing the value of isConcrete
in addBeanProps
to true
while running in a debugger suffices to fix this problem, though I cannot say if this has any other effects.