Skip to content

Commit

Permalink
Fix #1932
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Mar 6, 2018
1 parent 13a7490 commit bfb2f99
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 15 deletions.
1 change: 1 addition & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Project: jackson-databind
(contributed by Deblock T)
#1931: Two more `c3p0` gadgets to exploit default typing issue
(reported by [email protected])
#1932: `EnumMap` cannot deserialize with type inclusion as property
#1940: `Float` values with integer value beyond `int` lose precision if
bound to `long`
(reported by Aniruddha M)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt)
}
// Ok: must point to START_OBJECT
JsonToken t = p.getCurrentToken();
if (t != JsonToken.START_OBJECT && t != JsonToken.FIELD_NAME && t != JsonToken.END_OBJECT) {
if ((t != JsonToken.START_OBJECT) && (t != JsonToken.FIELD_NAME) && (t != JsonToken.END_OBJECT)) {
// (empty) String may be ok however; or single-String-arg ctor
if (t == JsonToken.VALUE_STRING) {
return (EnumMap<?,?>) _valueInstantiator.createFromString(ctxt, p.getText());
Expand All @@ -258,25 +258,37 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt,

final JsonDeserializer<Object> valueDes = _valueDeserializer;
final TypeDeserializer typeDeser = _valueTypeDeserializer;
String keyName;

while ((keyName = p.nextFieldName()) != null) {
String keyStr;
if (p.isExpectedStartObjectToken()) {
keyStr = p.nextFieldName();
} else {
JsonToken t = p.getCurrentToken();
if (t != JsonToken.FIELD_NAME) {
if (t == JsonToken.END_OBJECT) {
return result;
}
ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null);
}
keyStr = p.getCurrentName();
}

for (; keyStr != null; keyStr = p.nextFieldName()) {
// but we need to let key deserializer handle it separately, nonetheless
Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyName, ctxt);
Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyStr, ctxt);
JsonToken t = p.nextToken();
if (key == null) {
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
return (EnumMap<?,?>) ctxt.handleWeirdStringValue(_enumClass, keyName,
return (EnumMap<?,?>) ctxt.handleWeirdStringValue(_enumClass, keyStr,
"value not one of declared Enum instance names for %s",
_containerType.getKeyType());
}
// 24-Mar-2012, tatu: Null won't work as a key anyway, so let's
// just skip the entry then. But we must skip the value as well, if so.
p.nextToken();
p.skipChildren();
continue;
}
// And then the value...
JsonToken t = p.nextToken();
// note: MUST check for nulls separately: deserializers will
// not handle them (and maybe fail or return bogus data)
Object value;
Expand All @@ -293,7 +305,7 @@ public EnumMap<?,?> deserialize(JsonParser p, DeserializationContext ctxt,
value = valueDes.deserializeWithType(p, ctxt, typeDeser);
}
} catch (Exception e) {
return wrapAndThrow(e, result, keyName);
return wrapAndThrow(e, result, keyStr);
}
result.put(key, value);
}
Expand Down Expand Up @@ -347,6 +359,7 @@ public EnumMap<?,?> _deserializeUsingProperties(JsonParser p, DeserializationCon
if (prop != null) {
// Last property to set?
if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) {
p.nextToken(); // from value to END_OBJECT or FIELD_NAME
EnumMap<?,?> result;
try {
result = (EnumMap<?,?>)creator.build(ctxt, buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,10 +436,10 @@ protected final void _readAndBind(JsonParser p, DeserializationContext ctxt,
keyStr = p.nextFieldName();
} else {
JsonToken t = p.getCurrentToken();
if (t == JsonToken.END_OBJECT) {
return;
}
if (t != JsonToken.FIELD_NAME) {
if (t == JsonToken.END_OBJECT) {
return;
}
ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null);
}
keyStr = p.getCurrentName();
Expand Down Expand Up @@ -572,7 +572,7 @@ public Map<Object,Object> _deserializeUsingCreator(JsonParser p, Deserialization
if (prop != null) {
// Last property to set?
if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) {
p.nextToken();
p.nextToken(); // from value to END_OBJECT or FIELD_NAME
Map<Object,Object> result;
try {
result = (Map<Object,Object>)creator.build(ctxt, buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import java.util.EnumMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.*;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;

Expand Down Expand Up @@ -61,6 +60,21 @@ public FromPropertiesEnumMap(@JsonProperty("a") int a,
}
}

// [databind#1859]
public enum Enum1859 {
A, B, C;
}

static class Pojo1859
{
public EnumMap<Enum1859, String> values;

public Pojo1859() { }
public Pojo1859(EnumMap<Enum1859, String> v) {
values = v;
}
}

/*
/**********************************************************
/* Test methods, basic
Expand Down Expand Up @@ -129,6 +143,38 @@ public void testCustomEnumMapFromProps() throws Exception
assertEquals(2, map.size());
}

/*
/**********************************************************
/* Test methods: polymorphic
/**********************************************************
*/

// [databind#1859]
public void testEnumMapAsPolymorphic() throws Exception
{
EnumMap<Enum1859, String> enumMap = new EnumMap<>(Enum1859.class);
enumMap.put(Enum1859.A, "Test");
enumMap.put(Enum1859.B, "stuff");
Pojo1859 input = new Pojo1859(enumMap);

ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.NON_FINAL, "@type");

// 05-Mar-2018, tatu: Original issue had this; should not make difference:
/*
TypeResolverBuilder<?> mapTyperAsPropertyType = new ObjectMapper.DefaultTypeResolverBuilder(ObjectMapper.DefaultTyping.NON_FINAL);
mapTyperAsPropertyType.init(JsonTypeInfo.Id.CLASS, null);
mapTyperAsPropertyType.inclusion(JsonTypeInfo.As.PROPERTY);
mapper.setDefaultTyping(mapTyperAsPropertyType);
*/

String json = mapper.writeValueAsString(input);
Pojo1859 result = mapper.readValue(json, Pojo1859.class);
assertNotNull(result);
assertNotNull(result.values);
assertEquals(2, result.values.size());
}

/*
/**********************************************************
/* Test methods: handling of invalid values
Expand Down

0 comments on commit bfb2f99

Please sign in to comment.