Skip to content

Commit 44b0cd3

Browse files
committed
Merge branch '2.11' into 2.12
2 parents af2ff9c + 1014493 commit 44b0cd3

File tree

8 files changed

+155
-17
lines changed

8 files changed

+155
-17
lines changed

release-notes/VERSION-2.x

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ Project: jackson-databind
6969

7070
2.11.3 (not yet released)
7171

72+
#2815: Add `JsonFormat.Shape` awareness for UUID serialization (`UUIDSerializer`)
73+
#2821: Json serialization fails or a specific case that contains generics and
74+
static methods with generic parameters (2.11.1 -> 2.11.2 regression)
75+
(reported by Lari H)
7276
#2840: `ObjectMapper.activateDefaultTypingAsProperty()` is not using
7377
parameter `PolymorphicTypeValidator`
7478
(reported by Daniel W)
@@ -85,7 +89,6 @@ Project: jackson-databind
8589
(reported by isaki@github)
8690
#2796: `TypeFactory.constructType()` does not take `TypeBindings` correctly
8791
(reported by Daniel H)
88-
#2815: Add `JsonFormat.Shape` awareness for UUID serialization (`UUIDSerializer`)
8992

9093
2.11.1 (25-Jun-2020)
9194

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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 36 additions & 9 deletions
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

Lines changed: 0 additions & 1 deletion
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

Lines changed: 21 additions & 0 deletions
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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,7 +1198,8 @@ private JavaType _mapType(Class<?> rawClass, TypeBindings bindings,
11981198
} else {
11991199
List<JavaType> typeParams = bindings.getTypeParameters();
12001200
// ok to have no types ("raw")
1201-
switch (typeParams.size()) {
1201+
final int pc = typeParams.size();
1202+
switch (pc) {
12021203
case 0: // acceptable?
12031204
kt = vt = _unknownType();
12041205
break;
@@ -1207,7 +1208,9 @@ private JavaType _mapType(Class<?> rawClass, TypeBindings bindings,
12071208
vt = typeParams.get(1);
12081209
break;
12091210
default:
1210-
throw new IllegalArgumentException("Strange Map type "+rawClass.getName()+": cannot determine type parameters");
1211+
throw new IllegalArgumentException(String.format(
1212+
"Strange Map type %s with %d type parameter%s (%s), can not resolve",
1213+
ClassUtil.nameOf(rawClass), pc, (pc == 1) ? "" : "s", bindings));
12111214
}
12121215
}
12131216
return MapType.construct(rawClass, bindings, superClass, superInterfaces, kt, vt);
@@ -1497,7 +1500,6 @@ protected JavaType _fromWellKnownClass(ClassStack context, Class<?> rawType, Typ
14971500
if (bindings == null) {
14981501
bindings = EMPTY_BINDINGS;
14991502
}
1500-
15011503
// Quite simple when we resolving exact class/interface; start with that
15021504
if (rawType == Map.class) {
15031505
return _mapType(rawType, bindings, superClass, superInterfaces);

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

Lines changed: 83 additions & 2 deletions
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
}

src/test/java/com/fasterxml/jackson/databind/type/TestTypeFactory.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ public void testMapTypesRefined()
401401
{
402402
TypeFactory tf = newTypeFactory();
403403
JavaType type = tf.constructType(new TypeReference<Map<String,List<Integer>>>() { });
404+
assertEquals(MapType.class, type.getClass());
404405
MapType mapType = (MapType) type;
405406
assertEquals(Map.class, mapType.getRawClass());
406407
assertEquals(String.class, mapType.getKeyType().getRawClass());
@@ -450,6 +451,7 @@ public void testMapTypesRaw()
450451
{
451452
TypeFactory tf = TypeFactory.defaultInstance();
452453
JavaType type = tf.constructType(HashMap.class);
454+
assertEquals(MapType.class, type.getClass());
453455
MapType mapType = (MapType) type;
454456
assertEquals(tf.constructType(Object.class), mapType.getKeyType());
455457
assertEquals(tf.constructType(Object.class), mapType.getContentType());
@@ -459,6 +461,7 @@ public void testMapTypesAdvanced()
459461
{
460462
TypeFactory tf = TypeFactory.defaultInstance();
461463
JavaType type = tf.constructType(MyMap.class);
464+
assertEquals(MapType.class, type.getClass());
462465
MapType mapType = (MapType) type;
463466
assertEquals(tf.constructType(String.class), mapType.getKeyType());
464467
assertEquals(tf.constructType(Long.class), mapType.getContentType());
@@ -483,6 +486,7 @@ public void testMapTypesSneaky()
483486
{
484487
TypeFactory tf = TypeFactory.defaultInstance();
485488
JavaType type = tf.constructType(IntLongMap.class);
489+
assertEquals(MapType.class, type.getClass());
486490
MapType mapType = (MapType) type;
487491
assertEquals(tf.constructType(Integer.class), mapType.getKeyType());
488492
assertEquals(tf.constructType(Long.class), mapType.getContentType());
@@ -496,7 +500,7 @@ public void testSneakyFieldTypes() throws Exception
496500
TypeFactory tf = TypeFactory.defaultInstance();
497501
Field field = SneakyBean.class.getDeclaredField("intMap");
498502
JavaType type = tf.constructType(field.getGenericType());
499-
assertTrue(type instanceof MapType);
503+
assertEquals(MapType.class, type.getClass());
500504
MapType mapType = (MapType) type;
501505
assertEquals(tf.constructType(Integer.class), mapType.getKeyType());
502506
assertEquals(tf.constructType(Long.class), mapType.getContentType());

0 commit comments

Comments
 (0)