diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSerializer.java index 6e8e192082..34ea011454 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSerializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSerializer.java @@ -59,6 +59,15 @@ public class EnumSerializer */ protected final EnumValues _valuesByEnumNaming; + /** + * Map that contains pre-resolved values for {@link Enum#toString} to use for serialization, + * while respecting {@link com.fasterxml.jackson.annotation.JsonProperty} + * and {@link com.fasterxml.jackson.databind.cfg.EnumFeature#WRITE_ENUMS_TO_LOWERCASE}. + * + * @since 2.16 + */ + protected final EnumValues _valuesByToString; + /* /********************************************************** /* Construction, initialization @@ -71,6 +80,7 @@ public EnumSerializer(EnumValues v, Boolean serializeAsIndex) _values = v; _serializeAsIndex = serializeAsIndex; _valuesByEnumNaming = null; + _valuesByToString = null; } /** @@ -82,6 +92,20 @@ public EnumSerializer(EnumValues v, Boolean serializeAsIndex, EnumValues valuesB _values = v; _serializeAsIndex = serializeAsIndex; _valuesByEnumNaming = valuesByEnumNaming; + _valuesByToString = null; + } + + /** + * @since 2.16 + */ + public EnumSerializer(EnumValues v, Boolean serializeAsIndex, EnumValues valuesByEnumNaming, + EnumValues valuesByToString) + { + super(v.getEnumClass(), false); + _values = v; + _serializeAsIndex = serializeAsIndex; + _valuesByEnumNaming = valuesByEnumNaming; + _valuesByToString = valuesByToString; } /** @@ -100,8 +124,9 @@ public static EnumSerializer construct(Class enumClass, SerializationConfig c */ EnumValues v = EnumValues.constructFromName(config, beanDesc.getClassInfo()); EnumValues valuesByEnumNaming = constructEnumNamingStrategyValues(config, (Class>) enumClass, beanDesc.getClassInfo()); + EnumValues valuesByToString = EnumValues.constructFromToString(config, beanDesc.getClassInfo()); Boolean serializeAsIndex = _isShapeWrittenUsingIndex(enumClass, format, true, null); - return new EnumSerializer(v, serializeAsIndex, valuesByEnumNaming); + return new EnumSerializer(v, serializeAsIndex, valuesByEnumNaming, valuesByToString); } /** @@ -154,7 +179,7 @@ public final void serialize(Enum en, JsonGenerator gen, SerializerProvider se } // [databind#749]: or via toString()? if (serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { - gen.writeString(en.toString()); + gen.writeString(_valuesByToString.serializedValueFor(en)); return; } gen.writeString(_values.serializedValueFor(en)); @@ -205,8 +230,8 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t // Use toString()? if ((serializers != null) && serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { - for (Enum e : _values.enums()) { - enums.add(e.toString()); + for (SerializableString value : _valuesByToString.values()) { + enums.add(value.getValue()); } } else { // No, serialize using name() or explicit overrides diff --git a/src/main/java/com/fasterxml/jackson/databind/util/EnumValues.java b/src/main/java/com/fasterxml/jackson/databind/util/EnumValues.java index 37a14d6e6f..aafc4e775c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/EnumValues.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/EnumValues.java @@ -39,7 +39,7 @@ private EnumValues(Class> enumClass, SerializableString[] textual) */ public static EnumValues construct(SerializationConfig config, AnnotatedClass annotatedClass) { if (config.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { - return constructFromToString(config, _enumClass(annotatedClass.getRawType())); + return constructFromToString(config, annotatedClass); } return constructFromName(config, annotatedClass); } @@ -104,6 +104,44 @@ public static EnumValues constructFromName(MapperConfig config, AnnotatedClas return construct(enumCls, textual); } + /** + * @since 2.16 + */ + public static EnumValues constructFromToString(MapperConfig config, AnnotatedClass annotatedClass) + { + // prepare data + final AnnotationIntrospector ai = config.getAnnotationIntrospector(); + final boolean useLowerCase = config.isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE); + final Class enumCls0 = annotatedClass.getRawType(); + final Class> enumCls = _enumClass(enumCls0); + final Enum[] enumConstants = _enumConstants(enumCls0); + + // introspect + String[] names = new String[enumConstants.length]; + if (ai != null) { + ai.findEnumValues(config, annotatedClass, enumConstants, names); + } + + // build + SerializableString[] textual = new SerializableString[enumConstants.length]; + for (int i = 0; i < enumConstants.length; i++) { + String name = names[i]; + if (name == null) { + Enum en = enumConstants[i]; + name = en.toString(); + } + if (useLowerCase) { + name = name.toLowerCase(); + } + textual[i] = config.compileString(name); + } + return construct(enumCls, textual); + } + + /** + * @deprecated since 2.16; use {@link #constructFromToString(MapperConfig, AnnotatedClass)} instead + */ + @Deprecated public static EnumValues constructFromToString(MapperConfig config, Class> enumClass) { Class> cls = ClassUtil.findEnumType(enumClass); diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/EnumSerializationTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/EnumSerializationTest.java index d09b3219c5..b9447adff6 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/jdk/EnumSerializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/EnumSerializationTest.java @@ -296,6 +296,13 @@ public void testEnumsWithJsonProperty() throws Exception { assertEquals(q("aleph"), MAPPER.writeValueAsString(EnumWithJsonProperty.A)); } + public void testEnumsWithJsonPropertyEnableToString() throws Exception { + String result = MAPPER.writerFor(EnumWithJsonProperty.class) + .with(SerializationFeature.WRITE_ENUMS_USING_TO_STRING) + .writeValueAsString(EnumWithJsonProperty.A); + assertEquals(q("aleph"), result); + } + // [databind#1535] public void testEnumKeysWithJsonProperty() throws Exception { Map input = new HashMap();