All Downloads are FREE. Search and download functionalities are using the official Maven repository.

spinjar.com.fasterxml.jackson.databind.util.EnumResolver Maven / Gradle / Ivy

There is a newer version: 7.22.0-alpha5
Show newest version
package com.fasterxml.jackson.databind.util;

import java.util.*;

import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.EnumNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;

/**
 * Helper class used to resolve String values (either JSON Object field
 * names or regular String values) into Java Enum instances.
 */
public class EnumResolver implements java.io.Serializable
{
    private static final long serialVersionUID = 1L;

    protected final Class> _enumClass;

    protected final Enum[] _enums;

    protected final HashMap> _enumsById;

    protected final Enum _defaultValue;

    /**
     * Marker for case-insensitive handling
     *
     * @since 2.12
     */
    protected final boolean _isIgnoreCase;

    /**
     * Marker for case where value may come from {@code @JsonValue} annotated
     * accessor and is expected/likely to come from actual integral number
     * value (and not String).
     *

* Special case is needed since this specifically means that {@code Enum.index()} * should NOT be used or default to. * * @since 2.13 */ protected final boolean _isFromIntValue; /* /********************************************************************** /* Constructors (non-deprecated) /********************************************************************** */ /** * @since 2.12 */ protected EnumResolver(Class> enumClass, Enum[] enums, HashMap> map, Enum defaultValue, boolean isIgnoreCase, boolean isFromIntValue) { _enumClass = enumClass; _enums = enums; _enumsById = map; _defaultValue = defaultValue; _isIgnoreCase = isIgnoreCase; _isFromIntValue = isFromIntValue; } /* /********************************************************************** /* Factory methods (non-deprecated) /********************************************************************** */ /** * Factory method for constructing resolver that maps from Enum.name() into * Enum value. * * @since 2.12 */ public static EnumResolver constructFor(DeserializationConfig config, Class enumCls) { return _constructFor(config, enumCls); } /** * @since 2.15 */ protected static EnumResolver _constructFor(DeserializationConfig config, Class enumCls0) { final AnnotationIntrospector ai = config.getAnnotationIntrospector(); final boolean isIgnoreCase = config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); final Class> enumCls = _enumClass(enumCls0); final Enum[] enumConstants = _enumConstants(enumCls0); String[] names = ai.findEnumValues(enumCls, enumConstants, new String[enumConstants.length]); final String[][] allAliases = new String[names.length][]; ai.findEnumAliases(enumCls, enumConstants, allAliases); HashMap> map = new HashMap>(); for (int i = 0, len = enumConstants.length; i < len; ++i) { final Enum enumValue = enumConstants[i]; String name = names[i]; if (name == null) { name = enumValue.name(); } map.put(name, enumValue); String[] aliases = allAliases[i]; if (aliases != null) { for (String alias : aliases) { // Avoid overriding any primary names map.putIfAbsent(alias, enumValue); } } } return new EnumResolver(enumCls, enumConstants, map, _enumDefault(ai, enumCls), isIgnoreCase, false); } /** * Factory method for constructing resolver that maps from Enum.toString() into * Enum value * * @since 2.12 */ public static EnumResolver constructUsingToString(DeserializationConfig config, Class enumCls) { return _constructUsingToString(config, enumCls); } /** * Factory method for constructing resolver that maps from index of Enum.values() into * Enum value * * @since 2.15 */ public static EnumResolver constructUsingIndex(DeserializationConfig config, Class> enumCls) { return _constructUsingIndex(config, enumCls); } private static EnumResolver _constructUsingIndex(DeserializationConfig config, Class> enumCls0) { final AnnotationIntrospector ai = config.getAnnotationIntrospector(); final boolean isIgnoreCase = config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); final Class> enumCls = _enumClass(enumCls0); final Enum[] enumConstants = _enumConstants(enumCls0); HashMap> map = new HashMap<>(); // from last to first, so that in case of duplicate values, first wins for (int i = enumConstants.length; --i >= 0; ) { Enum enumValue = enumConstants[i]; map.put(String.valueOf(i), enumValue); } return new EnumResolver(enumCls, enumConstants, map, _enumDefault(ai, enumCls), isIgnoreCase, false); } /** * Factory method for constructing resolver that maps the name of enums converted to external property * names into Enum value using an implementation of {@link EnumNamingStrategy}. * * The output {@link EnumResolver} should contain values that are symmetric to * {@link EnumValues#constructUsingEnumNamingStrategy(MapperConfig, Class, EnumNamingStrategy)}. * @since 2.15 */ public static EnumResolver constructUsingEnumNamingStrategy(DeserializationConfig config, Class enumCls, EnumNamingStrategy enumNamingStrategy) { return _constructUsingEnumNamingStrategy(config, enumCls, enumNamingStrategy); } /** * Internal method for * {@link EnumResolver#constructUsingEnumNamingStrategy(DeserializationConfig, Class, EnumNamingStrategy)} * * @since 2.15 */ private static EnumResolver _constructUsingEnumNamingStrategy( DeserializationConfig config, Class enumCls0, EnumNamingStrategy enumNamingStrategy) { final AnnotationIntrospector ai = config.getAnnotationIntrospector(); final boolean isIgnoreCase = config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); final Class> enumCls = _enumClass(enumCls0); final Enum[] enumConstants = _enumConstants(enumCls0); HashMap> map = new HashMap<>(); // from last to first, so that in case of duplicate values, first wins for (int i = enumConstants.length; --i >= 0; ) { Enum anEnum = enumConstants[i]; String translatedExternalValue = enumNamingStrategy.convertEnumToExternalName(anEnum.name()); map.put(translatedExternalValue, anEnum); } return new EnumResolver(enumCls, enumConstants, map, _enumDefault(ai, enumCls), isIgnoreCase, false); } /** * @since 2.12 */ protected static EnumResolver _constructUsingToString(DeserializationConfig config, Class enumCls0) { final AnnotationIntrospector ai = config.getAnnotationIntrospector(); final boolean isIgnoreCase = config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); final Class> enumCls = _enumClass(enumCls0); final Enum[] enumConstants = _enumConstants(enumCls0); HashMap> map = new HashMap>(); final String[][] allAliases = new String[enumConstants.length][]; if (ai != null) { ai.findEnumAliases(enumCls, enumConstants, allAliases); } // from last to first, so that in case of duplicate values, first wins for (int i = enumConstants.length; --i >= 0; ) { Enum enumValue = enumConstants[i]; map.put(enumValue.toString(), enumValue); String[] aliases = allAliases[i]; if (aliases != null) { for (String alias : aliases) { // Avoid overriding any primary names map.putIfAbsent(alias, enumValue); } } } return new EnumResolver(enumCls, enumConstants, map, _enumDefault(ai, enumCls), isIgnoreCase, false); } /** * Method used when actual String serialization is indicated using @JsonValue * on a method in Enum class. * * @since 2.12 */ public static EnumResolver constructUsingMethod(DeserializationConfig config, Class enumCls, AnnotatedMember accessor) { return _constructUsingMethod(config, enumCls, accessor); } /** * @since 2.12 */ protected static EnumResolver _constructUsingMethod(DeserializationConfig config, Class enumCls0, AnnotatedMember accessor) { final AnnotationIntrospector ai = config.getAnnotationIntrospector(); final boolean isIgnoreCase = config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); final Class> enumCls = _enumClass(enumCls0); final Enum[] enumConstants = _enumConstants(enumCls0); HashMap> map = new HashMap>(); // from last to first, so that in case of duplicate values, first wins for (int i = enumConstants.length; --i >= 0; ) { Enum en = enumConstants[i]; try { Object o = accessor.getValue(en); if (o != null) { map.put(o.toString(), en); } } catch (Exception e) { throw new IllegalArgumentException("Failed to access @JsonValue of Enum value "+en+": "+e.getMessage()); } } return new EnumResolver(enumCls, enumConstants, map, _enumDefault(ai, enumCls), isIgnoreCase, // 26-Sep-2021, tatu: [databind#1850] Need to consider "from int" case _isIntType(accessor.getRawType()) ); } public CompactStringObjectMap constructLookup() { return CompactStringObjectMap.construct(_enumsById); } @SuppressWarnings("unchecked") protected static Class> _enumClass(Class enumCls0) { return (Class>) enumCls0; } protected static Enum[] _enumConstants(Class enumCls) { final Enum[] enumValues = _enumClass(enumCls).getEnumConstants(); if (enumValues == null) { throw new IllegalArgumentException("No enum constants for class "+enumCls.getName()); } return enumValues; } protected static Enum _enumDefault(AnnotationIntrospector intr, Class enumCls) { return (intr != null) ? intr.findDefaultEnumValue(_enumClass(enumCls)) : null; } protected static boolean _isIntType(Class erasedType) { if (erasedType.isPrimitive()) { erasedType = ClassUtil.wrapperType(erasedType); } return (erasedType == Long.class) || (erasedType == Integer.class) || (erasedType == Short.class) || (erasedType == Byte.class) ; } /* /********************************************************************** /* Deprecated constructors, factory methods /********************************************************************** */ /** * @deprecated Since 2.13 -- remove from 2.16 */ @Deprecated // since 2.13 protected EnumResolver(Class> enumClass, Enum[] enums, HashMap> map, Enum defaultValue, boolean isIgnoreCase) { this(enumClass, enums, map, defaultValue, isIgnoreCase, false); } /* /********************************************************************** /* Public API /********************************************************************** */ public Enum findEnum(final String key) { Enum en = _enumsById.get(key); if (en == null) { if (_isIgnoreCase) { return _findEnumCaseInsensitive(key); } } return en; } // @since 2.12 protected Enum _findEnumCaseInsensitive(final String key) { for (Map.Entry> entry : _enumsById.entrySet()) { if (key.equalsIgnoreCase(entry.getKey())) { return entry.getValue(); } } return null; } public Enum getEnum(int index) { if (index < 0 || index >= _enums.length) { return null; } return _enums[index]; } public Enum getDefaultValue(){ return _defaultValue; } public Enum[] getRawEnums() { return _enums; } public List> getEnums() { ArrayList> enums = new ArrayList>(_enums.length); for (Enum e : _enums) { enums.add(e); } return enums; } /** * @since 2.7.3 */ public Collection getEnumIds() { return _enumsById.keySet(); } public Class> getEnumClass() { return _enumClass; } public int lastValidIndex() { return _enums.length-1; } /** * Accessor for checking if we have a special case in which value to map * is from {@code @JsonValue} annotated accessor with integral type: this * matters for cases where incoming content value is of integral type * and should be mapped to specific value and NOT to {@code Enum.index()}. * * @since 2.13 */ public boolean isFromIntValue() { return _isFromIntValue; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy