Skip to content

Commit 1014493

Browse files
committed
Fix #2821
1 parent 4b9c723 commit 1014493

File tree

8 files changed

+151
-14
lines changed

8 files changed

+151
-14
lines changed

release-notes/CREDITS-2.x

+6
Original file line numberDiff line numberDiff line change
@@ -1148,3 +1148,9 @@ Daniel Hrabovcak (TheSpiritXIII@github)
11481148
Daniel Wu (DanielYWoo@github)
11491149
* Reported #2840: `ObjectMapper.activateDefaultTypingAsProperty()` is not using
11501150
(2.11.3)
1151+
1152+
Lari Hotari (lhotari@github)
1153+
1154+
* Reported #2821: Json serialization fails or a specific case that contains generics and
1155+
static methods with generic parameters (2.11.1 -> 2.11.2 regression)
1156+
(2.11.3)

release-notes/VERSION-2.x

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Project: jackson-databind
66

77
2.11.3 (not yet released)
88

9+
#2815: Add `JsonFormat.Shape` awareness for UUID serialization (`UUIDSerializer`)
10+
#2821: Json serialization fails or a specific case that contains generics and
11+
static methods with generic parameters (2.11.1 -> 2.11.2 regression)
12+
(reported by Lari H)
913
#2840: `ObjectMapper.activateDefaultTypingAsProperty()` is not using
1014
parameter `PolymorphicTypeValidator`
1115
(reported by Daniel W)
@@ -22,7 +26,6 @@ Project: jackson-databind
2226
(reported by isaki@github)
2327
#2796: `TypeFactory.constructType()` does not take `TypeBindings` correctly
2428
(reported by Daniel H)
25-
#2815: Add `JsonFormat.Shape` awareness for UUID serialization (`UUIDSerializer`)
2629

2730
2.11.1 (25-Jun-2020)
2831

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java

+1
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ private final Creators _creators() {
396396
c = NO_CREATORS;
397397
} else {
398398
c = AnnotatedCreatorCollector.collectCreators(_annotationIntrospector,
399+
_typeFactory,
399400
this, _type, _primaryMixIn, _collectAnnotations);
400401
}
401402
_creators = c;

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedCreatorCollector.java

+36-9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.fasterxml.jackson.databind.AnnotationIntrospector;
1313
import com.fasterxml.jackson.databind.JavaType;
1414
import com.fasterxml.jackson.databind.introspect.AnnotatedClass.Creators;
15+
import com.fasterxml.jackson.databind.type.TypeFactory;
1516
import com.fasterxml.jackson.databind.util.ClassUtil;
1617

1718
/**
@@ -27,6 +28,9 @@ final class AnnotatedCreatorCollector
2728

2829
private final TypeResolutionContext _typeContext;
2930

31+
// @since 2.11.3
32+
private final TypeFactory _typeFactory;
33+
3034
/**
3135
* @since 2.11
3236
*/
@@ -36,23 +40,36 @@ final class AnnotatedCreatorCollector
3640

3741
private AnnotatedConstructor _defaultConstructor;
3842

