Skip to content

Commit a01d01f

Browse files
committed
Merge branch '2.16' into 2.17
2 parents 11f9b4a + ee39f3e commit a01d01f

File tree

5 files changed

+87
-13
lines changed

5 files changed

+87
-13
lines changed

release-notes/CREDITS-2.x

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,10 @@ Stephane Bailliez (sbailliez@github)
17391739
leads to `InvalidDefinitionException`: Multiple fields representing property
17401740
(2.16.2)
17411741

1742+
Guillaume Jardillier (Mugiwara84@github)
1743+
* Reported #4564: Possible 2.16.0 Enum-as-JSON-Object serialization regression
1744+
(2.16.3)
1745+
17421746
Muhammad Khalikov (mukham12@github)
17431747
* Contributed fix for #4209: Make `BeanDeserializerModifier`/`BeanSerializerModifier`
17441748
implement `java.io.Serializable`
@@ -1770,4 +1774,3 @@ Oddbjørn Kvalsund (oddbjornkvalsund@github)
17701774
* Reported, contributed fix for #4430: Use `ReentrantLock` instead of `synchronized`
17711775
in `DeserializerCache` to avoid deadlock on pinning
17721776
(2.17.1)
1773-

release-notes/VERSION-2.x

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ Project: jackson-databind
9191
(suggested by András P)
9292
- JUnit5 upgraded to 5.10.1
9393
94+
2.16.3 (not yet released)
95+
96+
#4564: Possible 2.16.0 Enum-as-JSON-Object serialization regression
97+
(reported by Guillaume J)
98+
(fix contributed by Joo-Hyuk K)
99+
94100
2.16.2 (09-Mar-2024)
95101
96102
#4302: Problem deserializing some type of Enums when using `PropertyNamingStrategy`

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedFieldCollector.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,18 @@ private void _addFieldMixIns(Class<?> mixInCls, Class<?> targetClass,
124124

125125
private boolean _isIncludableField(Field f)
126126
{
127-
// [databind#2787]: Allow `Enum` mixins
127+
// [databind#2787]: To allow `Enum` mixins, need to include Enum constants even
128+
// to they are static fields, not instance ones.
128129
if (f.isEnumConstant()) {
129130
return true;
130131
}
131132
// Most likely synthetic fields, if any, are to be skipped similar to methods
132133
if (f.isSynthetic()) {
133134
return false;
134135
}
135-
// Static fields are never included. Transient are (since 2.6), for
136-
// purpose of propagating removal
137-
int mods = f.getModifiers();
138-
if (Modifier.isStatic(mods)) {
136+
// Static fields are never included (except for above-mentioned Enum constants.
137+
// Transient are (since 2.6), for purpose of propagating removal
138+
if (Modifier.isStatic(f.getModifiers())) {
139139
return false;
140140
}
141141
return true;

src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ protected JsonSerializer<?> buildEnumSerializer(SerializationConfig config,
12081208
((BasicBeanDescription) beanDesc).removeProperty("declaringClass");
12091209
// [databind#2787]: remove self-referencing enum fields introduced by annotation flattening of mixins
12101210
if (type.isEnumType()){
1211-
_removeEnumSelfReferences(((BasicBeanDescription) beanDesc));
1211+
_removeEnumSelfReferences(beanDesc);
12121212
}
12131213
// returning null will mean that eventually BeanSerializer gets constructed
12141214
return null;
@@ -1226,24 +1226,28 @@ protected JsonSerializer<?> buildEnumSerializer(SerializationConfig config,
12261226
}
12271227

12281228
/**
1229-
* Helper method used for serialization {@link Enum} as {@link JsonFormat.Shape#OBJECT}. Removes any
1230-
* self-referencing properties from its bean description before it is transformed into a JSON Object
1231-
* as configured by {@link JsonFormat.Shape#OBJECT}.
1229+
* Helper method used for serialization {@link Enum} as {@link JsonFormat.Shape#OBJECT}.
1230+
* Removes any self-referencing properties from its bean description before it is
1231+
* transformed into a JSON Object as configured by {@link JsonFormat.Shape#OBJECT}.
12321232
* <p>
1233-
* Internally, this method iterates through {@link BeanDescription#findProperties()} and removes self.
1233+
* Internally, this method iterates through {@link BeanDescription#findProperties()}
1234+
* and removes self references.
12341235
*
12351236
* @param beanDesc the bean description to remove Enum properties from.
12361237
*
12371238
* @since 2.16
12381239
*/
1239-
private void _removeEnumSelfReferences(BasicBeanDescription beanDesc) {
1240+
private void _removeEnumSelfReferences(BeanDescription beanDesc) {
12401241
Class<?> aClass = ClassUtil.findEnumType(beanDesc.getBeanClass());
12411242
Iterator<BeanPropertyDefinition> it = beanDesc.findProperties().iterator();
12421243
while (it.hasNext()) {
12431244
BeanPropertyDefinition property = it.next();
12441245
JavaType propType = property.getPrimaryType();
12451246
// is the property a self-reference?
1246-
if (propType.isEnumType() && propType.isTypeOrSubTypeOf(aClass)) {
1247+
if (propType.isEnumType() && propType.isTypeOrSubTypeOf(aClass)
1248+
// [databind#4564] Since 2.16.3, Enum's should allow self as field, so let's remove only if static.
1249+
&& property.getAccessor().isStatic())
1250+
{
12471251
it.remove();
12481252
}
12491253
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.fasterxml.jackson.databind.ser.enums;
2+
3+
import com.fasterxml.jackson.annotation.JsonFormat;
4+
import com.fasterxml.jackson.annotation.JsonInclude;
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.core.type.TypeReference;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
8+
import com.fasterxml.jackson.databind.json.JsonMapper;
9+
import org.junit.jupiter.api.Test;
10+
11+
import java.util.ArrayList;
12+
import java.util.List;
13+
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
16+
// [databind#4564] Fix Enum-asJSON-Object serialization with self as field.
17+
public class EnumAsFormatObject4564Test
18+
{
19+
20+
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
21+
@JsonInclude(JsonInclude.Include.NON_NULL)
22+
public enum Level {
23+
LEVEL1("level1"),
24+
LEVEL2("level2"),
25+
LEVEL3("level3", Level.LEVEL1);
26+
27+
public String label;
28+
public Level sublevel;
29+
30+
Level(String level2) {
31+
this.label = level2;
32+
}
33+
34+
Level(String level3, Level level) {
35+
this.label = level3;
36+
this.sublevel = level;
37+
}
38+
}
39+
40+
private final ObjectMapper MAPPER = new JsonMapper();
41+
42+
@Test
43+
public void testEnumAsFormatObject() throws JsonProcessingException {
44+
List<Level> levels = new ArrayList<>();
45+
levels.add(Level.LEVEL1);
46+
levels.add(Level.LEVEL2);
47+
levels.add(Level.LEVEL3);
48+
49+
String JSON = MAPPER.writerFor(new TypeReference<List<Level>>() {
50+
}).writeValueAsString(levels);
51+
52+
// Fails, because we get [{"label":"level1"},{"label":"level2"},{"label":"level3"}]
53+
assertEquals(
54+
"["
55+
+ "{\"label\":\"level1\"},"
56+
+ "{\"label\":\"level2\"},"
57+
+ "{\"label\":\"level3\",\"sublevel\":{\"label\":\"level1\"}}"
58+
+ "]",
59+
JSON);
60+
}
61+
}

0 commit comments

Comments
 (0)