Skip to content

Commit bfb2f99

Browse files
committed
Fix #1932
1 parent 13a7490 commit bfb2f99

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
@@ -236,7 +236,7 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt)
236236
}
237237
// Ok: must point to START_OBJECT
238238
JsonToken t = p.getCurrentToken();
239-
if (t != JsonToken.START_OBJECT && t != JsonToken.FIELD_NAME && t != JsonToken.END_OBJECT) {
239+
if ((t != JsonToken.START_OBJECT) && (t != JsonToken.FIELD_NAME) && (t != JsonToken.END_OBJECT)) {
240240
// (empty) String may be ok however; or single-String-arg ctor
241241
if (t == JsonToken.VALUE_STRING) {
242242
return (EnumMap<?,?>) _valueInstantiator.createFromString(ctxt, p.getText());
@@ -258,25 +258,37 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt,
258258

259259
final JsonDeserializer<Object> valueDes = _valueDeserializer;
260260
final TypeDeserializer typeDeser = _valueTypeDeserializer;
261-
String keyName;
262261

263-
while ((keyName = p.nextFieldName()) != null) {
262+
String keyStr;
263+
if (p.isExpectedStartObjectToken()) {
264+
keyStr = p.nextFieldName();
265+
} else {
266+
JsonToken t = p.getCurrentToken();
267+
if (t != JsonToken.FIELD_NAME) {
268+
if (t == JsonToken.END_OBJECT) {
269+
return result;
270+
}
271+
ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null);
272+
}
273+
keyStr = p.getCurrentName();
274+
}
275+
276+
for (; keyStr != null; keyStr = p.nextFieldName()) {
264277
// but we need to let key deserializer handle it separately, nonetheless
265-
Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyName, ctxt);
278+
Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyStr, ctxt);
279+
JsonToken t = p.nextToken();
266280
if (key == null) {
267281
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
268-
return (EnumMap<?,?>) ctxt.handleWeirdStringValue(_enumClass, keyName,
282+
return (EnumMap<?,?>) ctxt.handleWeirdStringValue(_enumClass, keyStr,
269283
"value not one of declared Enum instance names for %s",
270284
_containerType.getKeyType());
271285
}
272286
// 24-Mar-2012, tatu: Null won't work as a key anyway, so let's
273287
// just skip the entry then. But we must skip the value as well, if so.
274-
p.nextToken();
275288
p.skipChildren();
276289
continue;
277290
}
278291
// And then the value...
279-
JsonToken t = p.nextToken();
280292
// note: MUST check for nulls separately: deserializers will
281293
// not handle them (and maybe fail or return bogus data)
282294
Object value;
@@ -293,7 +305,7 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt,
293305
value = valueDes.deserializeWithType(p, ctxt, typeDeser);
294306
}
295307
} catch (Exception e) {
296-
return wrapAndThrow(e, result, keyName);
308+
return wrapAndThrow(e, result, keyStr);
297309
}
298310
result.put(key, value);
299311
}
@@ -347,6 +359,7 @@ public EnumMap<?,?> _deserializeUsingProperties(JsonParser p, DeserializationCon
347359
if (prop != null) {
348360
// Last property to set?
349361
if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) {
362+
p.nextToken(); // from value to END_OBJECT or FIELD_NAME
350363
EnumMap<?,?> result;
351364
try {
352365
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
@@ -436,10 +436,10 @@ protected final void _readAndBind(JsonParser p, DeserializationContext ctxt,
436436
keyStr = p.nextFieldName();
437437
} else {
438438
JsonToken t = p.getCurrentToken();
439-
if (t == JsonToken.END_OBJECT) {
440-
return;
441-
}
442439
if (t != JsonToken.FIELD_NAME) {
440+
if (t == JsonToken.END_OBJECT) {
441+
return;
442+
}
443443
ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null);
444444
}
445445
keyStr = p.getCurrentName();
@@ -572,7 +572,7 @@ public Map<Object,Object> _deserializeUsingCreator(JsonParser p, Deserialization
572572
if (prop != null) {
573573
// Last property to set?
574574
if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) {
575-
p.nextToken();
575+
p.nextToken(); // from value to END_OBJECT or FIELD_NAME
576576
Map<Object,Object> result;
577577
try {
578578
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)