From 4e7257c8dfbda526d52a617384195ec81b1a8408 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 20:51:17 +0900 Subject: [PATCH 1/7] Add failing tests for ObjectArrayDeserializer wrt #5165 --- .../jdk/ObjectArrayDeserializer5165Test.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java new file mode 100644 index 0000000000..898796e201 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java @@ -0,0 +1,57 @@ +package com.fasterxml.jackson.databind.deser.jdk; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.InvalidNullException; +import com.fasterxml.jackson.databind.json.JsonMapper; +import org.opentest4j.AssertionFailedError; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +// For [databind#5165] +public class ObjectArrayDeserializer5165Test +{ + static class Dst { + private Integer[] array; + + public Integer[] getArray() { + return array; + } + + public void setArray(Integer[] array) { + this.array = array; + } + } + + @Test + public void nullsFailTest() { + ObjectMapper mapper = JsonMapper.builder() + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.FAIL)) + .build(); + + assertThrows( + AssertionFailedError.class, + () -> assertThrows( + InvalidNullException.class, + () -> mapper.readValue("{\"array\":[\"\"]}", new TypeReference(){}) + ), + "databind#5165 for ObjectArrayDeserializer is fixed" + ); + } + + @Test + public void nullsSkipTest() throws Exception { + ObjectMapper mapper = JsonMapper.builder() + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP)) + .build(); + + Dst dst = mapper.readValue("{\"array\":[\"\"]}", new TypeReference() {}); + + assertNotEquals(0, dst.getArray().length, "databind#5165 for ObjectArrayDeserializer is fixed"); + } +} From 7d74e719e54b7564bbf83e1bf9430abf4ecdcfdd Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 21:22:28 +0900 Subject: [PATCH 2/7] Fix #5165 on ObjectArrayDeserializer ref: https://github.com/FasterXML/jackson-databind/pull/5140/files#diff-692175612209d50652f1d14ffd325eb70cfdd282a6277f994207bfc63c0db515 --- .../deser/std/ObjectArrayDeserializer.java | 34 ++++++++++++++++--- .../jdk/ObjectArrayDeserializer5165Test.java | 13 +++---- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer.java index 61cc466335..d6e194c634 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer.java @@ -211,10 +211,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) if (_skipNullValues) { continue; } - value = _nullProvider.getNullValue(ctxt); + value = null; } else { value = _deserializeNoNullChecks(p, ctxt); } + + if (value == null) { + value = _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } + if (ix >= chunk.length) { chunk = buffer.appendCompletedChunk(chunk); ix = 0; @@ -275,10 +284,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt, if (_skipNullValues) { continue; } - value = _nullProvider.getNullValue(ctxt); + value = null; } else { value = _deserializeNoNullChecks(p, ctxt); } + + if (value == null) { + value = _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } + if (ix >= chunk.length) { chunk = buffer.appendCompletedChunk(chunk); ix = 0; @@ -346,7 +364,7 @@ protected Object handleNonArray(JsonParser p, DeserializationContext ctxt) if (_skipNullValues) { return _emptyValue; } - value = _nullProvider.getNullValue(ctxt); + value = null; } else { if (p.hasToken(JsonToken.VALUE_STRING)) { String textValue = p.getText(); @@ -371,6 +389,15 @@ protected Object handleNonArray(JsonParser p, DeserializationContext ctxt) value = _deserializeNoNullChecks(p, ctxt); } + + if (value == null) { + value = _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + return _emptyValue; + } + } + // Ok: bit tricky, since we may want T[], not just Object[] Object[] result; @@ -399,4 +426,3 @@ protected Object _deserializeNoNullChecks(JsonParser p, DeserializationContext c return _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer); } } - diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java index 898796e201..c4e007eaef 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ObjectArrayDeserializer5165Test.java @@ -8,9 +8,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.InvalidNullException; import com.fasterxml.jackson.databind.json.JsonMapper; -import org.opentest4j.AssertionFailedError; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; // For [databind#5165] @@ -35,12 +34,8 @@ public void nullsFailTest() { .build(); assertThrows( - AssertionFailedError.class, - () -> assertThrows( - InvalidNullException.class, - () -> mapper.readValue("{\"array\":[\"\"]}", new TypeReference(){}) - ), - "databind#5165 for ObjectArrayDeserializer is fixed" + InvalidNullException.class, + () -> mapper.readValue("{\"array\":[\"\"]}", new TypeReference(){}) ); } @@ -52,6 +47,6 @@ public void nullsSkipTest() throws Exception { Dst dst = mapper.readValue("{\"array\":[\"\"]}", new TypeReference() {}); - assertNotEquals(0, dst.getArray().length, "databind#5165 for ObjectArrayDeserializer is fixed"); + assertEquals(0, dst.getArray().length, "Null values should be skipped"); } } From d1b4ba332ebd128e1b6360361d3bce87b7b82bfe Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 21:08:19 +0900 Subject: [PATCH 3/7] Add failing tests for StringArrayDeserializer wrt #5165 --- .../jdk/StringArrayDeserializer5165Test.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java new file mode 100644 index 0000000000..9b4cd04357 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java @@ -0,0 +1,93 @@ +package com.fasterxml.jackson.databind.deser.jdk; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidNullException; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.opentest4j.AssertionFailedError; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +// For [databind#5165] +public class StringArrayDeserializer5165Test +{ + static class Dst { + private String[] array; + + public String[] getArray() { + return array; + } + + public void setArray(String[] array) { + this.array = array; + } + } + + // Custom deserializer that converts empty strings to null + static class EmptyStringToNullDeserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public EmptyStringToNullDeserializer() { + super(String.class); + } + + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + if (value != null && value.isEmpty()) { + return null; + } + return value; + } + } + + private ObjectMapper createMapperWithCustomDeserializer() { + SimpleModule module = new SimpleModule(); + module.addDeserializer(String.class, new EmptyStringToNullDeserializer()); + + return JsonMapper.builder() + .addModule(module) + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.FAIL)) + .build(); + } + + @Test + public void nullsFailTest() { + ObjectMapper mapper = createMapperWithCustomDeserializer(); + + assertThrows( + AssertionFailedError.class, + () -> assertThrows( + InvalidNullException.class, + () -> mapper.readValue("{\"array\":[\"\"]}", new TypeReference(){}) + ), + "databind#5165 for StringArrayDeserializer is fixed" + ); + } + + @Test + public void nullsSkipTest() throws Exception { + SimpleModule module = new SimpleModule(); + module.addDeserializer(String.class, new EmptyStringToNullDeserializer()); + + ObjectMapper mapper = JsonMapper.builder() + .addModule(module) + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP)) + .build(); + + Dst dst = mapper.readValue("{\"array\":[\"\"]}", new TypeReference() {}); + + assertNotEquals(0, dst.getArray().length, "databind#5165 for StringArrayDeserializer is fixed"); + } +} From bdc4df0ef5fb2395d8dad36625f60b8686098b63 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 21:24:18 +0900 Subject: [PATCH 4/7] Fix #5165 on StringArrayDeserializer ref: https://github.com/FasterXML/jackson-databind/pull/5140/files#diff-692175612209d50652f1d14ffd325eb70cfdd282a6277f994207bfc63c0db515 --- .../deser/std/StringArrayDeserializer.java | 29 +++++++++++++++++-- .../jdk/StringArrayDeserializer5165Test.java | 13 +++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java index 864299d326..aafdc80230 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java @@ -162,10 +162,17 @@ public String[] deserialize(JsonParser p, DeserializationContext ctxt) throws IO if (_skipNullValues) { continue; } - value = (String) _nullProvider.getNullValue(ctxt); } else { value = _parseString(p, ctxt, _nullProvider); } + + if (value == null) { + value = (String) _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } } if (ix >= chunk.length) { chunk = buffer.appendCompletedChunk(chunk); @@ -219,13 +226,22 @@ private String[] _deserializeCustom(JsonParser p, DeserializationContext ctxt, if (_skipNullValues) { continue; } - value = (String) _nullProvider.getNullValue(ctxt); + value = null; } else { value = deser.deserialize(p, ctxt); } } else { value = deser.deserialize(p, ctxt); } + + if (value == null) { + value = (String) _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } + if (ix >= chunk.length) { chunk = buffer.appendCompletedChunk(chunk); ix = 0; @@ -283,10 +299,17 @@ public String[] deserialize(JsonParser p, DeserializationContext ctxt, if (_skipNullValues) { return NO_STRINGS; } - value = (String) _nullProvider.getNullValue(ctxt); } else { value = _parseString(p, ctxt, _nullProvider); } + + if (value == null) { + value = (String) _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } } if (ix >= chunk.length) { chunk = buffer.appendCompletedChunk(chunk); diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java index 9b4cd04357..8d65e86c86 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringArrayDeserializer5165Test.java @@ -14,9 +14,8 @@ import com.fasterxml.jackson.databind.exc.InvalidNullException; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.opentest4j.AssertionFailedError; -import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; // For [databind#5165] @@ -67,12 +66,8 @@ public void nullsFailTest() { ObjectMapper mapper = createMapperWithCustomDeserializer(); assertThrows( - AssertionFailedError.class, - () -> assertThrows( - InvalidNullException.class, - () -> mapper.readValue("{\"array\":[\"\"]}", new TypeReference(){}) - ), - "databind#5165 for StringArrayDeserializer is fixed" + InvalidNullException.class, + () -> mapper.readValue("{\"array\":[\"\"]}", new TypeReference(){}) ); } @@ -88,6 +83,6 @@ public void nullsSkipTest() throws Exception { Dst dst = mapper.readValue("{\"array\":[\"\"]}", new TypeReference() {}); - assertNotEquals(0, dst.getArray().length, "databind#5165 for StringArrayDeserializer is fixed"); + assertEquals(0, dst.getArray().length, "Null values should be skipped"); } } From 6f98b24ca1a0a28ac07f423da9be2620c6ed1eaa Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 21:19:13 +0900 Subject: [PATCH 5/7] Add failing tests for StringArrayDeserializer wrt #5165 --- .../StringCollectionDeserializer5165Test.java | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java new file mode 100644 index 0000000000..b0aaf8441f --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java @@ -0,0 +1,94 @@ +package com.fasterxml.jackson.databind.deser.jdk; + +import java.io.IOException; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidNullException; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.opentest4j.AssertionFailedError; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; + +// For [databind#5165] +public class StringCollectionDeserializer5165Test +{ + static class Dst { + private List list; + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + } + + // Custom deserializer that converts empty strings to null + static class EmptyStringToNullDeserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public EmptyStringToNullDeserializer() { + super(String.class); + } + + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + if (value != null && value.isEmpty()) { + return null; + } + return value; + } + } + + private ObjectMapper createMapperWithCustomDeserializer() { + SimpleModule module = new SimpleModule(); + module.addDeserializer(String.class, new EmptyStringToNullDeserializer()); + + return JsonMapper.builder() + .addModule(module) + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.FAIL)) + .build(); + } + + @Test + public void nullsFailTest() { + ObjectMapper mapper = createMapperWithCustomDeserializer(); + + assertThrows( + AssertionFailedError.class, + () -> assertThrows( + InvalidNullException.class, + () -> mapper.readValue("{\"list\":[\"\"]}", new TypeReference(){}) + ), + "databind#5165 for StringCollectionDeserializer is fixed" + ); + } + + @Test + public void nullsSkipTest() throws Exception { + SimpleModule module = new SimpleModule(); + module.addDeserializer(String.class, new EmptyStringToNullDeserializer()); + + ObjectMapper mapper = JsonMapper.builder() + .addModule(module) + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP)) + .build(); + + Dst dst = mapper.readValue("{\"list\":[\"\"]}", new TypeReference() {}); + + assertFalse(dst.getList().isEmpty(), "databind#5165 for StringCollectionDeserializer is fixed"); + } +} From 0cff12356463b07eee47e3bed37dfc9fa2b100cf Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 21:28:51 +0900 Subject: [PATCH 6/7] Fix #5165 on StringCollectionDeserializer ref: https://github.com/FasterXML/jackson-databind/pull/5140/files#diff-692175612209d50652f1d14ffd325eb70cfdd282a6277f994207bfc63c0db515 --- .../std/StringCollectionDeserializer.java | 32 +++++++++++++++++-- .../StringCollectionDeserializer5165Test.java | 13 +++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java index d4984a084b..acfb21f32a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java @@ -213,10 +213,18 @@ public Collection deserialize(JsonParser p, DeserializationContext ctxt, if (_skipNullValues) { continue; } - value = (String) _nullProvider.getNullValue(ctxt); } else { value = _parseString(p, ctxt, _nullProvider); } + + if (value == null) { + value = (String) _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } + result.add(value); } } catch (Exception e) { @@ -246,13 +254,22 @@ private Collection deserializeUsingCustom(JsonParser p, DeserializationC if (_skipNullValues) { continue; } - value = (String) _nullProvider.getNullValue(ctxt); + value = null; } else { value = deser.deserialize(p, ctxt); } } else { value = deser.deserialize(p, ctxt); } + + if (value == null) { + value = (String) _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + continue; + } + } + result.add(value); } } catch (Exception e) { @@ -297,7 +314,7 @@ private final Collection handleNonArray(JsonParser p, DeserializationCon if (_skipNullValues) { return result; } - value = (String) _nullProvider.getNullValue(ctxt); + value = null; } else { if (p.hasToken(JsonToken.VALUE_STRING)) { String textValue = p.getText(); @@ -326,6 +343,15 @@ private final Collection handleNonArray(JsonParser p, DeserializationCon throw JsonMappingException.wrapWithPath(e, result, result.size()); } } + + if (value == null) { + value = (String) _nullProvider.getNullValue(ctxt); + + if (value == null && _skipNullValues) { + return result; + } + } + result.add(value); return result; } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java index b0aaf8441f..8a93eb2fc9 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/StringCollectionDeserializer5165Test.java @@ -15,10 +15,9 @@ import com.fasterxml.jackson.databind.exc.InvalidNullException; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.opentest4j.AssertionFailedError; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; // For [databind#5165] public class StringCollectionDeserializer5165Test @@ -68,12 +67,8 @@ public void nullsFailTest() { ObjectMapper mapper = createMapperWithCustomDeserializer(); assertThrows( - AssertionFailedError.class, - () -> assertThrows( - InvalidNullException.class, - () -> mapper.readValue("{\"list\":[\"\"]}", new TypeReference(){}) - ), - "databind#5165 for StringCollectionDeserializer is fixed" + InvalidNullException.class, + () -> mapper.readValue("{\"list\":[\"\"]}", new TypeReference(){}) ); } @@ -89,6 +84,6 @@ public void nullsSkipTest() throws Exception { Dst dst = mapper.readValue("{\"list\":[\"\"]}", new TypeReference() {}); - assertFalse(dst.getList().isEmpty(), "databind#5165 for StringCollectionDeserializer is fixed"); + assertTrue(dst.getList().isEmpty(), "Null values should be skipped"); } } From 6b0c5f2f1ff5eeba1f951c317430cf128aa0773a Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 21 Jun 2025 21:33:13 +0900 Subject: [PATCH 7/7] Add failing tests for EnumSetDeserializer wrt #5165 --- .../tofix/EnumSetDeserializer5165Test.java | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/test/java/com/fasterxml/jackson/databind/tofix/EnumSetDeserializer5165Test.java diff --git a/src/test/java/com/fasterxml/jackson/databind/tofix/EnumSetDeserializer5165Test.java b/src/test/java/com/fasterxml/jackson/databind/tofix/EnumSetDeserializer5165Test.java new file mode 100644 index 0000000000..49542266a6 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/tofix/EnumSetDeserializer5165Test.java @@ -0,0 +1,96 @@ +package com.fasterxml.jackson.databind.tofix; + +import java.io.IOException; +import java.util.EnumSet; + +import com.fasterxml.jackson.databind.testutil.failure.JacksonTestFailureExpected; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.exc.InvalidNullException; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +// For [databind#5165] +public class EnumSetDeserializer5165Test +{ + public enum MyEnum { + FOO + } + + static class Dst { + private EnumSet set; + + public EnumSet getSet() { + return set; + } + + public void setSet(EnumSet set) { + this.set = set; + } + } + + // Custom deserializer that converts empty strings to null + static class EmptyStringToNullDeserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public EmptyStringToNullDeserializer() { + super(MyEnum.class); + } + + @Override + public MyEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = p.getValueAsString(); + if (value != null && value.isEmpty()) { + return null; + } + return MyEnum.valueOf(value); + } + } + + private ObjectMapper createMapperWithCustomDeserializer() { + SimpleModule module = new SimpleModule(); + module.addDeserializer(MyEnum.class, new EmptyStringToNullDeserializer()); + + return JsonMapper.builder() + .addModule(module) + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.FAIL)) + .build(); + } + + @JacksonTestFailureExpected + @Test + public void nullsFailTest() { + ObjectMapper mapper = createMapperWithCustomDeserializer(); + + assertThrows( + InvalidNullException.class, + () -> mapper.readValue("{\"set\":[\"\"]}", new TypeReference(){}) + ); + } + + @JacksonTestFailureExpected + @Test + public void nullsSkipTest() throws Exception { + SimpleModule module = new SimpleModule(); + module.addDeserializer(MyEnum.class, new EmptyStringToNullDeserializer()); + + ObjectMapper mapper = JsonMapper.builder() + .addModule(module) + .defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP)) + .build(); + + Dst dst = mapper.readValue("{\"set\":[\"FOO\",\"\"]}", new TypeReference() {}); + + assertTrue(dst.getSet().isEmpty(), "Null values should be skipped"); + } +}