From c22be66116cded3dd753127c8a38aa50f0bdd69c Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Thu, 13 Jul 2023 09:48:45 +0900 Subject: [PATCH] Implement new `EnumResolver.constructUsingEnumNamingStrategy()` via `AnnotatedClass` instead of `Class` (#4032) --- .../deser/BasicDeserializerFactory.java | 23 ++++++++- .../jackson/databind/util/EnumResolver.java | 47 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java index a031ed4da9..778b646833 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java @@ -1713,7 +1713,7 @@ public JsonDeserializer createEnumDeserializer(DeserializationContext ctxt, if (deser == null) { deser = new EnumDeserializer(constructEnumResolver(enumClass, config, beanDesc), config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS), - constructEnumNamingStrategyResolver(config, enumClass, beanDesc.getClassInfo()), + constructEnumNamingStrategyResolver(config, beanDesc.getClassInfo()), // since 2.16 EnumResolver.constructUsingToString(config, beanDesc.getClassInfo()) ); @@ -1923,7 +1923,7 @@ private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt, } } EnumResolver enumRes = constructEnumResolver(enumClass, config, beanDesc); - EnumResolver byEnumNamingResolver = constructEnumNamingStrategyResolver(config, enumClass, beanDesc.getClassInfo()); + EnumResolver byEnumNamingResolver = constructEnumNamingStrategyResolver(config, beanDesc.getClassInfo()); EnumResolver byToStringResolver = EnumResolver.constructUsingToString(config, beanDesc.getClassInfo()); // May have @JsonCreator for static factory method @@ -2439,7 +2439,10 @@ protected EnumResolver constructEnumResolver(Class enumClass, * with {@link EnumNamingStrategy} applied for the target class. * * @since 2.15 + * @deprecated Since 2.16. + * Use {@link #constructEnumNamingStrategyResolver(DeserializationConfig, AnnotatedClass)} instead. */ + @Deprecated protected EnumResolver constructEnumNamingStrategyResolver(DeserializationConfig config, Class enumClass, AnnotatedClass annotatedClass) { Object namingDef = config.getAnnotationIntrospector().findEnumNamingStrategy(config, annotatedClass); @@ -2449,6 +2452,22 @@ protected EnumResolver constructEnumNamingStrategyResolver(DeserializationConfig : EnumResolver.constructUsingEnumNamingStrategy(config, enumClass, enumNamingStrategy); } + /** + * Factory method used to resolve an instance of {@link CompactStringObjectMap} + * with {@link EnumNamingStrategy} applied for the target class. + * + * @since 2.16 + */ + protected EnumResolver constructEnumNamingStrategyResolver(DeserializationConfig config, + AnnotatedClass annotatedClass) + { + Object namingDef = config.getAnnotationIntrospector().findEnumNamingStrategy(config, annotatedClass); + EnumNamingStrategy enumNamingStrategy = EnumNamingStrategyFactory.createEnumNamingStrategyInstance( + namingDef, config.canOverrideAccessModifiers()); + return enumNamingStrategy == null ? null + : EnumResolver.constructUsingEnumNamingStrategy(config, annotatedClass, enumNamingStrategy); + } + /** * @since 2.9 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/util/EnumResolver.java b/src/main/java/com/fasterxml/jackson/databind/util/EnumResolver.java index 0569fef860..ba5ae55f70 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/EnumResolver.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/EnumResolver.java @@ -265,7 +265,10 @@ public static EnumResolver constructUsingIndex(DeserializationConfig config, * The output {@link EnumResolver} should contain values that are symmetric to * {@link EnumValues#constructUsingEnumNamingStrategy(MapperConfig, Class, EnumNamingStrategy)}. * @since 2.15 + * @deprecated Since 2.16. Use + * {@link #constructUsingEnumNamingStrategy(DeserializationConfig, AnnotatedClass, EnumNamingStrategy)}. */ + @Deprecated public static EnumResolver constructUsingEnumNamingStrategy(DeserializationConfig config, Class enumCls, EnumNamingStrategy enumNamingStrategy) { return _constructUsingEnumNamingStrategy(config, enumCls, enumNamingStrategy); @@ -276,7 +279,10 @@ public static EnumResolver constructUsingEnumNamingStrategy(DeserializationConfi * {@link EnumResolver#constructUsingEnumNamingStrategy(DeserializationConfig, Class, EnumNamingStrategy)} * * @since 2.15 + * @deprecated Since 2.16. Use + * {@link #_constructUsingEnumNamingStrategy(DeserializationConfig, AnnotatedClass, EnumNamingStrategy)}. */ + @Deprecated private static EnumResolver _constructUsingEnumNamingStrategy( DeserializationConfig config, Class enumCls0, EnumNamingStrategy enumNamingStrategy) { @@ -297,6 +303,47 @@ private static EnumResolver _constructUsingEnumNamingStrategy( _enumDefault(ai, enumCls), isIgnoreCase, false); } + /** + * Factory method for constructing an {@link EnumResolver} with {@link EnumNamingStrategy} applied. + * + * @since 2.16 + */ + public static EnumResolver constructUsingEnumNamingStrategy(DeserializationConfig config, + AnnotatedClass annotatedClass, EnumNamingStrategy enumNamingStrategy) + { + return _constructUsingEnumNamingStrategy(config, annotatedClass, enumNamingStrategy); + } + + /** + * Internal method for + * {@link EnumResolver#constructUsingEnumNamingStrategy(DeserializationConfig, AnnotatedClass, EnumNamingStrategy)} + * + * @since 2.16 + */ + private static EnumResolver _constructUsingEnumNamingStrategy( + DeserializationConfig config, AnnotatedClass annotatedClass, EnumNamingStrategy enumNamingStrategy) + { + // prepare data + final AnnotationIntrospector ai = config.getAnnotationIntrospector(); + final boolean isIgnoreCase = config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS); + final Class enumCls0 = annotatedClass.getRawType(); + final Class> enumCls = _enumClass(enumCls0); + final Enum[] enumConstants = _enumConstants(enumCls0); + final Enum defaultEnum = _enumDefault(ai, annotatedClass, enumConstants); + + // finally build + // from last to first, so that in case of duplicate values, first wins + HashMap> map = new HashMap<>(); + 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, + defaultEnum, isIgnoreCase, false); + } + /** * Method used when actual String serialization is indicated using @JsonValue * on a method in Enum class.