diff --git a/release-notes/CREDITS b/release-notes/CREDITS index 1d2bbb252a..df82843bd2 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS @@ -247,6 +247,9 @@ Dmitry Spikhalskiy (Spikhalskiy@github) * Reported #731, suggested the way to fix it: XmlAdapter result marshaling error in case of ValueType=Object (2.5.3) + * Reported #1456: `TypeFactory` type resolution broken in 2.7 for generic types + when using `constructType` with context + (2.7.9 / 2.8.6) John Meyer (jpmeyer@github) * Reported, contributed fix for #745: EnumDeserializer.deserializerForCreator() fails diff --git a/release-notes/VERSION b/release-notes/VERSION index adcdecd46f..f0d8611459 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -13,6 +13,9 @@ Project: jackson-databind #1432: Off by 1 bug in PropertyValueBuffer (reported by Kevin D) #1439: NPE when using with filter id, serializing `java.util.Map` types +#1456: `TypeFactory` type resolution broken in 2.7 for generic types + when using `constructType` with context + (reported by Dmitry S) 2.7.8 (26-Sep-2016) 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 1e85958633..0022dddaf4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java @@ -621,9 +621,8 @@ public JavaType constructType(TypeReference typeRef) */ @Deprecated public JavaType constructType(Type type, Class contextClass) { - TypeBindings bindings = (contextClass == null) - ? TypeBindings.emptyBindings() : constructType(contextClass).getBindings(); - return _fromAny(null, type, bindings); + JavaType contextType = (contextClass == null) ? null : constructType(contextClass); + return constructType(type, contextType); } /** @@ -631,8 +630,27 @@ public JavaType constructType(Type type, Class contextClass) { */ @Deprecated public JavaType constructType(Type type, JavaType contextType) { - TypeBindings bindings = (contextType == null) - ? TypeBindings.emptyBindings() : contextType.getBindings(); + TypeBindings bindings; + if (contextType == null) { + bindings = TypeBindings.emptyBindings(); + } else { + bindings = contextType.getBindings(); + // 16-Nov-2016, tatu: Unfortunately as per [databind#1456] this can't + // be made to work for some cases used to work (even if accidentally); + // however, we can try a simple heuristic to increase chances of + // compatibility from 2.6 code + if (type.getClass() != Class.class) { + // Ok: so, ideally we would test super-interfaces if necessary; + // but let's assume most if not all cases are for classes. + while (bindings.isEmpty()) { + contextType = contextType.getSuperClass(); + if (contextType == null) { + break; + } + bindings = contextType.getBindings(); + } + } + } return _fromAny(null, type, bindings); } diff --git a/src/test/java/com/fasterxml/jackson/failing/GenericParameterTypeFactory1456Test.java b/src/test/java/com/fasterxml/jackson/databind/type/DeprecatedConstructType1456Test.java similarity index 79% rename from src/test/java/com/fasterxml/jackson/failing/GenericParameterTypeFactory1456Test.java rename to src/test/java/com/fasterxml/jackson/databind/type/DeprecatedConstructType1456Test.java index 03efadb1e7..8d3e58caba 100644 --- a/src/test/java/com/fasterxml/jackson/failing/GenericParameterTypeFactory1456Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/type/DeprecatedConstructType1456Test.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.failing; +package com.fasterxml.jackson.databind.type; import java.lang.reflect.Method; import java.lang.reflect.Type; @@ -8,7 +8,9 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; import com.fasterxml.jackson.databind.introspect.AnnotatedParameter; -public class GenericParameterTypeFactory1456Test extends BaseMapTest +// Tests for [databind#1456]: resolution using methods deprecated +// in 2.7, but used to work in 2.6 +public class DeprecatedConstructType1456Test extends BaseMapTest { public static class BaseController { public void process(Entity entity) {} @@ -21,8 +23,9 @@ public static class BaseEntity {} public static class ImplEntity extends BaseEntity {} private final ObjectMapper MAPPER = new ObjectMapper(); - - public void testGenericParameterDirect() throws Exception + + @SuppressWarnings("deprecation") + public void testGenericResolutionUsingDeprecated() throws Exception { Method proceed = BaseController.class.getMethod("process", BaseEntity.class); Type entityType = proceed.getGenericParameterTypes()[0]; @@ -31,6 +34,7 @@ public void testGenericParameterDirect() throws Exception assertEquals(ImplEntity.class, resolvedType.getRawClass()); } + // and this is how new code should resolve types if at all possible public void testGenericParameterViaClass() throws Exception { BeanDescription desc = MAPPER.getDeserializationConfig().introspect(