Skip to content

Commit

Permalink
Fix #4788 : WRITE_ENUMS_TO_LOWERCASE overrides @JsonProperty (#4789)
Browse files Browse the repository at this point in the history
  • Loading branch information
JooHyukKim authored Nov 8, 2024
1 parent bd5d3d6 commit 45b2dac
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 34 deletions.
60 changes: 26 additions & 34 deletions src/main/java/com/fasterxml/jackson/databind/util/EnumValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static EnumValues constructFromName(MapperConfig<?> config, Class<Enum<?>
{
// Enum types with per-instance sub-classes need special handling
Class<? extends Enum<?>> enumCls = ClassUtil.findEnumType(enumClass);
boolean useLowerCase = config.isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE);
Enum<?>[] enumValues = enumCls.getEnumConstants();
if (enumValues == null) {
throw new IllegalArgumentException("Cannot determine enum constants for Class "+enumClass.getName());
Expand All @@ -60,13 +61,7 @@ public static EnumValues constructFromName(MapperConfig<?> config, Class<Enum<?>
SerializableString[] textual = new SerializableString[enumValues.length];
for (int i = 0, len = enumValues.length; i < len; ++i) {
Enum<?> en = enumValues[i];
String name = names[i];
if (name == null) {
name = en.name();
}
if (config.isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE)) {
name = name.toLowerCase();
}
String name = _findNameToUse(names[i], enumValues[i].name(), useLowerCase);
textual[en.ordinal()] = config.compileString(name);
}
return construct(enumClass, textual);
Expand All @@ -92,13 +87,8 @@ public static EnumValues constructFromName(MapperConfig<?> config, AnnotatedClas
SerializableString[] textual = new SerializableString[enumConstants.length];
for (int i = 0, len = enumConstants.length; i < len; ++i) {
Enum<?> enumValue = enumConstants[i];
String name = names[i];
if (name == null) {
name = enumValue.name();
}
if (useLowerCase) {
name = name.toLowerCase();
}
String name = _findNameToUse(names[i], enumValue.name(), useLowerCase);
// if it should lower case? then lower it, but if there is Json Property, use JsonProperty name first, and not lower
textual[enumValue.ordinal()] = config.compileString(name);
}
return construct(enumCls, textual);
Expand All @@ -125,19 +115,11 @@ public static EnumValues constructFromToString(MapperConfig<?> config, Annotated
// 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();
// 01-Feb-2024, tatu: [databind#4355] Nulls not great but... let's
// coerce into "" for backwards compatibility
if (name == null) {
name = "";
}
}
if (useLowerCase) {
name = name.toLowerCase();
}
String enumToString = enumConstants[i].toString();
// 01-Feb-2024, tatu: [databind#4355] Nulls not great but... let's
// coerce into "" for backwards compatibility
enumToString = (enumToString == null) ? "" : enumToString;
String name = _findNameToUse(names[i], enumToString, useLowerCase);
textual[i] = config.compileString(name);
}
return construct(enumCls, textual);
Expand Down Expand Up @@ -189,13 +171,7 @@ public static EnumValues constructUsingEnumNamingStrategy(MapperConfig<?> config
SerializableString[] textual = new SerializableString[enumConstants.length];
for (int i = 0, len = enumConstants.length; i < len; i++) {
Enum<?> enumValue = enumConstants[i];
String name = names[i];
if (name == null) {
name = namingStrategy.convertEnumToExternalName(enumValue.name());
}
if (useLowerCase) {
name = name.toLowerCase();
}
String name = _findNameToUse(names[i], namingStrategy.convertEnumToExternalName(enumValue.name()), useLowerCase);
textual[i] = config.compileString(name);
}
return construct(enumCls, textual);
Expand Down Expand Up @@ -267,6 +243,22 @@ protected static Enum<?>[] _enumConstants(Class<?> enumCls) {
}
return enumValues;
}

protected static String _findNameToUse(String explicitName, String otherName, boolean toLowerCase) {
String name;
// If explicitly named, like @JsonProperty-annotated, then use it
if (explicitName != null) {
name = explicitName;
} else {
name = otherName;
// [databind#4788] Since 2.18.2 : EnumFeature.WRITE_ENUMS_TO_LOWERCASE should not
// override @JsonProperty values
if (toLowerCase) {
name = name.toLowerCase();
}
}
return name;
}

/*
/**********************************************************************
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.fasterxml.jackson.databind.ser.enums;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.EnumNamingStrategies;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.EnumNaming;
import com.fasterxml.jackson.databind.cfg.EnumFeature;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;

import static org.junit.jupiter.api.Assertions.assertEquals;

// [databind#4788] 2.18
public class WriteEnumsToLowerCaseOverridesJsonPropertyValue4788Test
extends DatabindTestUtil
{

public enum SauceA {
@JsonProperty("Ketchup")
KETCHUP,
}

@EnumNaming(EnumNamingStrategies.CamelCaseStrategy.class)
public enum SauceB {
@JsonProperty("PROPERTY_MAYO_NAIZZZZ")
MAYO_NAIZZZZ
}

public enum SauceC {
@JsonProperty("Is-A-Prop")
IS_MY_NAME
}

ObjectMapper objectMapper = jsonMapperBuilder()
.configure(EnumFeature.WRITE_ENUMS_TO_LOWERCASE, true)
.build();

@Test
void shouldUseJsonPropertySimple()
throws Exception
{
assertEquals(
"\"Ketchup\"",
objectMapper.writeValueAsString(SauceA.KETCHUP)
);

}

@Test
void shouldUseJsonPropertyOverEnumNaming()
throws Exception
{
assertEquals(
"\"PROPERTY_MAYO_NAIZZZZ\"",
objectMapper.writeValueAsString(SauceB.MAYO_NAIZZZZ)
);
}

@Test
void shouldUseJsonPropertyOverToString()
throws Exception
{
assertEquals(
"\"Is-A-Prop\"",
objectMapper.writer().with(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
.writeValueAsString(SauceC.IS_MY_NAME)
);
}
}

0 comments on commit 45b2dac

Please sign in to comment.