diff --git a/release-notes/VERSION b/release-notes/VERSION index c497037ae7..a366ab9bb9 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -4,6 +4,11 @@ Project: jackson-databind === Releases === ------------------------------------------------------------------------ +2.6.3 (not yet released) + +#938: Regression: StackOverflowError with with 2.6.x (2.5.4 works fine) + (reported by jloisel@github) + 2.6.2 (14-Sep-2015) #894: When using withFactory on ObjectMapper, the created Factory has a TypeParser 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 f177963941..bc1b54a917 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java @@ -369,6 +369,24 @@ public JavaType[] findTypeParameters(JavaType type, Class expType) return findTypeParameters(raw, expType, new TypeBindings(this, type)); } + /** + * @since 2.7 + */ + public JavaType[] findTypeParameters(JavaType type, Class expType, TypeBindings bindings) + { + if (expType == type.getParameterSource()) { + int count = type.containedTypeCount(); + if (count == 0) return null; + JavaType[] result = new JavaType[count]; + for (int i = 0; i < count; ++i) { + result[i] = type.containedType(i); + } + return result; + } + Class raw = type.getRawClass(); + return findTypeParameters(raw, expType, bindings); + } + public JavaType[] findTypeParameters(Class clz, Class expType) { return findTypeParameters(clz, expType, new TypeBindings(this, clz)); } @@ -989,6 +1007,8 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context) if (Map.class.isAssignableFrom(rawType)) { // 19-Mar-2015, tatu: Looks like 2nd arg ought to be Map.class, but that causes fails JavaType subtype = constructSimpleType(rawType, rawType, pt); + // 23-Sep-2015, tatu: and why do we not pass 3rd arg of 'context'? Won't help, it seems, + // plus causes other issues. Sigh. JavaType[] mapParams = findTypeParameters(subtype, Map.class); if (mapParams.length != 2) { throw new IllegalArgumentException("Could not find 2 type parameters for Map class "+rawType.getName()+" (found "+mapParams.length+")"); @@ -1013,8 +1033,9 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context) rt = pt[0]; } } else { - JavaType[] pts = findTypeParameters(rawType, AtomicReference.class); - if (pts != null && pts.length != 1) { + JavaType subtype = constructSimpleType(rawType, rawType, pt); + JavaType[] pts = findTypeParameters(subtype, AtomicReference.class, context); + if (pts != null && pts.length == 1) { rt = pts[0]; } } @@ -1029,8 +1050,11 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context) vt = pt[1]; } } else { - JavaType[] pts = findTypeParameters(rawType, Map.Entry.class); - if (pts != null && pts.length != 2) { + // 23-Sep-2015, tatu: Must be careful here; type resolution can NOT be done + // directly quite yet. Instead, need to do indirectly... + JavaType subtype = constructSimpleType(rawType, rawType, pt); + JavaType[] pts = findTypeParameters(subtype, Map.Entry.class, context); + if (pts != null && pts.length == 2) { kt = pts[0]; vt = pts[1]; } diff --git a/src/test/java/com/fasterxml/jackson/databind/type/RecursiveType938Test.java b/src/test/java/com/fasterxml/jackson/databind/type/RecursiveType938Test.java new file mode 100644 index 0000000000..f41a87b7b8 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/type/RecursiveType938Test.java @@ -0,0 +1,57 @@ +package com.fasterxml.jackson.databind.type; + +import java.util.*; + +import com.fasterxml.jackson.databind.*; + +// for [databind#938] +public class RecursiveType938Test extends BaseMapTest +{ + public static interface Ability { } + + public static final class ImmutablePair implements Map.Entry, Ability> { + public final L key; + public final R value; + + public ImmutablePair(final L key, final R value) { + this.key = key; + this.value = value; + } + + @Override + public L getKey() { + return key; + } + + @Override + public R getValue() { + return value; + } + + @Override + public R setValue(final R value) { + throw new UnsupportedOperationException(); + } + + static ImmutablePair of(final L left, final R right) { + return new ImmutablePair(left, right); + } + } + + private final ObjectMapper MAPPER = new ObjectMapper(); + + public void testRecursivePair() throws Exception + { + JavaType t = MAPPER.constructType(ImmutablePair.class); + + assertNotNull(t); + assertEquals(ImmutablePair.class, t.getRawClass()); + + /* + List> list = new ArrayList>(); + list.add(ImmutablePair.of("Hello World!", 123d)); + String json = MAPPER.writeValueAsString(list); + assertNotNull(json); + */ + } +}