1 package com.fasterxml.jackson.databind.util; 2 3 import java.util.*; 4 5 import com.fasterxml.jackson.core.SerializableString; 6 import com.fasterxml.jackson.databind.*; 7 import com.fasterxml.jackson.databind.cfg.MapperConfig; 8 9 /** 10 * Helper class used for storing String serializations of {@code Enum}s, 11 * to match to/from external representations. 12 */ 13 public final class EnumValues 14 implements java.io.Serializable 15 { 16 private static final long serialVersionUID = 1; 17 18 private final Class<Enum<?>> _enumClass; 19 20 private final Enum<?>[] _values; 21 private final SerializableString[] _textual; 22 23 private transient EnumMap<?,SerializableString> _asMap; 24 EnumValues(Class<Enum<?>> enumClass, SerializableString[] textual)25 private EnumValues(Class<Enum<?>> enumClass, SerializableString[] textual) 26 { 27 _enumClass = enumClass; 28 _values = enumClass.getEnumConstants(); 29 _textual = textual; 30 } 31 32 /** 33 * NOTE: do NOT call this if configuration may change, and choice between toString() 34 * and name() might change dynamically. 35 */ construct(SerializationConfig config, Class<Enum<?>> enumClass)36 public static EnumValues construct(SerializationConfig config, Class<Enum<?>> enumClass) { 37 if (config.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { 38 return constructFromToString(config, enumClass); 39 } 40 return constructFromName(config, enumClass); 41 } 42 constructFromName(MapperConfig<?> config, Class<Enum<?>> enumClass)43 public static EnumValues constructFromName(MapperConfig<?> config, Class<Enum<?>> enumClass) 44 { 45 // Enum types with per-instance sub-classes need special handling 46 Class<? extends Enum<?>> enumCls = ClassUtil.findEnumType(enumClass); 47 Enum<?>[] enumValues = enumCls.getEnumConstants(); 48 if (enumValues == null) { 49 throw new IllegalArgumentException("Cannot determine enum constants for Class "+enumClass.getName()); 50 } 51 String[] names = config.getAnnotationIntrospector().findEnumValues(enumCls, enumValues, new String[enumValues.length]); 52 SerializableString[] textual = new SerializableString[enumValues.length]; 53 for (int i = 0, len = enumValues.length; i < len; ++i) { 54 Enum<?> en = enumValues[i]; 55 String name = names[i]; 56 if (name == null) { 57 name = en.name(); 58 } 59 textual[en.ordinal()] = config.compileString(name); 60 } 61 return construct(enumClass, textual); 62 } 63 constructFromToString(MapperConfig<?> config, Class<Enum<?>> enumClass)64 public static EnumValues constructFromToString(MapperConfig<?> config, Class<Enum<?>> enumClass) 65 { 66 Class<? extends Enum<?>> cls = ClassUtil.findEnumType(enumClass); 67 Enum<?>[] values = cls.getEnumConstants(); 68 if (values == null) { // can this ever occur? 69 throw new IllegalArgumentException("Cannot determine enum constants for Class "+enumClass.getName()); 70 } 71 ArrayList<String> external = new ArrayList<>(values.length); 72 for (Enum<?> en : values) { 73 external.add(en.toString()); 74 } 75 return construct(config, enumClass, external); 76 } 77 78 /** 79 * @since 2.11 80 */ construct(MapperConfig<?> config, Class<Enum<?>> enumClass, List<String> externalValues)81 public static EnumValues construct(MapperConfig<?> config, Class<Enum<?>> enumClass, 82 List<String> externalValues) { 83 final int len = externalValues.size(); 84 SerializableString[] textual = new SerializableString[len]; 85 for (int i = 0; i < len; ++i) { 86 textual[i] = config.compileString(externalValues.get(i)); 87 } 88 return construct(enumClass, textual); 89 } 90 91 /** 92 * @since 2.11 93 */ construct(Class<Enum<?>> enumClass, SerializableString[] externalValues)94 public static EnumValues construct(Class<Enum<?>> enumClass, 95 SerializableString[] externalValues) { 96 return new EnumValues(enumClass, externalValues); 97 } 98 serializedValueFor(Enum<?> key)99 public SerializableString serializedValueFor(Enum<?> key) { 100 return _textual[key.ordinal()]; 101 } 102 values()103 public Collection<SerializableString> values() { 104 return Arrays.asList(_textual); 105 } 106 107 /** 108 * Convenience accessor for getting raw Enum instances. 109 * 110 * @since 2.6 111 */ enums()112 public List<Enum<?>> enums() { 113 return Arrays.asList(_values); 114 } 115 116 /** 117 * Method used for serialization and introspection by core Jackson code. 118 */ 119 @SuppressWarnings({ "unchecked", "rawtypes" }) internalMap()120 public EnumMap<?,SerializableString> internalMap() { 121 EnumMap<?,SerializableString> result = _asMap; 122 if (result == null) { 123 // Alas, need to create it in a round-about way, due to typing constraints... 124 Map<Enum<?>,SerializableString> map = new LinkedHashMap<Enum<?>,SerializableString>(); 125 for (Enum<?> en : _values) { 126 map.put(en, _textual[en.ordinal()]); 127 } 128 result = new EnumMap(map); 129 } 130 return result; 131 } 132 133 /** 134 * @since 2.2 135 */ getEnumClass()136 public Class<Enum<?>> getEnumClass() { return _enumClass; } 137 } 138