From a5b470880d4ca4213b46d9be0def5fa9becd8163 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 12 Mar 2023 17:36:53 -0700 Subject: [PATCH] Fix #3824 (same as #2968 but for 3.x) --- .../impl/AsDeductionTypeDeserializer.java | 2 +- .../impl/AsPropertyTypeDeserializer.java | 20 ++++++++++++++-- .../jsontype/impl/StdTypeResolverBuilder.java | 24 ++++++++++++++++++- .../JsonTypeInfoIgnored2968Test.java | 7 +++--- .../DeserDefaultTypedConcrete2968Test.java | 3 ++- 5 files changed, 47 insertions(+), 9 deletions(-) rename src/test/java/tools/jackson/{failing => databind/jsontype}/JsonTypeInfoIgnored2968Test.java (92%) rename src/test/java/tools/jackson/{failing => databind/jsontype/deftyping}/DeserDefaultTypedConcrete2968Test.java (93%) diff --git a/src/main/java/tools/jackson/databind/jsontype/impl/AsDeductionTypeDeserializer.java b/src/main/java/tools/jackson/databind/jsontype/impl/AsDeductionTypeDeserializer.java index b364c01273..b179c16f52 100644 --- a/src/main/java/tools/jackson/databind/jsontype/impl/AsDeductionTypeDeserializer.java +++ b/src/main/java/tools/jackson/databind/jsontype/impl/AsDeductionTypeDeserializer.java @@ -39,7 +39,7 @@ public AsDeductionTypeDeserializer(DeserializationContext ctxt, JavaType bt, TypeIdResolver idRes, JavaType defaultImpl, Collection subtypes) { - super(bt, idRes, null, false, defaultImpl, null); + super(bt, idRes, null, false, defaultImpl, null, true); propertyBitIndex = new HashMap<>(); subtypeFingerprints = buildFingerprints(ctxt, subtypes); } diff --git a/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java b/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java index f47c251c14..16fb4ba97e 100644 --- a/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java +++ b/src/main/java/tools/jackson/databind/jsontype/impl/AsPropertyTypeDeserializer.java @@ -24,6 +24,11 @@ public class AsPropertyTypeDeserializer extends AsArrayTypeDeserializer { protected final As _inclusion; + /** + * Indicates if the current class has a TypeResolver attached or not. + */ + protected final boolean _hasTypeResolver; + protected final String _msgForMissingId = (_property == null) ? String.format("missing type id property '%s'", _typePropertyName) : String.format("missing type id property '%s' (for POJO property '%s')", _typePropertyName, _property.getName()); @@ -37,14 +42,24 @@ public AsPropertyTypeDeserializer(JavaType bt, TypeIdResolver idRes, public AsPropertyTypeDeserializer(JavaType bt, TypeIdResolver idRes, String typePropertyName, boolean typeIdVisible, JavaType defaultImpl, As inclusion) + { + this(bt, idRes, typePropertyName, typeIdVisible, defaultImpl, inclusion, true); + } + + public AsPropertyTypeDeserializer(JavaType bt, TypeIdResolver idRes, + String typePropertyName, boolean typeIdVisible, JavaType defaultImpl, + As inclusion, + boolean hasTypeResolver) { super(bt, idRes, typePropertyName, typeIdVisible, defaultImpl); _inclusion = inclusion; + _hasTypeResolver = hasTypeResolver; } - + public AsPropertyTypeDeserializer(AsPropertyTypeDeserializer src, BeanProperty property) { super(src, property); _inclusion = src._inclusion; + _hasTypeResolver = src._hasTypeResolver; } @Override @@ -166,7 +181,8 @@ protected Object _deserializeTypedUsingDefaultImpl(JsonParser p, // genuine, or faked for "dont fail on bad type id") ValueDeserializer deser = _findDefaultImplDeserializer(ctxt); if (deser == null) { - JavaType t = _handleMissingTypeId(ctxt, priorFailureMsg); + JavaType t = _hasTypeResolver + ? _handleMissingTypeId(ctxt, priorFailureMsg) : _baseType; if (t == null) { // 09-Mar-2017, tatu: Is this the right thing to do? return null; diff --git a/src/main/java/tools/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java b/src/main/java/tools/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java index c9d9995b3c..101464b5cc 100644 --- a/src/main/java/tools/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java +++ b/src/main/java/tools/jackson/databind/jsontype/impl/StdTypeResolverBuilder.java @@ -6,6 +6,8 @@ import tools.jackson.databind.*; import tools.jackson.databind.cfg.MapperConfig; +import tools.jackson.databind.introspect.AnnotatedClass; +import tools.jackson.databind.introspect.AnnotatedClassResolver; import tools.jackson.databind.jsontype.*; import tools.jackson.databind.util.ClassUtil; @@ -192,7 +194,8 @@ public TypeDeserializer buildTypeDeserializer(DeserializationContext ctxt, case PROPERTY: case EXISTING_PROPERTY: // as per [#528] same class as PROPERTY return new AsPropertyTypeDeserializer(baseType, idRes, - _typeProperty, _typeIdVisible, defaultImpl, _includeAs); + _typeProperty, _typeIdVisible, defaultImpl, _includeAs, + _hasTypeResolver(ctxt, baseType)); case WRAPPER_OBJECT: return new AsWrapperTypeDeserializer(baseType, idRes, _typeProperty, _typeIdVisible, defaultImpl); @@ -372,4 +375,23 @@ protected boolean allowPrimitiveTypes(DatabindContext ctxt, JavaType baseType) { return false; } + + + /** + * Checks whether the given class has annotations indicating some type resolver + * is applied, for example {@link com.fasterxml.jackson.annotation.JsonSubTypes}. + * Only initializes {@link #_hasTypeResolver} once if its value is null. + * + * @param ctxt Currently active context + * @param baseType the base type to check for type resolver annotations + * + * @return true if the class has type resolver annotations, false otherwise + */ + protected boolean _hasTypeResolver(DatabindContext ctxt, JavaType baseType) { + AnnotatedClass ac = + AnnotatedClassResolver.resolveWithoutSuperTypes(ctxt.getConfig(), + baseType.getRawClass()); + AnnotationIntrospector ai = ctxt.getAnnotationIntrospector(); + return ai.findPolymorphicTypeInfo(ctxt.getConfig(), ac) != null; + } } diff --git a/src/test/java/tools/jackson/failing/JsonTypeInfoIgnored2968Test.java b/src/test/java/tools/jackson/databind/jsontype/JsonTypeInfoIgnored2968Test.java similarity index 92% rename from src/test/java/tools/jackson/failing/JsonTypeInfoIgnored2968Test.java rename to src/test/java/tools/jackson/databind/jsontype/JsonTypeInfoIgnored2968Test.java index b159397e5c..b391c4a8e8 100644 --- a/src/test/java/tools/jackson/failing/JsonTypeInfoIgnored2968Test.java +++ b/src/test/java/tools/jackson/databind/jsontype/JsonTypeInfoIgnored2968Test.java @@ -1,4 +1,4 @@ -package tools.jackson.failing; +package tools.jackson.databind.jsontype; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -98,7 +98,7 @@ public void testDeserializationWrapperWithDefaultTyping() throws Exception { final String defaultTypedJson = a2q( "{'value':" + - "['com.fasterxml.jackson.databind.jsontype.JsonTypeInfoIgnored2968Test$BasketBall'," + + "['"+getClass().getName()+"$BasketBall'," + "{'size':42}]}"); BallValueWrapper wrapper = mapper.readValue(defaultTypedJson, BallValueWrapper.class); @@ -118,8 +118,7 @@ public void testDeserializationBaseClassWithDefaultTyping() throws Exception { try { mapper.readValue(concreteTypeJson, SimpleBall.class); } catch (MismatchedInputException | InvalidDefinitionException e) { - verifyException(e, "Unexpected token (START_OBJECT), expected START_ARRAY: need Array value " + - "to contain `As.WRAPPER_ARRAY` type information for class"); + verifyException(e, "Unexpected token", "START_OBJECT", "expected", "START_ARRAY"); } } } diff --git a/src/test/java/tools/jackson/failing/DeserDefaultTypedConcrete2968Test.java b/src/test/java/tools/jackson/databind/jsontype/deftyping/DeserDefaultTypedConcrete2968Test.java similarity index 93% rename from src/test/java/tools/jackson/failing/DeserDefaultTypedConcrete2968Test.java rename to src/test/java/tools/jackson/databind/jsontype/deftyping/DeserDefaultTypedConcrete2968Test.java index 5ef9770d36..da0bd4b0f2 100644 --- a/src/test/java/tools/jackson/failing/DeserDefaultTypedConcrete2968Test.java +++ b/src/test/java/tools/jackson/databind/jsontype/deftyping/DeserDefaultTypedConcrete2968Test.java @@ -1,4 +1,4 @@ -package tools.jackson.failing; +package tools.jackson.databind.jsontype.deftyping; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -23,6 +23,7 @@ public BasketBall(int size) { } } + // [databind#2968] / [databind#3824] public void testDeserializationConcreteClassWithDefaultTyping() throws Exception { final PolymorphicTypeValidator ptv = BasicPolymorphicTypeValidator.builder() .allowIfBaseType(SimpleBall.class)