Skip to content

Commit 838ae27

Browse files
committed
Merge branch '2.9'
2 parents 692f20e + bfb2f99 commit 838ae27

File tree

4 files changed

+75
-15
lines changed

4 files changed

+75
-15
lines changed

release-notes/VERSION-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Project: jackson-databind
1414
(contributed by Deblock T)
1515
#1931: Two more `c3p0` gadgets to exploit default typing issue
1616
(reported by lilei@venusgroup.com.cn)
17+
#1932: `EnumMap` cannot deserialize with type inclusion as property
1718
#1940: `Float` values with integer value beyond `int` lose precision if
1819
bound to `long`
1920
(reported by Aniruddha M)

src/main/java/com/fasterxml/jackson/databind/deser/std/EnumMapDeserializer.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt)
221221
}
222222
// Ok: must point to START_OBJECT
223223
JsonToken t = p.currentToken();
224-
if (t != JsonToken.START_OBJECT && t != JsonToken.FIELD_NAME && t != JsonToken.END_OBJECT) {
224+
if ((t != JsonToken.START_OBJECT) && (t != JsonToken.FIELD_NAME) && (t != JsonToken.END_OBJECT)) {
225225
// (empty) String may be ok however; or single-String-arg ctor
226226
if (t == JsonToken.VALUE_STRING) {
227227
return (EnumMap<?,?>) _valueInstantiator.createFromString(ctxt, p.getText());
@@ -243,25 +243,37 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt,
243243

244244
final JsonDeserializer<Object> valueDes = _valueDeserializer;
245245
final TypeDeserializer typeDeser = _valueTypeDeserializer;
246-
String keyName;
247246

248-
while ((keyName = p.nextFieldName()) != null) {
247+
String keyStr;
248+
if (p.isExpectedStartObjectToken()) {
249+
keyStr = p.nextFieldName();
250+
} else {
251+
JsonToken t = p.currentToken();
252+
if (t != JsonToken.FIELD_NAME) {
253+
if (t == JsonToken.END_OBJECT) {
254+
return result;
255+
}
256+
ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null);
257+
}
258+
keyStr = p.currentName();
259+
}
260+
261+
for (; keyStr != null; keyStr = p.nextFieldName()) {
249262
// but we need to let key deserializer handle it separately, nonetheless
250-
Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyName, ctxt);
263+
Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyStr, ctxt);
264+
JsonToken t = p.nextToken();
251265
if (key == null) {
252266
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
253-
return (EnumMap<?,?>) ctxt.handleWeirdStringValue(_enumClass, keyName,
267+
return (EnumMap<?,?>) ctxt.handleWeirdStringValue(_enumClass, keyStr,
254268
"value not one of declared Enum instance names for %s",
255269
_containerType.getKeyType());
256270
}
257271
// 24-Mar-2012, tatu: Null won't work as a key anyway, so let's
258272
// just skip the entry then. But we must skip the value as well, if so.
259-
p.nextToken();
260273
p.skipChildren();
261274
continue;
262275
}
263276
// And then the value...
264-
JsonToken t = p.nextToken();
265277
// note: MUST check for nulls separately: deserializers will
266278
// not handle them (and maybe fail or return bogus data)
267279
Object value;
@@ -278,7 +290,7 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt,
278290
value = valueDes.deserializeWithType(p, ctxt, typeDeser);
279291
}
280292
} catch (Exception e) {
281-
return wrapAndThrow(e, result, keyName);
293+
return wrapAndThrow(e, result, keyStr);
282294
}
283295
result.put(key, value);
284296
}
@@ -332,6 +344,7 @@ public EnumMap<?,?> _deserializeUsingProperties(JsonParser p, DeserializationCon
332344
if (prop != null) {
333345
// Last property to set?
334346
if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) {
347+
p.nextToken(); // from value to END_OBJECT or FIELD_NAME
335348
EnumMap<?,?> result;
336349
try {
337350
result = (EnumMap<?,?>)creator.build(ctxt, buffer);

src/main/java/com/fasterxml/jackson/databind/deser/std/MapDeserializer.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,10 @@ protected final void _readAndBind(JsonParser p, DeserializationContext ctxt,
435435
keyStr = p.nextFieldName();
436436
} else {
437437
JsonToken t = p.currentToken();
438-
if (t == JsonToken.END_OBJECT) {
439-
return;
440-
}
441438
if (t != JsonToken.FIELD_NAME) {
439+
if (t == JsonToken.END_OBJECT) {
440+
return;
441+
}
442442
ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null);
443443
}
444444
keyStr = p.currentName();
@@ -571,7 +571,7 @@ public Map<Object,Object> _deserializeUsingCreator(JsonParser p, Deserialization
571571
if (prop != null) {
572572
// Last property to set?
573573
if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) {
574-
p.nextToken();
574+
p.nextToken(); // from value to END_OBJECT or FIELD_NAME
575575
Map<Object,Object> result;
576576
try {
577577
result = (Map<Object,Object>)creator.build(ctxt, buffer);

src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumMapDeserializationTest.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
import java.util.EnumMap;
44
import java.util.Map;
55

6-
import com.fasterxml.jackson.annotation.JsonCreator;
7-
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
8-
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import com.fasterxml.jackson.annotation.*;
7+
98
import com.fasterxml.jackson.core.type.TypeReference;
109
import com.fasterxml.jackson.databind.*;
1110

@@ -61,6 +60,21 @@ public FromPropertiesEnumMap(@JsonProperty("a") int a,
6160
}
6261
}
6362

63+
// [databind#1859]
64+
public enum Enum1859 {
65+
A, B, C;
66+
}
67+
68+
static class Pojo1859
69+
{
70+
public EnumMap<Enum1859, String> values;
71+
72+
public Pojo1859() { }
73+
public Pojo1859(EnumMap<Enum1859, String> v) {
74+
values = v;
75+
}
76+
}
77+
6478
/*
6579
/**********************************************************
6680
/* Test methods, basic
@@ -129,6 +143,38 @@ public void testCustomEnumMapFromProps() throws Exception
129143
assertEquals(2, map.size());
130144
}
131145

146+
/*
147+
/**********************************************************
148+
/* Test methods: polymorphic
149+
/**********************************************************
150+
*/
151+
152+
// [databind#1859]
153+
public void testEnumMapAsPolymorphic() throws Exception
154+
{
155+
EnumMap<Enum1859, String> enumMap = new EnumMap<>(Enum1859.class);
156+
enumMap.put(Enum1859.A, "Test");
157+
enumMap.put(Enum1859.B, "stuff");
158+
Pojo1859 input = new Pojo1859(enumMap);
159+
160+
ObjectMapper mapper = new ObjectMapper();
161+
mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.NON_FINAL, "@type");
162+
163+
// 05-Mar-2018, tatu: Original issue had this; should not make difference:
164+
/*
165+
TypeResolverBuilder<?> mapTyperAsPropertyType = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.NON_FINAL);
166+
mapTyperAsPropertyType.init(JsonTypeInfo.Id.CLASS, null);
167+
mapTyperAsPropertyType.inclusion(JsonTypeInfo.As.PROPERTY);
168+
mapper.setDefaultTyping(mapTyperAsPropertyType);
169+
*/
170+
171+
String json = mapper.writeValueAsString(input);
172+
Pojo1859 result = mapper.readValue(json, Pojo1859.class);
173+
assertNotNull(result);
174+
assertNotNull(result.values);
175+
assertEquals(2, result.values.size());
176+
}
177+
132178
/*
133179
/**********************************************************
134180
/* Test methods: handling of invalid values

0 commit comments

Comments
 (0)