From 09ce4befa126abc293952c715b8bb24f8a302388 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sat, 28 Mar 2020 14:08:33 -0700 Subject: [PATCH] More work towards solving #2632 --- .../databind/DeserializationContext.java | 9 ++++-- .../jackson/databind/SerializerProvider.java | 9 ++++-- .../jackson/databind/cfg/MapperConfig.java | 3 +- .../deser/BasicDeserializerFactory.java | 7 +++-- .../jackson/databind/type/TypeFactory.java | 30 ++++++++++++++++++- 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 097466723f..3541ac0873 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -254,9 +254,12 @@ public final TypeFactory getTypeFactory() { @Override // since 2.11 public JavaType constructSpecializedType(JavaType baseType, Class subclass) { - // No specialized handling for deserialization, but needs to be implemented - return baseType.hasRawClass(subclass) ? baseType - : getConfig().constructSpecializedType(baseType, subclass); + if (baseType.hasRawClass(subclass)) { + return baseType; + } + // On deserialization side, still uses "strict" type-compatibility checking; + // see [databind#2632] about serialization side + return getConfig().getTypeFactory().constructSpecializedType(baseType, subclass, false); } /** diff --git a/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java b/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java index 2216d9c410..121a50359d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java @@ -335,9 +335,12 @@ public final TypeFactory getTypeFactory() { @Override // since 2.11 public JavaType constructSpecializedType(JavaType baseType, Class subclass) { - // Need little bit different handling due to [databind#2632] - return baseType.hasRawClass(subclass) ? baseType - : getConfig().constructSpecializedType(baseType, subclass); + if (baseType.hasRawClass(subclass)) { + return baseType; + } + // Need little bit different handling due to [databind#2632]; pass `true` for + // "relaxed" type assingment checks. + return getConfig().getTypeFactory().constructSpecializedType(baseType, subclass, true); } @Override diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java index 78571ed543..64afde82ec 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java @@ -319,7 +319,8 @@ public final JavaType constructType(TypeReference valueTypeRef) { } public JavaType constructSpecializedType(JavaType baseType, Class subclass) { - return getTypeFactory().constructSpecializedType(baseType, subclass); + // note: since 2.11 specify "strict" resolution + return getTypeFactory().constructSpecializedType(baseType, subclass, true); } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java index d0a7dc526f..9be8904f81 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java @@ -1246,7 +1246,8 @@ protected CollectionType _mapAbstractCollectionType(JavaType type, Deserializati { final Class collectionClass = ContainerDefaultMappings.findCollectionFallback(type); if (collectionClass != null) { - return (CollectionType) config.constructSpecializedType(type, collectionClass); + return (CollectionType) config.getTypeFactory() + .constructSpecializedType(type, collectionClass, true); } return null; } @@ -1394,12 +1395,12 @@ protected MapType _mapAbstractMapType(JavaType type, DeserializationConfig confi { final Class mapClass = ContainerDefaultMappings.findMapFallback(type); if (mapClass != null) { - return (MapType) config.constructSpecializedType(type, mapClass); + return (MapType) config.getTypeFactory() + .constructSpecializedType(type, mapClass, true); } return null; } - // Copied almost verbatim from "createMapDeserializer" -- should try to share more code @Override public JsonDeserializer createMapLikeDeserializer(DeserializationContext ctxt, diff --git a/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java b/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java index 220d938f68..4b5a2c6b54 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java @@ -359,8 +359,36 @@ protected Class _findPrimitive(String className) * Can be used, for example, to get equivalent of "HashMap<String,Integer>" * from "Map<String,Integer>" by giving HashMap.class * as subclass. + * Short-cut for: + *
+     * constructSpecializedType(baseType, subclass, class);
+     *
+ * that is, will use "strict" compatibility checking, usually used for + * deserialization purposes (but often not for serialization). + */ + public JavaType constructSpecializedType(JavaType baseType, Class subclass) { + return constructSpecializedType(baseType, subclass, false); + } + + /** + * Factory method for creating a subtype of given base type, as defined + * by specified subclass; but retaining generic type information if any. + * Can be used, for example, to get equivalent of "HashMap<String,Integer>" + * from "Map<String,Integer>" by giving HashMap.class + * as subclass. + * + * @param baseType Declared base type with resolved type parameters + * @param subclass Runtime subtype to use for resolving + * @param relaxedCompatibilityCheck Whether checking for type-assignment compatibility + * should be "relaxed" ({@code true}) or "strict" ({@code false}): typically + * serialization uses relaxed, deserialization strict checking. + * + * @return Resolved sub-type + * + * @since 2.11 */ - public JavaType constructSpecializedType(JavaType baseType, Class subclass) + public JavaType constructSpecializedType(JavaType baseType, Class subclass, + boolean relaxedCompatibilityCheck) { // simple optimization to avoid costly introspection if type-erased type does NOT differ final Class rawBase = baseType.getRawClass();