Skip to content

Commit 3c48461

Browse files
authored
Use JsonProperty and lowercase feature with Enum serialization despite write using toString (#4039)
1 parent 32045e0 commit 3c48461

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

src/main/java/com/fasterxml/jackson/databind/ser/std/EnumSerializer.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ public class EnumSerializer
5959
*/
6060
protected final EnumValues _valuesByEnumNaming;
6161

62+
/**
63+
* Map that contains pre-resolved values for {@link Enum#toString} to use for serialization,
64+
* while respecting {@link com.fasterxml.jackson.annotation.JsonProperty}
65+
* and {@link com.fasterxml.jackson.databind.cfg.EnumFeature#WRITE_ENUMS_TO_LOWERCASE}.
66+
*
67+
* @since 2.16
68+
*/
69+
protected final EnumValues _valuesByToString;
70+
6271
/*
6372
/**********************************************************
6473
/* Construction, initialization
@@ -71,6 +80,7 @@ public EnumSerializer(EnumValues v, Boolean serializeAsIndex)
7180
_values = v;
7281
_serializeAsIndex = serializeAsIndex;
7382
_valuesByEnumNaming = null;
83+
_valuesByToString = null;
7484
}
7585

7686
/**
@@ -82,6 +92,20 @@ public EnumSerializer(EnumValues v, Boolean serializeAsIndex, EnumValues valuesB
8292
_values = v;
8393
_serializeAsIndex = serializeAsIndex;
8494
_valuesByEnumNaming = valuesByEnumNaming;
95+
_valuesByToString = null;
96+
}
97+
98+
/**
99+
* @since 2.16
100+
*/
101+
public EnumSerializer(EnumValues v, Boolean serializeAsIndex, EnumValues valuesByEnumNaming,
102+
EnumValues valuesByToString)
103+
{
104+
super(v.getEnumClass(), false);
105+
_values = v;
106+
_serializeAsIndex = serializeAsIndex;
107+
_valuesByEnumNaming = valuesByEnumNaming;
108+
_valuesByToString = valuesByToString;
85109
}
86110

87111
/**
@@ -100,8 +124,9 @@ public static EnumSerializer construct(Class<?> enumClass, SerializationConfig c
100124
*/
101125
EnumValues v = EnumValues.constructFromName(config, beanDesc.getClassInfo());
102126
EnumValues valuesByEnumNaming = constructEnumNamingStrategyValues(config, (Class<Enum<?>>) enumClass, beanDesc.getClassInfo());
127+
EnumValues valuesByToString = EnumValues.constructFromToString(config, beanDesc.getClassInfo());
103128
Boolean serializeAsIndex = _isShapeWrittenUsingIndex(enumClass, format, true, null);
104-
return new EnumSerializer(v, serializeAsIndex, valuesByEnumNaming);
129+
return new EnumSerializer(v, serializeAsIndex, valuesByEnumNaming, valuesByToString);
105130
}
106131

107132
/**
@@ -154,7 +179,7 @@ public final void serialize(Enum<?> en, JsonGenerator gen, SerializerProvider se
154179
}
155180
// [databind#749]: or via toString()?
156181
if (serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) {
157-
gen.writeString(en.toString());
182+
gen.writeString(_valuesByToString.serializedValueFor(en));
158183
return;
159184
}
160185
gen.writeString(_values.serializedValueFor(en));
@@ -205,8 +230,8 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t
205230
// Use toString()?
206231
if ((serializers != null) &&
207232
serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) {
208-
for (Enum<?> e : _values.enums()) {
209-
enums.add(e.toString());
233+
for (SerializableString value : _valuesByToString.values()) {
234+
enums.add(value.getValue());
210235
}
211236
} else {
212237
// No, serialize using name() or explicit overrides

src/main/java/com/fasterxml/jackson/databind/util/EnumValues.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ private EnumValues(Class<Enum<?>> enumClass, SerializableString[] textual)
3939
*/
4040
public static EnumValues construct(SerializationConfig config, AnnotatedClass annotatedClass) {
4141
if (config.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) {
42-
return constructFromToString(config, _enumClass(annotatedClass.getRawType()));
42+
return constructFromToString(config, annotatedClass);
4343
}
4444
return constructFromName(config, annotatedClass);
4545
}
@@ -104,6 +104,44 @@ public static EnumValues constructFromName(MapperConfig<?> config, AnnotatedClas
104104
return construct(enumCls, textual);
105105
}
106106

107+
/**
108+
* @since 2.16
109+
*/
110+
public static EnumValues constructFromToString(MapperConfig<?> config, AnnotatedClass annotatedClass)
111+
{
112+
// prepare data
113+
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
114+
final boolean useLowerCase = config.isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE);
115+
final Class<?> enumCls0 = annotatedClass.getRawType();
116+
final Class<Enum<?>> enumCls = _enumClass(enumCls0);
117+
final Enum<?>[] enumConstants = _enumConstants(enumCls0);
118+
119+
// introspect
120+
String[] names = new String[enumConstants.length];
121+
if (ai != null) {
122+
ai.findEnumValues(config, annotatedClass, enumConstants, names);
123+
}
124+
125+
// build
126+
SerializableString[] textual = new SerializableString[enumConstants.length];
127+
for (int i = 0; i < enumConstants.length; i++) {
128+
String name = names[i];
129+
if (name == null) {
130+
Enum<?> en = enumConstants[i];
131+
name = en.toString();
132+
}
133+
if (useLowerCase) {
134+
name = name.toLowerCase();
135+
}
136+
textual[i] = config.compileString(name);
137+
}
138+
return construct(enumCls, textual);
139+
}
140+
141+
/**
142+
* @deprecated since 2.16; use {@link #constructFromToString(MapperConfig, AnnotatedClass)} instead
143+
*/
144+
@Deprecated
107145
public static EnumValues constructFromToString(MapperConfig<?> config, Class<Enum<?>> enumClass)
108146
{
109147
Class<? extends Enum<?>> cls = ClassUtil.findEnumType(enumClass);

src/test/java/com/fasterxml/jackson/databind/ser/jdk/EnumSerializationTest.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,13 @@ public void testEnumsWithJsonProperty() throws Exception {
296296
assertEquals(q("aleph"), MAPPER.writeValueAsString(EnumWithJsonProperty.A));
297297
}
298298

299+
public void testEnumsWithJsonPropertyEnableToString() throws Exception {
300+
String result = MAPPER.writerFor(EnumWithJsonProperty.class)
301+
.with(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
302+
.writeValueAsString(EnumWithJsonProperty.A);
303+
assertEquals(q("aleph"), result);
304+
}
305+
299306
// [databind#1535]
300307
public void testEnumKeysWithJsonProperty() throws Exception {
301308
Map<EnumWithJsonProperty,Integer> input = new HashMap<EnumWithJsonProperty,Integer>();

0 commit comments

Comments
 (0)