package com.fasterxml.jackson.databind.util; import java.util.*; import com.fasterxml.jackson.core.SerializableString; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.cfg.MapperConfig; /** * Helper class used for storing String serializations of {@code Enum}s, * to match to/from external representations. */ public final class EnumValues implements java.io.Serializable { private static final long serialVersionUID = 1; private final Class> _enumClass; private final Enum[] _values; private final SerializableString[] _textual; private transient EnumMap _asMap; private EnumValues(Class> enumClass, SerializableString[] textual) { _enumClass = enumClass; _values = enumClass.getEnumConstants(); _textual = textual; } /** * NOTE: do NOT call this if configuration may change, and choice between toString() * and name() might change dynamically. */ public static EnumValues construct(SerializationConfig config, Class> enumClass) { if (config.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { return constructFromToString(config, enumClass); } return constructFromName(config, enumClass); } public static EnumValues constructFromName(MapperConfig config, Class> enumClass) { // Enum types with per-instance sub-classes need special handling Class> enumCls = ClassUtil.findEnumType(enumClass); Enum[] enumValues = enumCls.getEnumConstants(); if (enumValues == null) { throw new IllegalArgumentException("Cannot determine enum constants for Class "+enumClass.getName()); } String[] names = config.getAnnotationIntrospector().findEnumValues(enumCls, enumValues, new String[enumValues.length]); SerializableString[] textual = new SerializableString[enumValues.length]; for (int i = 0, len = enumValues.length; i < len; ++i) { Enum en = enumValues[i]; String name = names[i]; if (name == null) { name = en.name(); } textual[en.ordinal()] = config.compileString(name); } return construct(enumClass, textual); } public static EnumValues constructFromToString(MapperConfig config, Class> enumClass) { Class> cls = ClassUtil.findEnumType(enumClass); Enum[] values = cls.getEnumConstants(); if (values == null) { // can this ever occur? throw new IllegalArgumentException("Cannot determine enum constants for Class "+enumClass.getName()); } ArrayList external = new ArrayList<>(values.length); for (Enum en : values) { external.add(en.toString()); } return construct(config, enumClass, external); } /** * @since 2.11 */ public static EnumValues construct(MapperConfig config, Class> enumClass, List externalValues) { final int len = externalValues.size(); SerializableString[] textual = new SerializableString[len]; for (int i = 0; i < len; ++i) { textual[i] = config.compileString(externalValues.get(i)); } return construct(enumClass, textual); } /** * @since 2.11 */ public static EnumValues construct(Class> enumClass, SerializableString[] externalValues) { return new EnumValues(enumClass, externalValues); } public SerializableString serializedValueFor(Enum key) { return _textual[key.ordinal()]; } public Collection values() { return Arrays.asList(_textual); } /** * Convenience accessor for getting raw Enum instances. * * @since 2.6 */ public List> enums() { return Arrays.asList(_values); } /** * Method used for serialization and introspection by core Jackson code. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public EnumMap internalMap() { EnumMap result = _asMap; if (result == null) { // Alas, need to create it in a round-about way, due to typing constraints... Map,SerializableString> map = new LinkedHashMap,SerializableString>(); for (Enum en : _values) { map.put(en, _textual[en.ordinal()]); } result = new EnumMap(map); } return result; } /** * @since 2.2 */ public Class> getEnumClass() { return _enumClass; } }