Skip to content

Commit 4387090

Browse files
committed
Merge branch '2.8' into 2.9
2 parents 985a3f9 + dfaca81 commit 4387090

File tree

3 files changed

+69
-5
lines changed

3 files changed

+69
-5
lines changed

release-notes/VERSION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Project: jackson-databind
1111
#1799: Allow creation of custom sub-types of `NullNode`, `BooleanNode`, `MissingNode`
1212
#1804: `ValueInstantiator.canInstantiate()` ignores `canCreateUsingArrayDelegate()`
1313
(reported byb henryptung@github)
14+
#1807: Jackson-databind caches plain map deserializer and use it even map has `@JsonDeserializer`
15+
(reported by lexas2509@github)
1416

1517
2.9.2 (14-Oct-2017)
1618

src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ protected JsonDeserializer<Object> _findCachedDeserializer(JavaType type)
204204
if (type == null) {
205205
throw new IllegalArgumentException("Null JavaType passed");
206206
}
207-
if (_hasCustomValueHandler(type)) {
207+
if (_hasCustomHandlers(type)) {
208208
return null;
209209
}
210210
return _cachedDeserializers.get(type);
@@ -274,7 +274,7 @@ protected JsonDeserializer<Object> _createAndCache2(DeserializationContext ctxt,
274274
* (but can be re-defined for sub-classes by using @JsonCachable!)
275275
*/
276276
// 27-Mar-2015, tatu: As per [databind#735], avoid caching types with custom value desers
277-
boolean addToCache = !_hasCustomValueHandler(type) && deser.isCachable();
277+
boolean addToCache = !_hasCustomHandlers(type) && deser.isCachable();
278278

279279
/* we will temporarily hold on to all created deserializers (to
280280
* handle cyclic references, and possibly reuse non-cached
@@ -539,13 +539,23 @@ private JavaType modifyTypeByAnnotation(DeserializationContext ctxt,
539539
* Helper method used to prevent both caching and cache lookups for structured
540540
* types that have custom value handlers
541541
*
542-
* @since 2.4.6
542+
* @since 2.8.11
543543
*/
544-
private boolean _hasCustomValueHandler(JavaType t) {
544+
private boolean _hasCustomHandlers(JavaType t) {
545545
if (t.isContainerType()) {
546+
// First: value types may have both value and type handlers
546547
JavaType ct = t.getContentType();
547548
if (ct != null) {
548-
return (ct.getValueHandler() != null) || (ct.getTypeHandler() != null);
549+
if ((ct.getValueHandler() != null) || (ct.getTypeHandler() != null)) {
550+
return true;
551+
}
552+
}
553+
// Second: map(-like) types may have value handler for key (but not type; keys are untyped)
554+
if (t.isMapLikeType()) {
555+
JavaType kt = t.getKeyType();
556+
if (kt.getValueHandler() != null) {
557+
return true;
558+
}
549559
}
550560
}
551561
return false;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.fasterxml.jackson.databind.deser.jdk;
2+
3+
import java.io.IOException;
4+
import java.util.Map;
5+
import java.util.TreeMap;
6+
7+
import com.fasterxml.jackson.databind.*;
8+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
9+
10+
// for [databind#1807]
11+
public class MapDeserializerCachingTest extends BaseMapTest
12+
{
13+
public static class NonAnnotatedMapHolderClass {
14+
public Map<String, String> data = new TreeMap<String, String>();
15+
}
16+
17+
public static class MapHolder {
18+
@JsonDeserialize(keyUsing = MyKeyDeserializer.class)
19+
public Map<String, String> data = new TreeMap<String, String>();
20+
}
21+
22+
public static class MyKeyDeserializer extends KeyDeserializer {
23+
@Override
24+
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
25+
return key + " (CUSTOM)";
26+
}
27+
}
28+
29+
/*
30+
/**********************************************************
31+
/* Test methods
32+
/**********************************************************
33+
*/
34+
35+
public void testCachedSerialize() throws IOException {
36+
ObjectMapper mapper = new ObjectMapper();
37+
String json = aposToQuotes("{'data':{'1st':'onedata','2nd':'twodata'}}");
38+
39+
// Do deserialization with non-annotated map property
40+
NonAnnotatedMapHolderClass ignored = mapper.readValue(json, NonAnnotatedMapHolderClass.class);
41+
assertTrue(ignored.data.containsKey("1st"));
42+
assertTrue(ignored.data.containsKey("2nd"));
43+
44+
//mapper = new ObjectMapper();
45+
46+
MapHolder model2 = mapper.readValue(json, MapHolder.class);
47+
if (!model2.data.containsKey("1st (CUSTOM)")
48+
|| !model2.data.containsKey("2nd (CUSTOM)")) {
49+
fail("Not using custom key deserializer for input: "+json+"; resulted in: "+model2.data);
50+
}
51+
}
52+
}

0 commit comments

Comments
 (0)