| package com.fasterxml.jackson.databind.deser.jdk; |
| |
| import java.util.EnumMap; |
| import java.util.Map; |
| |
| import com.fasterxml.jackson.annotation.*; |
| |
| import com.fasterxml.jackson.core.type.TypeReference; |
| import com.fasterxml.jackson.databind.*; |
| |
| @SuppressWarnings("serial") |
| public class EnumMapDeserializationTest extends BaseMapTest |
| { |
| enum TestEnum { JACKSON, RULES, OK; } |
| |
| enum TestEnumWithDefault { |
| JACKSON, RULES, |
| @JsonEnumDefaultValue |
| OK; |
| } |
| |
| protected enum LowerCaseEnum { |
| A, B, C; |
| private LowerCaseEnum() { } |
| @Override |
| public String toString() { return name().toLowerCase(); } |
| } |
| |
| static class MySimpleEnumMap extends EnumMap<TestEnum,String> { |
| public MySimpleEnumMap() { |
| super(TestEnum.class); |
| } |
| } |
| |
| static class FromStringEnumMap extends EnumMap<TestEnum,String> { |
| @JsonCreator |
| public FromStringEnumMap(String value) { |
| super(TestEnum.class); |
| put(TestEnum.JACKSON, value); |
| } |
| } |
| |
| static class FromDelegateEnumMap extends EnumMap<TestEnum,String> { |
| @JsonCreator |
| public FromDelegateEnumMap(Map<Object,Object> stuff) { |
| super(TestEnum.class); |
| put(TestEnum.OK, String.valueOf(stuff)); |
| } |
| } |
| |
| static class FromPropertiesEnumMap extends EnumMap<TestEnum,String> { |
| int a0, b0; |
| |
| @JsonCreator |
| public FromPropertiesEnumMap(@JsonProperty("a") int a, |
| @JsonProperty("b") int b) { |
| super(TestEnum.class); |
| a0 = a; |
| b0 = b; |
| } |
| } |
| |
| // [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 |
| /********************************************************** |
| */ |
| |
| protected final ObjectMapper MAPPER = new ObjectMapper(); |
| |
| public void testEnumMaps() throws Exception |
| { |
| EnumMap<TestEnum,String> value = MAPPER.readValue("{\"OK\":\"value\"}", |
| new TypeReference<EnumMap<TestEnum,String>>() { }); |
| assertEquals("value", value.get(TestEnum.OK)); |
| } |
| |
| public void testToStringEnumMaps() throws Exception |
| { |
| // can't reuse global one due to reconfig |
| ObjectReader r = MAPPER.reader() |
| .with(DeserializationFeature.READ_ENUMS_USING_TO_STRING); |
| EnumMap<LowerCaseEnum,String> value = r.forType( |
| new TypeReference<EnumMap<LowerCaseEnum,String>>() { }) |
| .readValue("{\"a\":\"value\"}"); |
| assertEquals("value", value.get(LowerCaseEnum.A)); |
| } |
| |
| /* |
| /********************************************************** |
| /* Test methods: custom enum maps |
| /********************************************************** |
| */ |
| |
| public void testCustomEnumMapWithDefaultCtor() throws Exception |
| { |
| MySimpleEnumMap map = MAPPER.readValue(aposToQuotes("{'RULES':'waves'}"), |
| MySimpleEnumMap.class); |
| assertEquals(1, map.size()); |
| assertEquals("waves", map.get(TestEnum.RULES)); |
| } |
| |
| public void testCustomEnumMapFromString() throws Exception |
| { |
| FromStringEnumMap map = MAPPER.readValue(quote("kewl"), FromStringEnumMap.class); |
| assertEquals(1, map.size()); |
| assertEquals("kewl", map.get(TestEnum.JACKSON)); |
| } |
| |
| public void testCustomEnumMapWithDelegate() throws Exception |
| { |
| FromDelegateEnumMap map = MAPPER.readValue(aposToQuotes("{'foo':'bar'}"), FromDelegateEnumMap.class); |
| assertEquals(1, map.size()); |
| assertEquals("{foo=bar}", map.get(TestEnum.OK)); |
| } |
| |
| public void testCustomEnumMapFromProps() throws Exception |
| { |
| FromPropertiesEnumMap map = MAPPER.readValue(aposToQuotes( |
| "{'a':13,'RULES':'jackson','b':-731,'OK':'yes'}"), |
| FromPropertiesEnumMap.class); |
| |
| assertEquals(13, map.a0); |
| assertEquals(-731, map.b0); |
| |
| assertEquals("jackson", map.get(TestEnum.RULES)); |
| assertEquals("yes", map.get(TestEnum.OK)); |
| 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 |
| /********************************************************** |
| */ |
| |
| // [databind#1859] |
| public void testUnknownKeyAsDefault() throws Exception |
| { |
| // first, via EnumMap |
| EnumMap<TestEnumWithDefault,String> value = MAPPER |
| .readerFor(new TypeReference<EnumMap<TestEnumWithDefault,String>>() { }) |
| .with(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE) |
| .readValue("{\"unknown\":\"value\"}"); |
| assertEquals(1, value.size()); |
| assertEquals("value", value.get(TestEnumWithDefault.OK)); |
| |
| Map<TestEnumWithDefault,String> value2 = MAPPER |
| .readerFor(new TypeReference<Map<TestEnumWithDefault,String>>() { }) |
| .with(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE) |
| .readValue("{\"unknown\":\"value\"}"); |
| assertEquals(1, value2.size()); |
| assertEquals("value", value2.get(TestEnumWithDefault.OK)); |
| } |
| |
| // [databind#1859] |
| public void testUnknownKeyAsNull() throws Exception |
| { |
| // first, via EnumMap |
| EnumMap<TestEnumWithDefault,String> value = MAPPER |
| .readerFor(new TypeReference<EnumMap<TestEnumWithDefault,String>>() { }) |
| .with(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL) |
| .readValue("{\"unknown\":\"value\"}"); |
| assertEquals(0, value.size()); |
| |
| // then regular Map |
| Map<TestEnumWithDefault,String> value2 = MAPPER |
| .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)); |
| } |
| } |