diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 4f42b3d49d..842877f6c0 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -20,6 +20,9 @@ Project: jackson-databind (contributed by Geoffrey G) #4388: Allow using `@JsonPropertyOrder` with "any" (`@JsonAnyGetter`) properties (fix by Joo-Hyuk K) +#4650: `PrimitiveArrayDeserializers` should deal with single String value if + `DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY` enabled + (reported, fix suggested by @eeren-bm) #4674: Allow setting global enum naming strategy similar to property naming strategy (requested by @hajdamak) (contributed by Konstantin M) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java index 17b1bc68ad..d058c5d380 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java @@ -213,13 +213,19 @@ public T deserialize(JsonParser p, DeserializationContext ctxt, T existing) thro @SuppressWarnings("unchecked") protected T handleNonArray(JsonParser p, DeserializationContext ctxt) throws IOException { - // Empty String can become null... - if (p.hasToken(JsonToken.VALUE_STRING)) { - return _deserializeFromString(p, ctxt); - } - boolean canWrap = (_unwrapSingle == Boolean.TRUE) || + + final boolean canWrap = (_unwrapSingle == Boolean.TRUE) || ((_unwrapSingle == null) && ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)); + // 12-Mar-2025, tatu: as per [databind#4650] things get bit tricky with + // single-element wrapping of a String value + // Let's still call _deserializeFromString() for empty strings no matter what, + // and for all values if wrapping not enabled + if (p.hasToken(JsonToken.VALUE_STRING)) { + if (!canWrap || _isBlank(p.getText())) { + return _deserializeFromString(p, ctxt); + } + } if (canWrap) { return handleSingleElementUnwrapped(p, ctxt); } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ArrayDeserializationTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ArrayDeserializationTest.java index 6489ef07a4..65e37ab467 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ArrayDeserializationTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/jdk/ArrayDeserializationTest.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.fasterxml.jackson.databind.module.SimpleModule; +import static com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY; import static org.junit.jupiter.api.Assertions.*; import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.a2q; @@ -542,6 +543,53 @@ public void testFloatArray() throws Exception } } + @Test + public void testSingleStringToPrimitiveArray() throws JsonProcessingException { + MAPPER.enable(ACCEPT_SINGLE_VALUE_AS_ARRAY); + assertLengthValue(MAPPER.readValue("\"true\"", boolean[].class), true); + assertLengthValue(MAPPER.readValue("\"a\"", char[].class), 'a'); + assertLengthValue(MAPPER.readValue("\"1\"", short[].class), (short) 1); + assertLengthValue(MAPPER.readValue("\"1\"", int[].class), 1); + assertLengthValue(MAPPER.readValue("\"1\"", long[].class), 1L); + assertLengthValue(MAPPER.readValue("\"7.038531e-26\"", float[].class), 7.038531e-26f); + assertLengthValue(MAPPER.readValue("\"1.5555\"", double[].class), 1.5555d); + } + + private void assertLengthValue(boolean[] arr, boolean expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + + private void assertLengthValue(char[] arr, char expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + + private void assertLengthValue(short[] arr, short expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + + private void assertLengthValue(int[] arr, int expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + + private void assertLengthValue(long[] arr, long expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + + private void assertLengthValue(float[] arr, float expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + + private void assertLengthValue(double[] arr, double expt) { + assertEquals(1, arr.length); + assertEquals(expt, arr[0]); + } + /* /********************************************************** /* Tests for Bean arrays