39-
AnnotatedCreatorCollector(AnnotationIntrospector intr,
43+
AnnotatedCreatorCollector(AnnotationIntrospector intr, TypeFactory tf,
4044
TypeResolutionContext tc, boolean collectAnnotations)
4145
{
4246
super(intr);
47+
_typeFactory = tf;
4348
_typeContext = tc;
4449
_collectAnnotations = collectAnnotations;
4550
}
4651

52+
@Deprecated // since 2.11.3; to be removed ASAP (2.12.0)
4753
public static Creators collectCreators(AnnotationIntrospector intr,
48-
TypeResolutionContext tc,
54+
TypeResolutionContext tc,
55+
JavaType type, Class<?> primaryMixIn, boolean collectAnnotations)
56+
{
57+
return collectCreators(intr, TypeFactory.defaultInstance(),
58+
tc, type, primaryMixIn, collectAnnotations);
59+
}
60+
61+
/**
62+
* @since 2.11.3
63+
*/
64+
public static Creators collectCreators(AnnotationIntrospector intr,
65+
TypeFactory typeFactory, TypeResolutionContext tc,
4966
JavaType type, Class<?> primaryMixIn, boolean collectAnnotations)
5067
{
5168
final boolean checkClassAnnotations = (intr != null)
5269
&& !ClassUtil.isJDKClass(type.getRawClass());
5370

5471
// Constructor also always members of resolved class, parent == resolution context
55-
return new AnnotatedCreatorCollector(intr, tc, checkClassAnnotations)
72+
return new AnnotatedCreatorCollector(intr, typeFactory, tc, checkClassAnnotations)
5673
.collect(type, primaryMixIn);
5774
}
5875

@@ -203,6 +220,13 @@ private List<AnnotatedMethod> _findPotentialFactories(JavaType type, Class<?> pr
203220
if (candidates == null) {
204221
return Collections.emptyList();
205222
}
223+
// 05-Sep-2020, tatu: Important fix wrt [databind#2821] -- static methods
224+
// do NOT have type binding context of the surrounding class and although
225+
// passing that should not break things, it appears to... Regardless,
226+
// it should not be needed or useful as those bindings are only available
227+
// to non-static members
228+
TypeResolutionContext typeResCtxt = new TypeResolutionContext.Empty(_typeFactory);
229+
206230
int factoryCount = candidates.size();
207231
List<AnnotatedMethod> result = new ArrayList<>(factoryCount);
208232
for (int i = 0; i < factoryCount; ++i) {
@@ -225,7 +249,8 @@ private List<AnnotatedMethod> _findPotentialFactories(JavaType type, Class<?> pr
225249
for (int i = 0; i < factoryCount; ++i) {
226250
if (key.equals(methodKeys[i])) {
227251
result.set(i,
228-
constructFactoryCreator(candidates.get(i), mixinFactory));
252+
constructFactoryCreator(candidates.get(i),
253+
typeResCtxt, mixinFactory));
229254
break;
230255
}
231256
}
@@ -236,7 +261,8 @@ private List<AnnotatedMethod> _findPotentialFactories(JavaType type, Class<?> pr
236261
AnnotatedMethod factory = result.get(i);
237262
if (factory == null) {
238263
result.set(i,
239-
constructFactoryCreator(candidates.get(i), null));
264+
constructFactoryCreator(candidates.get(i),
265+
typeResCtxt, null));
240266
}
241267
}
242268
return result;
@@ -308,18 +334,19 @@ protected AnnotatedConstructor constructNonDefaultConstructor(ClassUtil.Ctor cto
308334
collectAnnotations(ctor, mixin), resolvedAnnotations);
309335
}
310336

311-
protected AnnotatedMethod constructFactoryCreator(Method m, Method mixin)
337+
protected AnnotatedMethod constructFactoryCreator(Method m,
338+
TypeResolutionContext typeResCtxt, Method mixin)
312339
{
313340
final int paramCount = m.getParameterTypes().length;
314341
if (_intr == null) { // when annotation processing is disabled
315-
return new AnnotatedMethod(_typeContext, m, _emptyAnnotationMap(),
342+
return new AnnotatedMethod(typeResCtxt, m, _emptyAnnotationMap(),
316343
_emptyAnnotationMaps(paramCount));
317344
}
318345
if (paramCount == 0) { // common enough we can slightly optimize
319-
return new AnnotatedMethod(_typeContext, m, collectAnnotations(m, mixin),
346+
return new AnnotatedMethod(typeResCtxt, m, collectAnnotations(m, mixin),
320347
NO_ANNOTATION_MAPS);
321348
}
322-
return new AnnotatedMethod(_typeContext, m, collectAnnotations(m, mixin),
349+
return new AnnotatedMethod(typeResCtxt, m, collectAnnotations(m, mixin),
323350
collectAnnotations(m.getParameterAnnotations(),
324351
(mixin == null) ? null : mixin.getParameterAnnotations()));
325352
}

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedMethod.java

-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ public AnnotatedMethod withAnnotations(AnnotationMap ann) {
5757
return new AnnotatedMethod(_typeContext, _method, ann, _paramAnnotations);
5858
}
5959

60-
6160
@Override
6261
public Method getAnnotated() { return _method; }
6362

src/main/java/com/fasterxml/jackson/databind/introspect/TypeResolutionContext.java

+21
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,25 @@ public String toString() {
4444
}
4545
*/
4646
}
47+
48+
/**
49+
* Dummy implementation for case where there are no bindings available
50+
* (for example, for static methods and fields)
51+
*
52+
* @since 2.11.3
53+
*/
54+
public static class Empty
55+
implements TypeResolutionContext
56+
{
57+
private final TypeFactory _typeFactory;
58+
59+
public Empty(TypeFactory tf) {
60+
_typeFactory = tf;
61+
}
62+
63+
@Override
64+
public JavaType resolveType(Type type) {
65+
return _typeFactory.constructType(type);
66+
}
67+
}
4768
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,6 @@ protected JavaType _fromWellKnownClass(ClassStack context, Class<?> rawType, Typ
14681468
if (bindings == null) {
14691469
bindings = EMPTY_BINDINGS;
14701470
}
1471-
14721471
// Quite simple when we resolving exact class/interface; start with that
14731472
if (rawType == Map.class) {
14741473
return _mapType(rawType, bindings, superClass, superInterfaces);

src/test/java/com/fasterxml/jackson/databind/ser/TestGenericTypes.java

+83-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import java.util.*;
44

5-
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
5+
import com.fasterxml.jackson.annotation.*;
6+
67
import com.fasterxml.jackson.core.type.TypeReference;
8+
79
import com.fasterxml.jackson.databind.BaseMapTest;
810
import com.fasterxml.jackson.databind.ObjectMapper;
911

@@ -99,7 +101,69 @@ public Impl727(int a, int b) {
99101
this.a = a;
100102
this.b = b;
101103
}
102-
}
104+
}
105+
106+
// For [databind#2821]
107+
static final class Wrapper2821 {
108+
// if Entity<?> -> Entity , the test passes
109+
final List<Entity2821<?>> entities;
110+
111+
@JsonCreator
112+
public Wrapper2821(List<Entity2821<?>> entities) {
113+
this.entities = entities;
114+
}
115+
116+
public List<Entity2821<?>> getEntities() {
117+
return this.entities;
118+
}
119+
}
120+
121+
static class Entity2821<T> {
122+
@JsonIgnore
123+
final Attributes2821 attributes;
124+
125+
final T data;
126+
127+
public Entity2821(Attributes2821 attributes, T data) {
128+
this.attributes = attributes;
129+
this.data = data;
130+
}
131+
132+
@JsonUnwrapped
133+
public Attributes2821 getAttributes() {
134+
return attributes;
135+
}
136+
137+
public T getData() {
138+
return data;
139+
}
140+
141+
@JsonCreator
142+
public static <T> Entity2821<T> create(@JsonProperty("attributes") Attributes2821 attributes,
143+
@JsonProperty("data") T data) {
144+
return new Entity2821<>(attributes, data);
145+
}
146+
}
147+
148+
public static class Attributes2821 {
149+
public final String id;
150+
151+
public Attributes2821(String id) {
152+
this.id = id;
153+
}
154+
155+
@JsonCreator
156+
public static Attributes2821 create(@JsonProperty("id") String id) {
157+
return new Attributes2821(id);
158+
}
159+
160+
// if this method is removed, the test passes
161+
@SuppressWarnings("rawtypes")
162+
public static Attributes2821 dummyMethod(Map attributes) {
163+
return null;
164+
}
165+
}
166+
103167
/*
104168
/**********************************************************
105169
/* Unit tests
@@ -178,4 +242,21 @@ public void testRootTypeForCollections727() throws Exception
178242
TypeReference<?> typeRef = new TypeReference<List<Base727>>() { };
179243
assertEquals(EXP, MAPPER.writer().forType(typeRef).writeValueAsString(input));
180244
}
245+
246+
// For [databind#2821]
247+
@SuppressWarnings("unchecked")
248+
public void testTypeResolution2821() throws Exception
249+
{
250+
Entity2821<String> entity = new Entity2821<>(new Attributes2821("id"), "hello");
251+
List<Entity2821<?>> list;
252+
{
253+
List<Entity2821<String>> foo = new ArrayList<>();
254+
foo.add(entity);
255+
list = (List<Entity2821<?>>) (List<?>) foo;
256+
}
257+
Wrapper2821 val = new Wrapper2821(list);
258+
// fails with com.fasterxml.jackson.databind.JsonMappingException: Strange Map type java.util.Map: cannot determine type parameters (through reference chain: com.github.lhotari.jacksonbug.JacksonBugIsolatedTest$Wrapper["entities"]->java.util.Collections$SingletonList[0]->com.github.lhotari.jacksonbug.JacksonBugIsolatedTest$Entity["attributes"])
259+
String json = MAPPER.writeValueAsString(val);
260+
assertNotNull(json);
261+
}
181262
}

0 commit comments

Comments
 (0)