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
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      */

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
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
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      */

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      */

94     public static EnumValues construct(Class<Enum<?>> enumClass,
95             SerializableString[] externalValues) {
96         return new EnumValues(enumClass, externalValues);
97     }
98     
99     public SerializableString serializedValueFor(Enum<?> key) {
100         return _textual[key.ordinal()];
101     }
102
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      */

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" })
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      */

136     public Class<Enum<?>> getEnumClass() { return _enumClass; }
137 }
138