Skip to content

Commit dbbca94

Browse files
committed
Merge branch '2.6'
Conflicts: release-notes/VERSION
2 parents 769853a + 1eb498e commit dbbca94

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

release-notes/VERSION

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ Project: jackson-databind
1010
(contributed by David H)
1111
#933:Close some gaps to allow using the tryToResolveUnresolved flows
1212

13+
2.6.3 (not yet released)
14+
15+
#938: Regression: `StackOverflowError` with recursive types that contain `Map.Entry`
16+
(reported by jloisel@github)
17+
1318
2.6.2 (14-Sep-2015)
1419

1520
#894: When using withFactory on ObjectMapper, the created Factory has a TypeParser

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,24 @@ public JavaType[] findTypeParameters(JavaType type, Class<?> expType)
381381
return findTypeParameters(raw, expType, new TypeBindings(this, type));
382382
}
383383

384+
/**
385+
* @since 2.7
386+
*/
387+
public JavaType[] findTypeParameters(JavaType type, Class<?> expType, TypeBindings bindings)
388+
{
389+
if (expType == type.getParameterSource()) {
390+
int count = type.containedTypeCount();
391+
if (count == 0) return null;
392+
JavaType[] result = new JavaType[count];
393+
for (int i = 0; i < count; ++i) {
394+
result[i] = type.containedType(i);
395+
}
396+
return result;
397+
}
398+
Class<?> raw = type.getRawClass();
399+
return findTypeParameters(raw, expType, bindings);
400+
}
401+
384402
public JavaType[] findTypeParameters(Class<?> clz, Class<?> expType) {
385403
return findTypeParameters(clz, expType, new TypeBindings(this, clz));
386404
}
@@ -1003,6 +1021,8 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)
10031021
if (Map.class.isAssignableFrom(rawType)) {
10041022
// 19-Mar-2015, tatu: Looks like 2nd arg ought to be Map.class, but that causes fails
10051023
JavaType subtype = constructSimpleType(rawType, rawType, pt);
1024+
// 23-Sep-2015, tatu: and why do we not pass 3rd arg of 'context'? Won't help, it seems,
1025+
// plus causes other issues. Sigh.
10061026
JavaType[] mapParams = findTypeParameters(subtype, Map.class);
10071027
if (mapParams.length != 2) {
10081028
throw new IllegalArgumentException("Could not find 2 type parameters for Map class "+rawType.getName()+" (found "+mapParams.length+")");
@@ -1027,8 +1047,9 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)
10271047
rt = pt[0];
10281048
}
10291049
} else {
1030-
JavaType[] pts = findTypeParameters(rawType, AtomicReference.class);
1031-
if (pts != null && pts.length != 1) {
1050+
JavaType subtype = constructSimpleType(rawType, rawType, pt);
1051+
JavaType[] pts = findTypeParameters(subtype, AtomicReference.class, context);
1052+
if (pts != null && pts.length == 1) {
10321053
rt = pts[0];
10331054
}
10341055
}
@@ -1043,8 +1064,11 @@ protected JavaType _fromParamType(ParameterizedType type, TypeBindings context)
10431064
vt = pt[1];
10441065
}
10451066
} else {
1046-
JavaType[] pts = findTypeParameters(rawType, Map.Entry.class);
1047-
if (pts != null && pts.length != 2) {
1067+
// 23-Sep-2015, tatu: Must be careful here; type resolution can NOT be done
1068+
// directly quite yet. Instead, need to do indirectly...
1069+
JavaType subtype = constructSimpleType(rawType, rawType, pt);
1070+
JavaType[] pts = findTypeParameters(subtype, Map.Entry.class, context);
1071+
if (pts != null && pts.length == 2) {
10481072
kt = pts[0];
10491073
vt = pts[1];
10501074
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.fasterxml.jackson.databind.type;
2+
3+
import java.util.*;
4+
5+
import com.fasterxml.jackson.databind.*;
6+
7+
// for [databind#938]
8+
public class RecursiveType938Test extends BaseMapTest
9+
{
10+
public static interface Ability<T> { }
11+
12+
public static final class ImmutablePair<L, R> implements Map.Entry<L, R>, Ability<ImmutablePair<L, R>> {
13+
public final L key;
14+
public final R value;
15+
16+
public ImmutablePair(final L key, final R value) {
17+
this.key = key;
18+
this.value = value;
19+
}
20+
21+
@Override
22+
public L getKey() {
23+
return key;
24+
}
25+
26+
@Override
27+
public R getValue() {
28+
return value;
29+
}
30+
31+
@Override
32+
public R setValue(final R value) {
33+
throw new UnsupportedOperationException();
34+
}
35+
36+
static <L, R> ImmutablePair<L, R> of(final L left, final R right) {
37+
return new ImmutablePair<L, R>(left, right);
38+
}
39+
}
40+
41+
private final ObjectMapper MAPPER = new ObjectMapper();
42+
43+
public void testRecursivePair() throws Exception
44+
{
45+
JavaType t = MAPPER.constructType(ImmutablePair.class);
46+
47+
assertNotNull(t);
48+
assertEquals(ImmutablePair.class, t.getRawClass());
49+
50+
/*
51+
List<ImmutablePair<String, Double>> list = new ArrayList<ImmutablePair<String, Double>>();
52+
list.add(ImmutablePair.of("Hello World!", 123d));
53+
String json = MAPPER.writeValueAsString(list);
54+
assertNotNull(json);
55+
*/
56+
}
57+
}

0 commit comments

Comments
 (0)