Skip to content

Commit 7bc2b76

Browse files
authored
Fix #5203 (null handling for EnumSet deserializer) (#5382)
1 parent 2877fcc commit 7bc2b76

File tree

4 files changed

+44
-30
lines changed

4 files changed

+44
-30
lines changed

release-notes/VERSION-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Project: jackson-databind
1010
#5045: If there is a no-parameter constructor marked as `JsonCreator` and
1111
a constructor reported as `DefaultCreator`, latter is incorrectly used
1212
(reported by @wrongwrong)
13+
#5203: Fix `null` handling of `EnumSetDeserializer`
1314
#5293: Fix minor typo in `PropertyBindingException.getMessageSuffix()`
1415
(reported by Johny L)
1516
#5313: Expose `getConverter()` in `StdDelegatingSerializer` for improved

src/main/java/com/fasterxml/jackson/databind/deser/std/EnumSetDeserializer.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,26 @@ protected final EnumSet<?> _deserialize(JsonParser p, DeserializationContext ctx
226226
// passed it to EnumDeserializer, too, but in general nulls should never be passed
227227
// to non-container deserializers)
228228
Enum<?> value;
229-
if (t == JsonToken.VALUE_NULL) {
230-
if (_skipNullValues) {
229+
if ((t == JsonToken.VALUE_NULL)
230+
// [databind#5203]: Custom deserializer may return null for non-null token
231+
|| (value = _enumDeserializer.deserialize(p, ctxt)) == null) {
232+
value = (Enum<?>) _nullProvider.getNullValue(ctxt);
233+
if (value == null) {
234+
if (_skipNullValues) {
235+
continue;
236+
}
237+
// EnumSet does not accept nulls, so we need to report an error
238+
// 05-Nov-2025, tatu: In case of no explicit Nulls handling; with 2.x,
239+
// let's just skip for backward compatibility; for 3.x, FAIL
240+
/*
241+
ctxt.handleUnexpectedToken(_enumType, JsonToken.VALUE_NULL, p,
242+
"`EnumSet` of type %s does not accept `null` values",
243+
ClassUtil.getTypeDescription(_enumType));
244+
*/
231245
continue;
232246
}
233-
value = (Enum<?>) _nullProvider.getNullValue(ctxt);
234-
} else {
235-
value = _enumDeserializer.deserialize(p, ctxt);
236-
}
237-
if (value != null) {
238-
result.add(value);
239247
}
248+
result.add(value);
240249
}
241250
} catch (Exception e) {
242251
throw JsonMappingException.wrapWithPath(e, result, result.size());

src/test/java/com/fasterxml/jackson/databind/tofix/EnumSetDeserializer5203Test.java renamed to src/test/java/com/fasterxml/jackson/databind/deser/enums/EnumSetDeserializer5203Test.java

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
package com.fasterxml.jackson.databind.tofix;
1+
package com.fasterxml.jackson.databind.deser.enums;
22

33
import java.io.IOException;
44
import java.util.EnumSet;
55

6-
import com.fasterxml.jackson.databind.testutil.failure.JacksonTestFailureExpected;
76
import org.junit.jupiter.api.Test;
87

98
import com.fasterxml.jackson.annotation.JsonSetter;
@@ -16,14 +15,16 @@
1615
import com.fasterxml.jackson.databind.exc.InvalidNullException;
1716
import com.fasterxml.jackson.databind.json.JsonMapper;
1817
import com.fasterxml.jackson.databind.module.SimpleModule;
18+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
1919

20+
import static org.junit.jupiter.api.Assertions.assertEquals;
2021
import static org.junit.jupiter.api.Assertions.assertThrows;
21-
import static org.junit.jupiter.api.Assertions.assertTrue;
2222

2323
// For [databind#5203]
2424
public class EnumSetDeserializer5203Test
25+
extends DatabindTestUtil
2526
{
26-
public enum MyEnum {
27+
enum MyEnum {
2728
FOO
2829
}
2930

@@ -57,40 +58,45 @@ public MyEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
5758
}
5859
}
5960

60-
private ObjectMapper createMapperWithCustomDeserializer() {
61-
SimpleModule module = new SimpleModule();
62-
module.addDeserializer(MyEnum.class, new EmptyStringToNullDeserializer());
63-
64-
return JsonMapper.builder()
65-
.addModule(module)
66-
.defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.FAIL))
67-
.build();
61+
@Test
62+
public void nullsDefaultTest() throws Exception {
63+
// In 2.x, default is to skip nulls (for backwards-compatibility)
64+
final ObjectMapper mapper = createMapperWithCustomDeserializer(Nulls.DEFAULT);
65+
_verifySkipResult(mapper);
6866
}
6967

70-
@JacksonTestFailureExpected
7168
@Test
72-
public void nullsFailTest() {
73-
ObjectMapper mapper = createMapperWithCustomDeserializer();
69+
public void nullsFailTest() throws Exception {
70+
final ObjectMapper mapper = createMapperWithCustomDeserializer(Nulls.FAIL);
7471

7572
assertThrows(
7673
InvalidNullException.class,
7774
() -> mapper.readValue("{\"set\":[\"\"]}", new TypeReference<Dst>(){})
7875
);
7976
}
80-
81-
@JacksonTestFailureExpected
77+
8278
@Test
8379
public void nullsSkipTest() throws Exception {
80+
final ObjectMapper mapper = createMapperWithCustomDeserializer(Nulls.SKIP);
81+
_verifySkipResult(mapper);
82+
}
83+
84+
private ObjectMapper createMapperWithCustomDeserializer(Nulls nullHandling) {
8485
SimpleModule module = new SimpleModule();
8586
module.addDeserializer(MyEnum.class, new EmptyStringToNullDeserializer());
8687

87-
ObjectMapper mapper = JsonMapper.builder()
88+
return JsonMapper.builder()
8889
.addModule(module)
89-
.defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP))
90+
.defaultSetterInfo(JsonSetter.Value.forContentNulls(nullHandling))
9091
.build();
92+
}
9193

94+
private void _verifySkipResult(ObjectMapper mapper) throws Exception
95+
{
9296
Dst dst = mapper.readValue("{\"set\":[\"FOO\",\"\"]}", new TypeReference<Dst>() {});
9397

94-
assertTrue(dst.getSet().isEmpty(), "Null values should be skipped");
98+
// Null value (from empty string) should be skipped, but FOO should be present
99+
assertEquals(1, dst.getSet().size());
100+
assertEquals(MyEnum.FOO, dst.getSet().iterator().next());
95101
}
96102
}

src/test/java/com/fasterxml/jackson/databind/deser/jdk/EnumMapDeserializer5165Test.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
import com.fasterxml.jackson.databind.ObjectMapper;
1111
import com.fasterxml.jackson.databind.exc.InvalidNullException;
1212
import com.fasterxml.jackson.databind.json.JsonMapper;
13-
import org.opentest4j.AssertionFailedError;
1413

15-
import static org.junit.jupiter.api.Assertions.assertFalse;
1614
import static org.junit.jupiter.api.Assertions.assertTrue;
1715
import static org.junit.jupiter.api.Assertions.assertThrows;
1816

0 commit comments

Comments
 (0)