diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 61ed80fddd..be405fbabb 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -1140,3 +1140,7 @@ Joshua Shannon (retrodaredevil@github) * Reported, contributed fix for #2785: Polymorphic subtypes not registering on copied ObjectMapper (2.11.1) (2.11.2) + +Daniel Hrabovcak (TheSpiritXIII@github) + * Reported #2796: `TypeFactory.constructType()` does not take `TypeBindings` correctly + (2.11.2) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 0a136e5536..197a86c110 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -10,6 +10,8 @@ Project: jackson-databind `createGenerator()` #2785: Polymorphic subtypes not registering on copied ObjectMapper (2.11.1) (reported, fix contributed by Joshua S) +#2796: `TypeFactory.constructType()` does not take `TypeBindings` correctly + (reported by Daniel H) 2.11.1 (25-Jun-2020) 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 ecef0a6b7f..17d1d31966 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java @@ -699,9 +699,15 @@ public JavaType constructType(Type type) { } public JavaType constructType(Type type, TypeBindings bindings) { + // 15-Jun-2020, tatu: To resolve (parts of) [databind#2796], need to + // call _fromClass() directly if we get `Class` argument + if (type instanceof Class) { + JavaType resultType = _fromClass(null, (Class) type, bindings); + return _applyModifiers(type, resultType); + } return _fromAny(null, type, bindings); } - + public JavaType constructType(TypeReference typeRef) { // 19-Oct-2015, tatu: Simpler variant like so should work @@ -1274,51 +1280,58 @@ protected JavaType _findWellKnownSimple(Class clz) { * as Java typing returned from getGenericXxx methods * (usually for a return or argument type). */ - protected JavaType _fromAny(ClassStack context, Type type, TypeBindings bindings) + protected JavaType _fromAny(ClassStack context, Type srcType, TypeBindings bindings) { JavaType resultType; // simple class? - if (type instanceof Class) { + if (srcType instanceof Class) { // Important: remove possible bindings since this is type-erased thingy - resultType = _fromClass(context, (Class) type, EMPTY_BINDINGS); + resultType = _fromClass(context, (Class) srcType, EMPTY_BINDINGS); } // But if not, need to start resolving. - else if (type instanceof ParameterizedType) { - resultType = _fromParamType(context, (ParameterizedType) type, bindings); + else if (srcType instanceof ParameterizedType) { + resultType = _fromParamType(context, (ParameterizedType) srcType, bindings); } - else if (type instanceof JavaType) { // [databind#116] + else if (srcType instanceof JavaType) { // [databind#116] // no need to modify further if we already had JavaType - return (JavaType) type; + return (JavaType) srcType; } - else if (type instanceof GenericArrayType) { - resultType = _fromArrayType(context, (GenericArrayType) type, bindings); + else if (srcType instanceof GenericArrayType) { + resultType = _fromArrayType(context, (GenericArrayType) srcType, bindings); } - else if (type instanceof TypeVariable) { - resultType = _fromVariable(context, (TypeVariable) type, bindings); + else if (srcType instanceof TypeVariable) { + resultType = _fromVariable(context, (TypeVariable) srcType, bindings); } - else if (type instanceof WildcardType) { - resultType = _fromWildcard(context, (WildcardType) type, bindings); + else if (srcType instanceof WildcardType) { + resultType = _fromWildcard(context, (WildcardType) srcType, bindings); } else { // sanity check - throw new IllegalArgumentException("Unrecognized Type: "+((type == null) ? "[null]" : type.toString())); + throw new IllegalArgumentException("Unrecognized Type: "+((srcType == null) ? "[null]" : srcType.toString())); } // 21-Feb-2016, nateB/tatu: as per [databind#1129] (applied for 2.7.2), // we do need to let all kinds of types to be refined, esp. for Scala module. - if (_modifiers != null) { - TypeBindings b = resultType.getBindings(); - if (b == null) { - b = EMPTY_BINDINGS; - } - for (TypeModifier mod : _modifiers) { - JavaType t = mod.modifyType(resultType, type, b, this); - if (t == null) { - throw new IllegalStateException(String.format( - "TypeModifier %s (of type %s) return null for type %s", - mod, mod.getClass().getName(), resultType)); - } - resultType = t; + return _applyModifiers(srcType, resultType); + } + + protected JavaType _applyModifiers(Type srcType, JavaType resolvedType) + { + if (_modifiers == null) { + return resolvedType; + } + JavaType resultType = resolvedType; + TypeBindings b = resultType.getBindings(); + if (b == null) { + b = EMPTY_BINDINGS; + } + for (TypeModifier mod : _modifiers) { + JavaType t = mod.modifyType(resultType, srcType, b, this); + if (t == null) { + throw new IllegalStateException(String.format( + "TypeModifier %s (of type %s) return null for type %s", + mod, mod.getClass().getName(), resultType)); } + resultType = t; } return resultType; } diff --git a/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java b/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java index aba0a28307..35ab672148 100644 --- a/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java +++ b/src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java @@ -278,7 +278,7 @@ public void testCanonicalWithSpaces() public void testCollections() { // Ok, first: let's test what happens when we pass 'raw' Collection: - TypeFactory tf = TypeFactory.defaultInstance(); + final TypeFactory tf = TypeFactory.defaultInstance(); JavaType t = tf.constructType(ArrayList.class); assertEquals(CollectionType.class, t.getClass()); assertSame(ArrayList.class, t.getRawClass()); @@ -299,7 +299,19 @@ public void testCollections() assertEquals(CollectionType.class, t.getClass()); assertSame(String.class, ((CollectionType) t).getContentType().getRawClass()); } - + + // [databind#2796] + public void testCollectionsWithBindings() + { + final TypeFactory tf = TypeFactory.defaultInstance(); + TypeBindings tb = TypeBindings.create(Set.class, new JavaType[] { + tf.constructType(String.class) }); + JavaType t = tf.constructType(ArrayList.class, tb); + assertEquals(CollectionType.class, t.getClass()); + assertSame(ArrayList.class, t.getRawClass()); + assertSame(String.class, ((CollectionType) t).getContentType().getRawClass()); + } + // since 2.7 public void testCollectionTypesRefined() {