1 package com.fasterxml.jackson.databind.ser; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.JsonAnyGetter; 7 import com.fasterxml.jackson.annotation.JsonValue; 8 9 import com.fasterxml.jackson.core.JsonGenerator; 10 11 import com.fasterxml.jackson.databind.*; 12 import com.fasterxml.jackson.databind.annotation.JsonSerialize; 13 14 public class EnumAsMapKeyTest extends BaseMapTest 15 { 16 static class MapBean { 17 public Map<ABCEnum,Integer> map = new HashMap<>(); 18 add(ABCEnum key, int value)19 public void add(ABCEnum key, int value) { 20 map.put(key, Integer.valueOf(value)); 21 } 22 } 23 24 protected enum ABCEnum { 25 A, B, C; ABCEnum()26 private ABCEnum() { } 27 toString()28 @Override public String toString() { return name().toLowerCase(); } 29 } 30 31 // [databind#594] 32 static enum MyEnum594 { 33 VALUE_WITH_A_REALLY_LONG_NAME_HERE("longValue"); 34 35 private final String key; MyEnum594(String k)36 private MyEnum594(String k) { key = k; } 37 38 @JsonValue getKey()39 public String getKey() { return key; } 40 } 41 42 static class MyStuff594 { 43 public Map<MyEnum594,String> stuff = new EnumMap<MyEnum594,String>(MyEnum594.class); 44 MyStuff594(String value)45 public MyStuff594(String value) { 46 stuff.put(MyEnum594.VALUE_WITH_A_REALLY_LONG_NAME_HERE, value); 47 } 48 } 49 50 // [databind#661] 51 static class MyBean661 { 52 private Map<Foo661, String> foo = new EnumMap<Foo661, String>(Foo661.class); 53 MyBean661(String value)54 public MyBean661(String value) { 55 foo.put(Foo661.FOO, value); 56 } 57 58 @JsonAnyGetter 59 @JsonSerialize(keyUsing = Foo661.Serializer.class) getFoo()60 public Map<Foo661, String> getFoo() { 61 return foo; 62 } 63 } 64 65 enum Foo661 { 66 FOO; 67 public static class Serializer extends JsonSerializer<Foo661> { 68 @Override serialize(Foo661 value, JsonGenerator jgen, SerializerProvider provider)69 public void serialize(Foo661 value, JsonGenerator jgen, SerializerProvider provider) 70 throws IOException { 71 jgen.writeFieldName("X-"+value.name()); 72 } 73 } 74 } 75 76 // [databind#2129] 77 public enum Type { 78 FIRST, 79 SECOND; 80 } 81 82 static class TypeContainer { 83 public Map<Type, Integer> values; 84 TypeContainer(Type type, int value)85 public TypeContainer(Type type, int value) { 86 values = Collections.singletonMap(type, value); 87 } 88 } 89 90 /* 91 /********************************************************************** 92 /* Test methods 93 /********************************************************************** 94 */ 95 96 private final ObjectMapper MAPPER = newJsonMapper(); 97 testMapWithEnumKeys()98 public void testMapWithEnumKeys() throws Exception 99 { 100 MapBean bean = new MapBean(); 101 bean.add(ABCEnum.B, 3); 102 103 // By default Enums serialized using `name()` 104 String json = MAPPER.writeValueAsString(bean); 105 assertEquals("{\"map\":{\"B\":3}}", json); 106 107 // but can change 108 json = MAPPER.writer() 109 .with(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) 110 .writeValueAsString(bean); 111 assertEquals("{\"map\":{\"b\":3}}", json); 112 113 // [databind#1570] 114 115 // 14-Sep-2019, tatu: as per [databind#2129], must NOT use this feature but 116 // instead new `WRITE_ENUM_KEYS_USING_INDEX` added in 2.10 117 json = MAPPER.writer() 118 .with(SerializationFeature.WRITE_ENUMS_USING_INDEX) 119 .writeValueAsString(bean); 120 // assertEquals(aposToQuotes("{'map':{'"+TestEnum.B.ordinal()+"':3}}"), json); 121 assertEquals(aposToQuotes("{'map':{'B':3}}"), json); 122 } 123 testCustomEnumMapKeySerializer()124 public void testCustomEnumMapKeySerializer() throws Exception { 125 String json = MAPPER.writeValueAsString(new MyBean661("abc")); 126 assertEquals(aposToQuotes("{'X-FOO':'abc'}"), json); 127 } 128 129 // [databind#594] testJsonValueForEnumMapKey()130 public void testJsonValueForEnumMapKey() throws Exception { 131 assertEquals(aposToQuotes("{'stuff':{'longValue':'foo'}}"), 132 MAPPER.writeValueAsString(new MyStuff594("foo"))); 133 } 134 135 // [databind#2129] testEnumAsIndexForRootMap()136 public void testEnumAsIndexForRootMap() throws Exception 137 { 138 final Map<Type, Integer> input = Collections.singletonMap(Type.FIRST, 3); 139 140 // by default, write using name() 141 assertEquals(aposToQuotes("{'FIRST':3}"), 142 MAPPER.writeValueAsString(input)); 143 144 // but change with setting 145 assertEquals(aposToQuotes("{'0':3}"), 146 MAPPER.writer() 147 .with(SerializationFeature.WRITE_ENUM_KEYS_USING_INDEX) 148 .writeValueAsString(input)); 149 150 // but NOT with value settings 151 assertEquals(aposToQuotes("{'FIRST':3}"), 152 MAPPER.writer() 153 .with(SerializationFeature.WRITE_ENUMS_USING_INDEX) 154 .writeValueAsString(input)); 155 } 156 157 // [databind#2129] testEnumAsIndexForValueMap()158 public void testEnumAsIndexForValueMap() throws Exception 159 { 160 final TypeContainer input = new TypeContainer(Type.SECOND, 72); 161 162 // by default, write using name() 163 assertEquals(aposToQuotes("{'values':{'SECOND':72}}"), 164 MAPPER.writeValueAsString(input)); 165 166 // but change with setting 167 assertEquals(aposToQuotes("{'values':{'1':72}}"), 168 MAPPER.writer() 169 .with(SerializationFeature.WRITE_ENUM_KEYS_USING_INDEX) 170 .writeValueAsString(input)); 171 172 // but NOT with value settings 173 assertEquals(aposToQuotes("{'values':{'SECOND':72}}"), 174 MAPPER.writer() 175 .with(SerializationFeature.WRITE_ENUMS_USING_INDEX) 176 .writeValueAsString(input)); 177 } 178 } 179