From eb4082a075cdb5ebb6f1768369be6c0449105c3f Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Aug 2025 15:42:00 -0700 Subject: [PATCH 1/7] Fix #196: support serialization of `float[]`, `double[]` --- .../jackson/jr/ob/impl/JSONWriter.java | 57 +++++++ .../jackson/jr/ob/impl/ValueLocatorBase.java | 12 ++ .../jackson/jr/ob/PrimitiveArrayTest.java | 141 ++++++++++++++++++ release-notes/CREDITS-2.x | 5 + release-notes/VERSION-2.x | 3 + 5 files changed, 218 insertions(+) create mode 100644 jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java diff --git a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java index a0cfc2f6..59055738 100644 --- a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java +++ b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java @@ -191,6 +191,15 @@ public void writeField(String fieldName, Object value, int type) throws IOExcept case SER_BOOLEAN_ARRAY: writeBooleanArrayField(fieldName, (boolean[]) value); return; + case SER_SHORT_ARRAY: + writeShortArrayField(fieldName, (short[]) value); + return; + case SER_FLOAT_ARRAY: + writeFloatArrayField(fieldName, (float[]) value); + return; + case SER_DOUBLE_ARRAY: + writeDoubleArrayField(fieldName, (double[]) value); + return; case SER_TREE_NODE: writeTreeNodeField(fieldName, (TreeNode) value); return; @@ -319,6 +328,15 @@ protected void _writeValue(Object value, int type) throws IOException case SER_BOOLEAN_ARRAY: writeBooleanArrayValue((boolean[]) value); return; + case SER_SHORT_ARRAY: + writeShortArrayValue((short[]) value); + return; + case SER_FLOAT_ARRAY: + writeFloatArrayValue((float[]) value); + return; + case SER_DOUBLE_ARRAY: + writeDoubleArrayValue((double[]) value); + return; case SER_TREE_NODE: writeTreeNodeValue((TreeNode) value); return; @@ -555,6 +573,45 @@ protected void writeBooleanArrayField(String fieldName, boolean[] v) throws IOEx writeBooleanArrayValue(v); } + protected void writeShortArrayValue(short[] v) throws IOException { + _generator.writeStartArray(); + for (int i = 0, len = v.length; i < len; ++i) { + _generator.writeNumber(v[i]); + } + _generator.writeEndArray(); + } + + protected void writeShortArrayField(String fieldName, short[] v) throws IOException { + _generator.writeFieldName(fieldName); + writeShortArrayValue(v); + } + + protected void writeFloatArrayValue(float[] v) throws IOException { + _generator.writeStartArray(); + for (int i = 0, len = v.length; i < len; ++i) { + _generator.writeNumber(v[i]); + } + _generator.writeEndArray(); + } + + protected void writeFloatArrayField(String fieldName, float[] v) throws IOException { + _generator.writeFieldName(fieldName); + writeFloatArrayValue(v); + } + + protected void writeDoubleArrayValue(double[] v) throws IOException { + _generator.writeStartArray(); + for (int i = 0, len = v.length; i < len; ++i) { + _generator.writeNumber(v[i]); + } + _generator.writeEndArray(); + } + + protected void writeDoubleArrayField(String fieldName, double[] v) throws IOException { + _generator.writeFieldName(fieldName); + writeDoubleArrayValue(v); + } + protected void writeTreeNodeValue(TreeNode v) throws IOException { if (_treeCodec == null) { throw new JSONObjectException("No `TreeCodec` configured: can not serialize `TreeNode` values"); diff --git a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java index a2e18bc3..61f56c32 100644 --- a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java +++ b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java @@ -61,6 +61,9 @@ public abstract class ValueLocatorBase public final static int SER_INT_ARRAY = 5; public final static int SER_LONG_ARRAY = 6; public final static int SER_BOOLEAN_ARRAY = 7; + public final static int SER_SHORT_ARRAY = 38; + public final static int SER_FLOAT_ARRAY = 39; + public final static int SER_DOUBLE_ARRAY = 40; /** * An implementation of {@link com.fasterxml.jackson.core.TreeNode} @@ -159,6 +162,15 @@ protected int _findSimpleType(Class raw, boolean forSer) if (raw == boolean[].class) { return SER_BOOLEAN_ARRAY; } + if (raw == short[].class) { + return SER_SHORT_ARRAY; + } + if (raw == float[].class) { + return SER_FLOAT_ARRAY; + } + if (raw == double[].class) { + return SER_DOUBLE_ARRAY; + } // Hmmh. Could support all types; add as/when needed return SER_UNKNOWN; } diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java new file mode 100644 index 00000000..fafb32ee --- /dev/null +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java @@ -0,0 +1,141 @@ +package com.fasterxml.jackson.jr.ob; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.jr.testutil.failure.JacksonTestFailureExpected; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PrimitiveArrayTest extends TestBase +{ + // Test all 7 primitive array types: boolean[], byte[], short[], int[], long[], float[], double[] + // Also test char[] which is handled specially (as String) + + private final static String BOOLEAN_ARRAY_JSON = "[true,false,true,false,true]"; + private final static boolean[] BOOLEAN_ARRAY = new boolean[] { true, false, true, false, true }; + + @Test + public void testBooleanArrayRead() throws Exception { + assertArrayEquals(BOOLEAN_ARRAY, JSON.std.beanFrom(boolean[].class, BOOLEAN_ARRAY_JSON)); + } + + @Test + public void testBooleanArrayWrite() throws Exception { + assertEquals(BOOLEAN_ARRAY_JSON, JSON.std.asString(BOOLEAN_ARRAY)); + } + + // Special: uses Base64 encoding for byte arrays + @Test + public void testByteArrayReadWrite() throws Exception { + final byte[] input = new byte[]{1, 2, 3, 127, -128}; + String json = JSON.std.asString(input); + byte[] result = JSON.std.beanFrom(byte[].class, json); + assertArrayEquals(input, result); + } + + // Special: char[] is serialized as a String + @Test + public void testCharArray() throws Exception { + final char[] input = new char[]{'a', 'b', 'c', 'X', 'Y', 'Z'}; + String json = JSON.std.asString(input); + char[] result = JSON.std.beanFrom(char[].class, json); + assertArrayEquals(input, result); + } + + private final static String SHORT_ARRAY_JSON = "[1,2,3,32767,-32768]"; + private final static short[] SHORT_ARRAY = new short[] { 1, 2, 3, 32767, -32768 }; + + @JacksonTestFailureExpected + @Test + public void testShortArrayRead() throws Exception { + assertArrayEquals(SHORT_ARRAY, JSON.std.beanFrom(short[].class, SHORT_ARRAY_JSON)); + } + + @Test + public void testShortArrayArrayWrite() throws Exception { + assertEquals(SHORT_ARRAY_JSON, JSON.std.asString(SHORT_ARRAY)); + } + + @Test + public void testIntArray() throws Exception { + final int[] input = new int[]{1, 2, 3, 25, 999}; + String json = JSON.std.asString(input); + int[] result = JSON.std.beanFrom(int[].class, json); + assertArrayEquals(input, result); + } + + @Test + public void testLongArray() throws Exception { + final long[] input = new long[]{1L, 2L, 3L, 999999999999L, -999999999999L}; + String json = JSON.std.asString(input); + long[] result = JSON.std.beanFrom(long[].class, json); + assertArrayEquals(input, result); + } + + @Test + public void testFloatArray() throws Exception { + final float[] input = new float[]{1.0f, 2.5f, 3.14f, -5.5f, 0.0f}; + String json = JSON.std.asString(input); + float[] result = JSON.std.beanFrom(float[].class, json); + assertArrayEquals(input, result, 0.0001f); + } + + @Test + public void testDoubleArray() throws Exception { + final double[] input = new double[]{1.0, 2.5, 3.14159, -5.5, 0.0}; + String json = JSON.std.asString(input); + double[] result = JSON.std.beanFrom(double[].class, json); + assertArrayEquals(input, result, 0.0000001); + } + + // Test empty arrays + @Test + public void testEmptyArrays() throws Exception { + assertArrayEquals(new boolean[0], JSON.std.beanFrom(boolean[].class, "[]")); + assertArrayEquals(new byte[0], JSON.std.beanFrom(byte[].class, "[]")); + assertArrayEquals(new char[0], JSON.std.beanFrom(char[].class, "\"\"")); + assertArrayEquals(new short[0], JSON.std.beanFrom(short[].class, "[]")); + assertArrayEquals(new int[0], JSON.std.beanFrom(int[].class, "[]")); + assertArrayEquals(new long[0], JSON.std.beanFrom(long[].class, "[]")); + assertArrayEquals(new float[0], JSON.std.beanFrom(float[].class, "[]"), 0.0f); + assertArrayEquals(new double[0], JSON.std.beanFrom(double[].class, "[]"), 0.0); + } + + // Test arrays as object fields + public static class AllArraysBean { + public boolean[] booleans; + public byte[] bytes; + public char[] chars; + public short[] shorts; + public int[] ints; + public long[] longs; + public float[] floats; + public double[] doubles; + } + + @Test + public void testArraysAsObjectFields() throws Exception { + AllArraysBean input = new AllArraysBean(); + input.booleans = new boolean[]{true, false}; + input.bytes = new byte[]{1, 2, 3}; + input.chars = new char[]{'a', 'b'}; + input.shorts = new short[]{10, 20}; + input.ints = new int[]{100, 200}; + input.longs = new long[]{1000L, 2000L}; + input.floats = new float[]{1.5f, 2.5f}; + input.doubles = new double[]{10.5, 20.5}; + + String json = JSON.std.asString(input); + AllArraysBean result = JSON.std.beanFrom(AllArraysBean.class, json); + + assertArrayEquals(input.booleans, result.booleans); + assertArrayEquals(input.bytes, result.bytes); + assertArrayEquals(input.chars, result.chars); + assertArrayEquals(input.shorts, result.shorts); + assertArrayEquals(input.ints, result.ints); + assertArrayEquals(input.longs, result.longs); + assertArrayEquals(input.floats, result.floats, 0.0001f); + assertArrayEquals(input.doubles, result.doubles, 0.0000001); + } +} \ No newline at end of file diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index bce4274e..97e59c76 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -75,3 +75,8 @@ Giovanni van der Schelde (@Giovds) * Reported, suggested a fix for #167: Deserialization of record fails on constructor parameter ordering (2.18.1) + +Luke Hutchison (@lukehutch) + +* Reported #196: `float[]` and `double[]` are serialized to JSON as `{ }` + (2.20.0) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index a7a7ce7b..c024a4f9 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -11,6 +11,9 @@ Modules: === Releases === ------------------------------------------------------------------------ +#196: `float[]` and `double[]` are serialized to JSON as `{ }` + (reported by Luke H) + 2.20.0-rc1 (04-Aug-2025) No changes since 2.19 From 0e4e59d81abbf8427d382a5290319d5cb6ea279c Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Aug 2025 15:52:57 -0700 Subject: [PATCH 2/7] ... --- .../jackson/jr/ob/PrimitiveArrayTest.java | 32 ++++++++++++------- release-notes/VERSION-2.x | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java index fafb32ee..f18025c8 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java @@ -53,24 +53,34 @@ public void testShortArrayRead() throws Exception { } @Test - public void testShortArrayArrayWrite() throws Exception { + public void testShortArrayWrite() throws Exception { assertEquals(SHORT_ARRAY_JSON, JSON.std.asString(SHORT_ARRAY)); } + private final static String INT_ARRAY_JSON = "[1,2,-2000,1000000,-999999999]"; + private final static int[] INT_ARRAY = new int[] {1,2,-2000,1000000,-999999999}; + @Test - public void testIntArray() throws Exception { - final int[] input = new int[]{1, 2, 3, 25, 999}; - String json = JSON.std.asString(input); - int[] result = JSON.std.beanFrom(int[].class, json); - assertArrayEquals(input, result); + public void testIntArrayRead() throws Exception { + assertArrayEquals(INT_ARRAY, JSON.std.beanFrom(int[].class, INT_ARRAY_JSON)); } @Test - public void testLongArray() throws Exception { - final long[] input = new long[]{1L, 2L, 3L, 999999999999L, -999999999999L}; - String json = JSON.std.asString(input); - long[] result = JSON.std.beanFrom(long[].class, json); - assertArrayEquals(input, result); + public void testIntArrayWrite() throws Exception { + assertEquals(INT_ARRAY_JSON, JSON.std.asString(INT_ARRAY)); + } + + private final static String LONG_ARRAY_JSON = "[1,-2,3,999999999999,-999999999999]"; + private final static long[] LONG_ARRAY = new long[] {1L,-2L,3L,999999999999L,-999999999999L}; + + @Test + public void testLongArrayRead() throws Exception { + assertArrayEquals(LONG_ARRAY, JSON.std.beanFrom(long[].class, LONG_ARRAY_JSON)); + } + + @Test + public void testLongArrayWrite() throws Exception { + assertEquals(LONG_ARRAY_JSON, JSON.std.asString(LONG_ARRAY)); } @Test diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index c024a4f9..29b367a5 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -12,7 +12,7 @@ Modules: ------------------------------------------------------------------------ #196: `float[]` and `double[]` are serialized to JSON as `{ }` - (reported by Luke H) + (contributed by Luke H) 2.20.0-rc1 (04-Aug-2025) From 62a3fda73b7023b5f60cab040300e7977d02aae5 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Aug 2025 16:56:18 -0700 Subject: [PATCH 3/7] Hack tests into submission --- .../jackson/jr/ob/PrimitiveArrayTest.java | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java index f18025c8..9ea7826d 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java @@ -15,6 +15,8 @@ public class PrimitiveArrayTest extends TestBase private final static String BOOLEAN_ARRAY_JSON = "[true,false,true,false,true]"; private final static boolean[] BOOLEAN_ARRAY = new boolean[] { true, false, true, false, true }; + // Not yet implemented in Jackson-jr + @JacksonTestFailureExpected @Test public void testBooleanArrayRead() throws Exception { assertArrayEquals(BOOLEAN_ARRAY, JSON.std.beanFrom(boolean[].class, BOOLEAN_ARRAY_JSON)); @@ -46,6 +48,7 @@ public void testCharArray() throws Exception { private final static String SHORT_ARRAY_JSON = "[1,2,3,32767,-32768]"; private final static short[] SHORT_ARRAY = new short[] { 1, 2, 3, 32767, -32768 }; + // Not yet implemented in Jackson-jr @JacksonTestFailureExpected @Test public void testShortArrayRead() throws Exception { @@ -83,23 +86,41 @@ public void testLongArrayWrite() throws Exception { assertEquals(LONG_ARRAY_JSON, JSON.std.asString(LONG_ARRAY)); } + private final static String FLOAT_ARRAY_JSON = "[1.0,2.5,3.125,-5.5,0.0]"; + private final static float[] FLOAT_ARRAY = new float[] {1.0f, 2.5f, 3.125f, -5.5f, 0.0f}; + + // Not yet implemented in Jackson-jr + @JacksonTestFailureExpected @Test - public void testFloatArray() throws Exception { - final float[] input = new float[]{1.0f, 2.5f, 3.14f, -5.5f, 0.0f}; - String json = JSON.std.asString(input); - float[] result = JSON.std.beanFrom(float[].class, json); - assertArrayEquals(input, result, 0.0001f); + public void testFloatArrayRead() throws Exception { + assertArrayEquals(FLOAT_ARRAY, JSON.std.beanFrom(float[].class, FLOAT_ARRAY_JSON), + 0.00001f); } @Test - public void testDoubleArray() throws Exception { - final double[] input = new double[]{1.0, 2.5, 3.14159, -5.5, 0.0}; - String json = JSON.std.asString(input); - double[] result = JSON.std.beanFrom(double[].class, json); - assertArrayEquals(input, result, 0.0000001); + public void testFloatArrayWrite() throws Exception { + assertEquals(FLOAT_ARRAY_JSON, JSON.std.asString(FLOAT_ARRAY)); + } + + private final static String DOUBLE_ARRAY_JSON = "[0.5,-2.25,3.14159,-5.5,0.0]"; + private final static double[] DOUBLE_ARRAY = new double[] {0.5, -2.25, 3.14159, -5.5f, 0.0}; + + // Not yet implemented in Jackson-jr + @JacksonTestFailureExpected + @Test + public void testDoubleArrayRead() throws Exception { + assertArrayEquals(DOUBLE_ARRAY, JSON.std.beanFrom(double[].class, DOUBLE_ARRAY_JSON), + 0.00001); + } + + @Test + public void testDoubleArrayWrite() throws Exception { + assertEquals(DOUBLE_ARRAY_JSON, JSON.std.asString(DOUBLE_ARRAY)); } // Test empty arrays + // Not yet implemented in Jackson-jr + @JacksonTestFailureExpected @Test public void testEmptyArrays() throws Exception { assertArrayEquals(new boolean[0], JSON.std.beanFrom(boolean[].class, "[]")); @@ -124,6 +145,8 @@ public static class AllArraysBean { public double[] doubles; } + // Not yet fully implemented in Jackson-jr + @JacksonTestFailureExpected @Test public void testArraysAsObjectFields() throws Exception { AllArraysBean input = new AllArraysBean(); From 023db390b834eed5b2a544f09feb73272ecf1b69 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Aug 2025 17:02:17 -0700 Subject: [PATCH 4/7] Re-order type constants --- .../jackson/jr/ob/impl/ValueLocatorBase.java | 72 +++++++++---------- .../jackson/jr/ob/PrimitiveArrayTest.java | 17 +++-- 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java index 61f56c32..e9a28d28 100644 --- a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java +++ b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueLocatorBase.java @@ -58,64 +58,64 @@ public abstract class ValueLocatorBase */ public final static int SER_OBJECT_ARRAY = 4; - public final static int SER_INT_ARRAY = 5; - public final static int SER_LONG_ARRAY = 6; - public final static int SER_BOOLEAN_ARRAY = 7; - public final static int SER_SHORT_ARRAY = 38; - public final static int SER_FLOAT_ARRAY = 39; - public final static int SER_DOUBLE_ARRAY = 40; + public final static int SER_SHORT_ARRAY = 5; // since 2.20 + public final static int SER_INT_ARRAY = 6; + public final static int SER_LONG_ARRAY = 7; + public final static int SER_FLOAT_ARRAY = 8; // since 2.20 + public final static int SER_DOUBLE_ARRAY = 9; // since 2.20 + public final static int SER_BOOLEAN_ARRAY = 10; /** * An implementation of {@link com.fasterxml.jackson.core.TreeNode} */ - public final static int SER_TREE_NODE = 8; + public final static int SER_TREE_NODE = 11; // // // String(-like) types - public final static int SER_STRING = 9; - public final static int SER_CHARACTER_SEQUENCE = 10; - public final static int SER_CHAR_ARRAY = 11; - public final static int SER_BYTE_ARRAY = 12; + public final static int SER_STRING = 12; + public final static int SER_CHARACTER_SEQUENCE = 13; + public final static int SER_CHAR_ARRAY = 14; + public final static int SER_BYTE_ARRAY = 15; // // // Numbers - public final static int SER_NUMBER_BYTE = 13; + public final static int SER_NUMBER_BYTE = 16; - public final static int SER_NUMBER_SHORT = 14; + public final static int SER_NUMBER_SHORT = 17; - public final static int SER_NUMBER_INTEGER = 15; - public final static int SER_NUMBER_INTEGER_WRAPPER = 16; + public final static int SER_NUMBER_INTEGER = 18; + public final static int SER_NUMBER_INTEGER_WRAPPER = 19; - public final static int SER_NUMBER_LONG = 17; - public final static int SER_NUMBER_LONG_WRAPPER = 18; + public final static int SER_NUMBER_LONG = 20; + public final static int SER_NUMBER_LONG_WRAPPER = 21; - public final static int SER_NUMBER_FLOAT = 19; - public final static int SER_NUMBER_FLOAT_WRAPPER = 20; + public final static int SER_NUMBER_FLOAT = 22; + public final static int SER_NUMBER_FLOAT_WRAPPER = 23; - public final static int SER_NUMBER_DOUBLE = 21; - public final static int SER_NUMBER_DOUBLE_WRAPPER = 22; + public final static int SER_NUMBER_DOUBLE = 24; + public final static int SER_NUMBER_DOUBLE_WRAPPER = 25; - public final static int SER_NUMBER_BIG_INTEGER = 23; + public final static int SER_NUMBER_BIG_INTEGER = 26; - public final static int SER_NUMBER_BIG_DECIMAL = 24; + public final static int SER_NUMBER_BIG_DECIMAL = 27; // // // Other specific scalar types - public final static int SER_BOOLEAN = 25; - public final static int SER_BOOLEAN_WRAPPER = 26; - public final static int SER_CHAR = 27; + public final static int SER_BOOLEAN = 28; + public final static int SER_BOOLEAN_WRAPPER = 29; + public final static int SER_CHAR = 30; - public final static int SER_ENUM = 28; + public final static int SER_ENUM = 31; - public final static int SER_DATE = 29; - public final static int SER_CALENDAR = 30; + public final static int SER_DATE = 32; + public final static int SER_CALENDAR = 33; - public final static int SER_CLASS = 31; - public final static int SER_FILE = 32; - public final static int SER_UUID = 33; - public final static int SER_URL = 34; - public final static int SER_URI = 35; - public final static int SER_PATH = 36; // since 2.17 + public final static int SER_CLASS = 34; + public final static int SER_FILE = 35; + public final static int SER_UUID = 36; + public final static int SER_URL = 37; + public final static int SER_URI = 38; + public final static int SER_PATH = 39; // since 2.17 // // // Iterate-able types @@ -123,7 +123,7 @@ public abstract class ValueLocatorBase * Anything that implements {@link java.lang.Iterable}, but not * {@link java.util.Collection}. */ - public final static int SER_ITERABLE = 37; + public final static int SER_ITERABLE = 40; /* /********************************************************************** diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java index 9ea7826d..741d57f2 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java @@ -120,19 +120,24 @@ public void testDoubleArrayWrite() throws Exception { // Test empty arrays // Not yet implemented in Jackson-jr - @JacksonTestFailureExpected @Test public void testEmptyArrays() throws Exception { - assertArrayEquals(new boolean[0], JSON.std.beanFrom(boolean[].class, "[]")); - assertArrayEquals(new byte[0], JSON.std.beanFrom(byte[].class, "[]")); assertArrayEquals(new char[0], JSON.std.beanFrom(char[].class, "\"\"")); - assertArrayEquals(new short[0], JSON.std.beanFrom(short[].class, "[]")); assertArrayEquals(new int[0], JSON.std.beanFrom(int[].class, "[]")); assertArrayEquals(new long[0], JSON.std.beanFrom(long[].class, "[]")); + } + + // Not yet implemented in Jackson-jr + @JacksonTestFailureExpected + @Test + public void testEmptyArraysFailing() throws Exception { + assertArrayEquals(new boolean[0], JSON.std.beanFrom(boolean[].class, "[]")); + assertArrayEquals(new byte[0], JSON.std.beanFrom(byte[].class, "[]")); + assertArrayEquals(new short[0], JSON.std.beanFrom(short[].class, "[]")); assertArrayEquals(new float[0], JSON.std.beanFrom(float[].class, "[]"), 0.0f); assertArrayEquals(new double[0], JSON.std.beanFrom(double[].class, "[]"), 0.0); } - + // Test arrays as object fields public static class AllArraysBean { public boolean[] booleans; @@ -171,4 +176,4 @@ public void testArraysAsObjectFields() throws Exception { assertArrayEquals(input.floats, result.floats, 0.0001f); assertArrayEquals(input.doubles, result.doubles, 0.0000001); } -} \ No newline at end of file +} From fa7b6979cd3795815978315e1184c360dce91e06 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Fri, 15 Aug 2025 17:07:01 -0700 Subject: [PATCH 5/7] ... --- .../jackson/jr/ob/PrimitiveArrayTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java index 741d57f2..f1639125 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java @@ -9,6 +9,18 @@ public class PrimitiveArrayTest extends TestBase { + // Test arrays as object fields + static class AllArraysBean { + public boolean[] booleans; + public byte[] bytes; + public char[] chars; + public short[] shorts; + public int[] ints; + public long[] longs; + public float[] floats; + public double[] doubles; + } + // Test all 7 primitive array types: boolean[], byte[], short[], int[], long[], float[], double[] // Also test char[] which is handled specially (as String) @@ -137,18 +149,6 @@ public void testEmptyArraysFailing() throws Exception { assertArrayEquals(new float[0], JSON.std.beanFrom(float[].class, "[]"), 0.0f); assertArrayEquals(new double[0], JSON.std.beanFrom(double[].class, "[]"), 0.0); } - - // Test arrays as object fields - public static class AllArraysBean { - public boolean[] booleans; - public byte[] bytes; - public char[] chars; - public short[] shorts; - public int[] ints; - public long[] longs; - public float[] floats; - public double[] doubles; - } // Not yet fully implemented in Jackson-jr @JacksonTestFailureExpected From 0ef3fcd7461fbaa57e8d3d537434cc7570c94954 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 17 Aug 2025 09:40:33 -0700 Subject: [PATCH 6/7] Use more optimal array-writing methods --- .../jackson/jr/ob/impl/JSONWriter.java | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java index 59055738..492ee022 100644 --- a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java +++ b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/JSONWriter.java @@ -445,7 +445,11 @@ protected void _writeValue(Object value, int type) throws IOException protected void writeCollectionValue(Collection v) throws IOException { - _generator.writeStartArray(); + if (v instanceof RandomAccess) { + _generator.writeStartArray(v, v.size()); + } else { + _generator.writeStartArray(v); + } for (Object ob : v) { writeValue(ob); } @@ -460,7 +464,7 @@ protected void writeCollectionField(String fieldName, Collection v) throws IO protected void writeIterableValue(Iterable v) throws IOException { - _generator.writeStartArray(); + _generator.writeStartArray(v); for (Object ob : v) { writeValue(ob); } @@ -475,7 +479,11 @@ protected void writeIterableField(String fieldName, Iterable v) throws IOExce protected void writeListValue(List list) throws IOException { - _generator.writeStartArray(); + if (list instanceof RandomAccess) { + _generator.writeStartArray(list, list.size()); + } else { + _generator.writeStartArray(list); + } for (int i = 0, len = list.size(); i < len; ++i) { Object value = list.get(i); if (value == null) { @@ -495,7 +503,7 @@ protected void writeListField(String fieldName, List v) throws IOException protected void writeMapValue(Map v) throws IOException { - _generator.writeStartObject(); + _generator.writeStartObject(v, v.size()); if (!v.isEmpty()) { for (Map.Entry entry : v.entrySet()) { String key = keyToString(entry.getKey()); @@ -522,8 +530,9 @@ protected void writeMapField(String fieldName, Map v) throws IOException } protected void writeObjectArrayValue(Object[] v) throws IOException { - _generator.writeStartArray(); - for (int i = 0, len = v.length; i < len; ++i) { + final int len = v.length; + _generator.writeStartArray(v, len); + for (int i = 0; i < len; ++i) { writeValue(v[i]); } _generator.writeEndArray(); @@ -535,11 +544,7 @@ protected void writeObjectArrayField(String fieldName, Object[] v) throws IOExce } protected void writeIntArrayValue(int[] v) throws IOException { - _generator.writeStartArray(); - for (int i = 0, len = v.length; i < len; ++i) { - _generator.writeNumber(v[i]); - } - _generator.writeEndArray(); + _generator.writeArray(v, 0, v.length); } protected void writeIntArrayField(String fieldName, int[] v) throws IOException { @@ -548,11 +553,7 @@ protected void writeIntArrayField(String fieldName, int[] v) throws IOException } protected void writeLongArrayValue(long[] v) throws IOException { - _generator.writeStartArray(); - for (int i = 0, len = v.length; i < len; ++i) { - _generator.writeNumber(v[i]); - } - _generator.writeEndArray(); + _generator.writeArray(v, 0, v.length); } protected void writeLongArrayField(String fieldName, long[] v) throws IOException { @@ -561,7 +562,7 @@ protected void writeLongArrayField(String fieldName, long[] v) throws IOExceptio } protected void writeBooleanArrayValue(boolean[] v) throws IOException { - _generator.writeStartArray(); + _generator.writeStartArray(v, v.length); for (int i = 0, len = v.length; i < len; ++i) { _generator.writeBoolean(v[i]); } @@ -574,7 +575,7 @@ protected void writeBooleanArrayField(String fieldName, boolean[] v) throws IOEx } protected void writeShortArrayValue(short[] v) throws IOException { - _generator.writeStartArray(); + _generator.writeStartArray(v, v.length); for (int i = 0, len = v.length; i < len; ++i) { _generator.writeNumber(v[i]); } @@ -587,7 +588,7 @@ protected void writeShortArrayField(String fieldName, short[] v) throws IOExcept } protected void writeFloatArrayValue(float[] v) throws IOException { - _generator.writeStartArray(); + _generator.writeStartArray(v, v.length); for (int i = 0, len = v.length; i < len; ++i) { _generator.writeNumber(v[i]); } @@ -600,11 +601,7 @@ protected void writeFloatArrayField(String fieldName, float[] v) throws IOExcept } protected void writeDoubleArrayValue(double[] v) throws IOException { - _generator.writeStartArray(); - for (int i = 0, len = v.length; i < len; ++i) { - _generator.writeNumber(v[i]); - } - _generator.writeEndArray(); + _generator.writeArray(v, 0, v.length); } protected void writeDoubleArrayField(String fieldName, double[] v) throws IOException { From 75f9a42b1b6d590ec6c76fbbcd1657252ca80ef7 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 17 Aug 2025 09:53:16 -0700 Subject: [PATCH 7/7] Improve error handling --- .../jackson/jr/ob/api/ValueReader.java | 10 ++++++ .../jackson/jr/ob/impl/SimpleValueReader.java | 15 +++++--- .../jackson/jr/ob/PrimitiveArrayTest.java | 35 ++++++++++++++----- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/api/ValueReader.java b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/api/ValueReader.java index a50081cb..deee759d 100644 --- a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/api/ValueReader.java +++ b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/api/ValueReader.java @@ -81,6 +81,16 @@ public Class valueType() { /********************************************************************** */ + /** + * Helper method for getting description of type of values this reader + * produces from input: used for example in exception messages. + * + * @since 2.20 + */ + protected String _valueTypeDesc() { + return _valueType.getCanonicalName(); + } + /** * Helper method for getting description of the token parser currently points to, * for use in descriptions and exception messages. diff --git a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/SimpleValueReader.java b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/SimpleValueReader.java index 138ed249..00460236 100644 --- a/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/SimpleValueReader.java +++ b/jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/SimpleValueReader.java @@ -114,9 +114,14 @@ public Object read(JSONReader reader, JsonParser p) throws IOException return _readIntArray(p); case SER_LONG_ARRAY: return _readLongArray(p); - //case SER_BOOLEAN_ARRAY: - // TODO: - + + // Not yet supported: + case SER_BOOLEAN_ARRAY: + case SER_SHORT_ARRAY: + case SER_FLOAT_ARRAY: + case SER_DOUBLE_ARRAY: + throw JSONObjectException.from(p, + "Deserialization of `"+_valueTypeDesc()+"` not yet supported"); case SER_TREE_NODE: return reader.readTree(); @@ -271,7 +276,7 @@ public Object read(JSONReader reader, JsonParser p) throws IOException } throw JSONObjectException.from(p, - "Can not create a `"+_valueType.getName()+"` instance out of "+_tokenDesc(p)); + "Can not create a `"+_valueTypeDesc()+"` instance out of "+_tokenDesc(p)); } /* @@ -374,6 +379,6 @@ protected long _fetchLong(JsonParser p) throws IOException return p.getLongValue(); } throw JSONObjectException.from(p, "Can not get long numeric value from JSON (to construct " - +_valueType.getName()+") from "+_tokenDesc(p, t)); + +_valueTypeDesc()+") from "+_tokenDesc(p, t)); } } diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java index f1639125..9e697f9f 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/PrimitiveArrayTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; public class PrimitiveArrayTest extends TestBase { @@ -61,10 +62,15 @@ public void testCharArray() throws Exception { private final static short[] SHORT_ARRAY = new short[] { 1, 2, 3, 32767, -32768 }; // Not yet implemented in Jackson-jr - @JacksonTestFailureExpected @Test public void testShortArrayRead() throws Exception { - assertArrayEquals(SHORT_ARRAY, JSON.std.beanFrom(short[].class, SHORT_ARRAY_JSON)); +// assertArrayEquals(SHORT_ARRAY, JSON.std.beanFrom(short[].class, SHORT_ARRAY_JSON)); + try { + JSON.std.beanFrom(short[].class, SHORT_ARRAY_JSON); + fail("Should not pass"); + } catch (JSONObjectException e) { + verifyException(e, "Deserialization of `short[]` not yet supported"); + } } @Test @@ -102,11 +108,17 @@ public void testLongArrayWrite() throws Exception { private final static float[] FLOAT_ARRAY = new float[] {1.0f, 2.5f, 3.125f, -5.5f, 0.0f}; // Not yet implemented in Jackson-jr - @JacksonTestFailureExpected @Test public void testFloatArrayRead() throws Exception { - assertArrayEquals(FLOAT_ARRAY, JSON.std.beanFrom(float[].class, FLOAT_ARRAY_JSON), - 0.00001f); + //assertArrayEquals(FLOAT_ARRAY, JSON.std.beanFrom(float[].class, FLOAT_ARRAY_JSON), + // 0.00001f); + + try { + JSON.std.beanFrom(float[].class, FLOAT_ARRAY_JSON); + fail("Should not pass"); + } catch (JSONObjectException e) { + verifyException(e, "Deserialization of `float[]` not yet supported"); + } } @Test @@ -117,12 +129,17 @@ public void testFloatArrayWrite() throws Exception { private final static String DOUBLE_ARRAY_JSON = "[0.5,-2.25,3.14159,-5.5,0.0]"; private final static double[] DOUBLE_ARRAY = new double[] {0.5, -2.25, 3.14159, -5.5f, 0.0}; - // Not yet implemented in Jackson-jr - @JacksonTestFailureExpected @Test public void testDoubleArrayRead() throws Exception { - assertArrayEquals(DOUBLE_ARRAY, JSON.std.beanFrom(double[].class, DOUBLE_ARRAY_JSON), - 0.00001); + //assertArrayEquals(DOUBLE_ARRAY, JSON.std.beanFrom(double[].class, DOUBLE_ARRAY_JSON), + // 0.00001); + + try { + JSON.std.beanFrom(double[].class, DOUBLE_ARRAY_JSON); + fail("Should not pass"); + } catch (JSONObjectException e) { + verifyException(e, "Deserialization of `double[]` not yet supported"); + } } @Test