• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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