Skip to content

Commit

Permalink
Fix #1883
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jan 25, 2018
1 parent 276c130 commit 134aa74
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 22 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Versions: 3.x (for earlier see VERSION-2.x)
(reported by timo-schmid@github)
#1789: Add `createGenerator` methods in `ObjectMapper`, `ObjectWriter`
#1790: Add `createParser` methods in `ObjectMapper`, `ObjectReader`
#1883: Add "abstract type mapping" for deserialization from `Map<ENUMTYPE,V>`
into `EnumMap` (and `Set<ENUMTYPE>` to `EnumSet<EnumType>`)
#1888: Merge `ResolvableSerializer` into `JsonSerializer`, `ResolvableDeserializer`
into `JsonDeserializer`
#1889: Merge `ContextualSerializer` into `JsonSerializer`, `ContextualDeserializer`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1361,13 +1361,11 @@ public ObjectMapper enableDefaultTyping(DefaultTyping dti) {
*/
public ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInfo.As includeAs)
{
/* 18-Sep-2014, tatu: Let's add explicit check to ensure no one tries to
* use "As.EXTERNAL_PROPERTY", since that will not work (with 2.5+)
*/
// 18-Sep-2014, tatu: Let's add explicit check to ensure no one tries to
// use "As.EXTERNAL_PROPERTY", since that will not work (with 2.5+)
if (includeAs == JsonTypeInfo.As.EXTERNAL_PROPERTY) {
throw new IllegalArgumentException("Cannot use includeAs of "+includeAs);
}

TypeResolverBuilder<?> typer = new DefaultTypeResolverBuilder(applicability);
// we'll always use full class name, when using defaulting
typer = typer.init(JsonTypeInfo.Id.CLASS, null);
Expand Down Expand Up @@ -1667,7 +1665,7 @@ public DateFormat getDateFormat() {
*
* @param hi Instantiator to use; if null, use the default implementation
*/
public Object setHandlerInstantiator(HandlerInstantiator hi)
public ObjectMapper setHandlerInstantiator(HandlerInstantiator hi)
{
_deserializationConfig = _deserializationConfig.with(hi);
_serializationConfig = _serializationConfig.with(hi);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1206,8 +1206,14 @@ public JsonDeserializer<?> createCollectionDeserializer(DeserializationContext c
if (deser == null) {
Class<?> collectionClass = type.getRawClass();
if (contentDeser == null) { // not defined by annotation
// [databind#1853]: Map `Set<ENUM>` to `EnumSet<ENUM>`
if (contentType.isEnumType() && (collectionClass == Set.class)) {
collectionClass = EnumSet.class;
type = (CollectionType) config.getTypeFactory().constructSpecializedType(type, collectionClass);
}
// One special type: EnumSet:
if (EnumSet.class.isAssignableFrom(collectionClass)) {
// 25-Jan-2018, tatu: shouldn't we pass `contentDeser`?
deser = new EnumSetDeserializer(contentType, null);
}
}
Expand Down Expand Up @@ -1343,6 +1349,12 @@ public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
if (deser == null) {
// Value handling is identical for all, but EnumMap requires special handling for keys
Class<?> mapClass = type.getRawClass();
// [databind#1853]: Map `Map<ENUM,x>` to `EnumMap<ENUM,x>`
if ((mapClass == Map.class) && keyType.isEnumType()) {
mapClass = EnumMap.class;
type = (MapType) config.getTypeFactory().constructSpecializedType(type, mapClass);
// type = (MapType) config.getTypeFactory().constructMapType(mapClass, keyType, contentType);
}
if (EnumMap.class.isAssignableFrom(mapClass)) {
ValueInstantiator inst;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ public class EnumSetDeserializer
* Specific override for this instance (from proper, or global per-type overrides)
* to indicate whether single value may be taken to mean an unwrapped one-element array
* or not. If null, left to global defaults.
*
* @since 2.7
*/
protected final Boolean _unwrapSingle;

Expand All @@ -55,9 +53,6 @@ public EnumSetDeserializer(JavaType enumType, JsonDeserializer<?> deser)
_unwrapSingle = null;
}

/**
* @since 2.7
*/
@SuppressWarnings("unchecked" )
protected EnumSetDeserializer(EnumSetDeserializer base,
JsonDeserializer<?> deser, Boolean unwrapSingle) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,20 +345,21 @@ public void testAllowUnknownEnumValuesReadAsNullWithCreatorMethod() throws Excep

public void testAllowUnknownEnumValuesForEnumSets() throws Exception
{
ObjectReader reader = MAPPER.reader(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
EnumSet<TestEnum> result = reader.forType(new TypeReference<EnumSet<TestEnum>>() { })
EnumSet<TestEnum> result = MAPPER.reader(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
.forType(new TypeReference<EnumSet<TestEnum>>() { })
.readValue("[\"NO-SUCH-VALUE\"]");
assertEquals(0, result.size());
}

public void testAllowUnknownEnumValuesAsMapKeysReadAsNull() throws Exception
{
ObjectReader reader = MAPPER.reader(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
ClassWithEnumMapKey result = reader.forType(ClassWithEnumMapKey.class)
ClassWithEnumMapKey result = MAPPER.reader(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
.forType(ClassWithEnumMapKey.class)
.readValue("{\"map\":{\"NO-SUCH-VALUE\":\"val\"}}");
assertTrue(result.map.containsKey(null));
// 25-Jan-2018, tatu: as per [databind#1883], we upgrade it to `EnumMap`, which won't accept nulls...
assertEquals(0, result.map.size());
}

public void testDoNotAllowUnknownEnumValuesAsMapKeysWhenReadAsNullDisabled() throws Exception
{
assertFalse(MAPPER.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,8 @@ public void testUnknownKeyAsNull() throws Exception
.readerFor(new TypeReference<Map<TestEnumWithDefault,String>>() { })
.with(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
.readValue("{\"unknown\":\"value\"}");
// 04-Jan-2017, tatu: Not sure if this is weird or not, but since `null`s are typically
// ok for "regular" JDK Maps...
assertEquals(1, value2.size());
assertEquals("value", value2.get(null));
// 25-Jan-2018, tatu: as per [databind#1883], we upgrade it to `EnumMap`, which won't accept nulls...
assertEquals(0, value2.size());
assertEquals(EnumMap.class, value2.getClass());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ public void testEnumUsingToString() throws Exception
assertEquals("\"c2\"", sw.toString());
}

// Test [JACKSON-214]
public void testSubclassedEnums() throws Exception
{
assertEquals("\"B\"", MAPPER.writeValueAsString(EnumWithSubClass.B));
Expand Down

0 comments on commit 134aa74

Please sign in to comment.