diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 427fb4421b..19a0e7ce30 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -7,6 +7,8 @@ Project: jackson-databind 2.12.0-rc2 (not yet released) +#2775: Disabling `FAIL_ON_INVALID_SUBTYPE` breaks polymorphic deserialization of Enums + (reported by holgerknoche@github) #2878: Revert change initially made to fix #2805: change in signature of `ObjectMapper.treeToValue()` regarding exceptions #2880: Revert removal of 2.7-deprecated `PropertyNamingStrategy` constants diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java index 4d956c8f9d..12d205432d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/ExternalTypeHandler.java @@ -467,7 +467,7 @@ public boolean hasTypePropertyName(String n) { } public boolean hasDefaultType() { - return _typeDeserializer.getDefaultImpl() != null; + return _typeDeserializer.hasDefaultImpl(); } /** diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeDeserializer.java index 5173845efd..17855e2172 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/TypeDeserializer.java @@ -71,6 +71,11 @@ public abstract class TypeDeserializer */ public abstract Class getDefaultImpl(); + /** + * @since 2.12 + */ + public boolean hasDefaultImpl() { return getDefaultImpl() != null; } + /* /********************************************************** /* Type deserialization methods diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java index 939dc146f8..f135d2930d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java @@ -78,7 +78,7 @@ public Object deserializeTypedFromObject(JsonParser p, DeserializationContext ct return _deserializeWithNativeTypeId(p, ctxt, typeId); } } - + // but first, sanity check to ensure we have START_OBJECT or FIELD_NAME JsonToken t = p.currentToken(); if (t == JsonToken.START_OBJECT) { @@ -115,7 +115,7 @@ public Object deserializeTypedFromObject(JsonParser p, DeserializationContext ct @SuppressWarnings("resource") protected Object _deserializeTypedForId(JsonParser p, DeserializationContext ctxt, - TokenBuffer tb, String typeId) throws IOException { + TokenBuffer tb, String typeId) throws IOException { JsonDeserializer deser = _findDeserializer(ctxt, typeId); if (_typeIdVisible) { // need to merge id back in JSON input? if (tb == null) { @@ -142,8 +142,9 @@ protected Object _deserializeTypedUsingDefaultImpl(JsonParser p, DeserializationContext ctxt, TokenBuffer tb) throws IOException { // May have default implementation to use - JsonDeserializer deser = _findDefaultImplDeserializer(ctxt); - if (deser == null) { + // 13-Oct-2020, tatu: As per [databind#2775], need to be careful to + // avoid ending up using "nullifying" deserializer + if (!hasDefaultImpl()) { // or, perhaps we just bumped into a "natural" value (boolean/int/double/String)? Object result = TypeDeserializer.deserializeIfNatural(p, ctxt, _baseType); if (result != null) { @@ -161,6 +162,11 @@ protected Object _deserializeTypedUsingDefaultImpl(JsonParser p, } } } + } + // ... and here we will check for default implementation handling (either + // genuine, or faked for "dont fail on bad type id") + JsonDeserializer deser = _findDefaultImplDeserializer(ctxt); + if (deser == null) { String msg = String.format("missing type id property '%s'", _typePropertyName); // even better, may know POJO property polymorphic value would be assigned to @@ -190,9 +196,8 @@ protected Object _deserializeTypedUsingDefaultImpl(JsonParser p, */ @Override public Object deserializeTypedFromAny(JsonParser p, DeserializationContext ctxt) throws IOException { - /* Sometimes, however, we get an array wrapper; specifically - * when an array or list has been serialized with type information. - */ + // Sometimes, however, we get an array wrapper; specifically + // when an array or list has been serialized with type information. if (p.hasToken(JsonToken.START_ARRAY)) { return super.deserializeTypedFromArray(p, ctxt); } diff --git a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java index e31be7cc63..fd8cf916f7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/jsontype/impl/TypeDeserializerBase.java @@ -112,11 +112,16 @@ protected TypeDeserializerBase(TypeDeserializerBase src, BeanProperty property) @Override public TypeIdResolver getTypeIdResolver() { return _idResolver; } - @Override + @Override public Class getDefaultImpl() { return ClassUtil.rawClass(_defaultImpl); } + @Override + public boolean hasDefaultImpl() { + return (_defaultImpl != null); + } + /** * @since 2.9 */ diff --git a/src/test/java/com/fasterxml/jackson/databind/introspect/CustomAnnotationIntrospector1756Test.java b/src/test/java/com/fasterxml/jackson/databind/introspect/CustomAnnotationIntrospector1756Test.java index 99be5d5314..8447a91282 100644 --- a/src/test/java/com/fasterxml/jackson/databind/introspect/CustomAnnotationIntrospector1756Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/introspect/CustomAnnotationIntrospector1756Test.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; @@ -89,10 +90,14 @@ public String findImplicitPropertyName(final AnnotatedMember member) { } @Override - public boolean hasCreatorAnnotation(Annotated a) { - final AnnotatedConstructor ctor = (AnnotatedConstructor) a; - return (ctor.getParameterCount() > 0) - && (ctor.getParameter(0).getAnnotation(Field1756.class) != null); + public JsonCreator.Mode findCreatorAnnotation(MapperConfig config, Annotated ann) { + final AnnotatedConstructor ctor = (AnnotatedConstructor) ann; + if (ctor.getParameterCount() > 0) { + if (ctor.getParameter(0).getAnnotation(Field1756.class) != null) { + return JsonCreator.Mode.PROPERTIES; + } + } + return null; } }