Skip to content

Commit 45b2dac

Browse files
authored
Fix #4788 : WRITE_ENUMS_TO_LOWERCASE overrides @JsonProperty (#4789)
1 parent bd5d3d6 commit 45b2dac

File tree

2 files changed

+97
-34
lines changed

2 files changed

+97
-34
lines changed

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

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public static EnumValues constructFromName(MapperConfig<?> config, Class<Enum<?>
5252
{
5353
// Enum types with per-instance sub-classes need special handling
5454
Class<? extends Enum<?>> enumCls = ClassUtil.findEnumType(enumClass);
55+
boolean useLowerCase = config.isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE);
5556
Enum<?>[] enumValues = enumCls.getEnumConstants();
5657
if (enumValues == null) {
5758
throw new IllegalArgumentException("Cannot determine enum constants for Class "+enumClass.getName());
@@ -60,13 +61,7 @@ public static EnumValues constructFromName(MapperConfig<?> config, Class<Enum<?>
6061
SerializableString[] textual = new SerializableString[enumValues.length];
6162
for (int i = 0, len = enumValues.length; i < len; ++i) {
6263
Enum<?> en = enumValues[i];
63-
String name = names[i];
64-
if (name == null) {
65-
name = en.name();
66-
}
67-
if (config.isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE)) {
68-
name = name.toLowerCase();
69-
}
64+
String name = _findNameToUse(names[i], enumValues[i].name(), useLowerCase);
7065
textual[en.ordinal()] = config.compileString(name);
7166
}
7267
return construct(enumClass, textual);
@@ -92,13 +87,8 @@ public static EnumValues constructFromName(MapperConfig<?> config, AnnotatedClas
9287
SerializableString[] textual = new SerializableString[enumConstants.length];
9388
for (int i = 0, len = enumConstants.length; i < len; ++i) {
9489
Enum<?> enumValue = enumConstants[i];
95-
String name = names[i];
96-
if (name == null) {
97-
name = enumValue.name();
98-
}
99-
if (useLowerCase) {
100-
name = name.toLowerCase();
101-
}
90+
String name = _findNameToUse(names[i], enumValue.name(), useLowerCase);
91+
// if it should lower case? then lower it, but if there is Json Property, use JsonProperty name first, and not lower
10292
textual[enumValue.ordinal()] = config.compileString(name);
10393
}
10494
return construct(enumCls, textual);
@@ -125,19 +115,11 @@ public static EnumValues constructFromToString(MapperConfig<?> config, Annotated
125115
// build
126116
SerializableString[] textual = new SerializableString[enumConstants.length];
127117
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-
// 01-Feb-2024, tatu: [databind#4355] Nulls not great but... let's
133-
// coerce into "" for backwards compatibility
134-
if (name == null) {
135-
name = "";
136-
}
137-
}
138-
if (useLowerCase) {
139-
name = name.toLowerCase();
140-
}
118+
String enumToString = enumConstants[i].toString();
119+
// 01-Feb-2024, tatu: [databind#4355] Nulls not great but... let's
120+
// coerce into "" for backwards compatibility
121+
enumToString = (enumToString == null) ? "" : enumToString;
122+
String name = _findNameToUse(names[i], enumToString, useLowerCase);
141123
textual[i] = config.compileString(name);
142124
}
143125
return construct(enumCls, textual);
@@ -189,13 +171,7 @@ public static EnumValues constructUsingEnumNamingStrategy(MapperConfig<?> config
189171
SerializableString[] textual = new SerializableString[enumConstants.length];
190172
for (int i = 0, len = enumConstants.length; i < len; i++) {
191173
Enum<?> enumValue = enumConstants[i];
192-
String name = names[i];
193-
if (name == null) {
194-
name = namingStrategy.convertEnumToExternalName(enumValue.name());
195-
}
196-
if (useLowerCase) {
197-
name = name.toLowerCase();
198-
}
174+
String name = _findNameToUse(names[i], namingStrategy.convertEnumToExternalName(enumValue.name()), useLowerCase);
199175
textual[i] = config.compileString(name);
200176
}
201177
return construct(enumCls, textual);
@@ -267,6 +243,22 @@ protected static Enum<?>[] _enumConstants(Class<?> enumCls) {
267243
}
268244
return enumValues;
269245
}
246+
247+
protected static String _findNameToUse(String explicitName, String otherName, boolean toLowerCase) {
248+
String name;
249+
// If explicitly named, like @JsonProperty-annotated, then use it
250+
if (explicitName != null) {
251+
name = explicitName;
252+
} else {
253+
name = otherName;
254+
// [databind#4788] Since 2.18.2 : EnumFeature.WRITE_ENUMS_TO_LOWERCASE should not
255+
// override @JsonProperty values
256+
if (toLowerCase) {
257+
name = name.toLowerCase();
258+
}
259+
}
260+
return name;
261+
}
270262

271263
/*
272264
/**********************************************************************
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.fasterxml.jackson.databind.ser.enums;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import com.fasterxml.jackson.databind.EnumNamingStrategies;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
8+
import com.fasterxml.jackson.databind.SerializationFeature;
9+
import com.fasterxml.jackson.databind.annotation.EnumNaming;
10+
import com.fasterxml.jackson.databind.cfg.EnumFeature;
11+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
12+
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
15+
// [databind#4788] 2.18
16+
public class WriteEnumsToLowerCaseOverridesJsonPropertyValue4788Test
17+
extends DatabindTestUtil
18+
{
19+
20+
public enum SauceA {
21+
@JsonProperty("Ketchup")
22+
KETCHUP,
23+
}
24+
25+
@EnumNaming(EnumNamingStrategies.CamelCaseStrategy.class)
26+
public enum SauceB {
27+
@JsonProperty("PROPERTY_MAYO_NAIZZZZ")
28+
MAYO_NAIZZZZ
29+
}
30+
31+
public enum SauceC {
32+
@JsonProperty("Is-A-Prop")
33+
IS_MY_NAME
34+
}
35+
36+
ObjectMapper objectMapper = jsonMapperBuilder()
37+
.configure(EnumFeature.WRITE_ENUMS_TO_LOWERCASE, true)
38+
.build();
39+
40+
@Test
41+
void shouldUseJsonPropertySimple()
42+
throws Exception
43+
{
44+
assertEquals(
45+
"\"Ketchup\"",
46+
objectMapper.writeValueAsString(SauceA.KETCHUP)
47+
);
48+
49+
}
50+
51+
@Test
52+
void shouldUseJsonPropertyOverEnumNaming()
53+
throws Exception
54+
{
55+
assertEquals(
56+
"\"PROPERTY_MAYO_NAIZZZZ\"",
57+
objectMapper.writeValueAsString(SauceB.MAYO_NAIZZZZ)
58+
);
59+
}
60+
61+
@Test
62+
void shouldUseJsonPropertyOverToString()
63+
throws Exception
64+
{
65+
assertEquals(
66+
"\"Is-A-Prop\"",
67+
objectMapper.writer().with(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
68+
.writeValueAsString(SauceC.IS_MY_NAME)
69+
);
70+
}
71+
}

0 commit comments

Comments
 (0)