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 ed8fefba..567fc3b2 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 @@ -217,16 +217,24 @@ public void writeField(String fieldName, Object value, int type) throws IOExcept writeBigIntegerField(fieldName, (BigInteger) value); return; case SER_NUMBER_FLOAT: // fall through + case SER_NUMBER_FLOAT_WRAPPER: + writeFloatField(fieldName, ((Float) value).floatValue()); + return; case SER_NUMBER_DOUBLE: - writeDoubleField(fieldName, ((Number) value).doubleValue()); + case SER_NUMBER_DOUBLE_WRAPPER: + writeDoubleField(fieldName, ((Double) value).doubleValue()); return; case SER_NUMBER_BYTE: // fall through case SER_NUMBER_SHORT: // fall through - case SER_NUMBER_INTEGER: writeIntField(fieldName, ((Number) value).intValue()); return; + case SER_NUMBER_INTEGER: + case SER_NUMBER_INTEGER_WRAPPER: + writeIntField(fieldName, ((Integer) value).intValue()); + return; case SER_NUMBER_LONG: - writeLongField(fieldName, ((Number) value).longValue()); + case SER_NUMBER_LONG_WRAPPER: + writeLongField(fieldName, ((Long) value).longValue()); return; // Scalar types: @@ -328,16 +336,24 @@ protected void _writeValue(Object value, int type) throws IOException // Number types: case SER_NUMBER_FLOAT: // fall through + case SER_NUMBER_FLOAT_WRAPPER: // fall through + writeFloatValue(((Float) value).floatValue()); + return; case SER_NUMBER_DOUBLE: - writeDoubleValue(((Number) value).doubleValue()); + case SER_NUMBER_DOUBLE_WRAPPER: + writeDoubleValue(((Double) value).doubleValue()); return; case SER_NUMBER_BYTE: // fall through case SER_NUMBER_SHORT: // fall through - case SER_NUMBER_INTEGER: writeIntValue(((Number) value).intValue()); return; + case SER_NUMBER_INTEGER: + case SER_NUMBER_INTEGER_WRAPPER: + writeIntValue(((Integer) value).intValue()); + return; case SER_NUMBER_LONG: - writeLongValue(((Number) value).longValue()); + case SER_NUMBER_LONG_WRAPPER: + writeLongValue(((Long) value).longValue()); return; case SER_NUMBER_BIG_DECIMAL: writeBigDecimalValue((BigDecimal) value); @@ -584,6 +600,14 @@ protected void writeLongField(String fieldName, long v) throws IOException { _generator.writeNumberField(fieldName, v); } + protected void writeFloatValue(float v) throws IOException { + _generator.writeNumber(v); + } + + protected void writeFloatField(String fieldName, float v) throws IOException { + _generator.writeNumberField(fieldName, v); + } + protected void writeDoubleValue(double v) throws IOException { _generator.writeNumber(v); } 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 57438ee4..582adaf6 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 @@ -60,6 +60,7 @@ public Object readNext(JSONReader reader, JsonParser p) throws IOException // cases default to "standard" handling which does range checks etc case SER_NUMBER_INTEGER: + case SER_NUMBER_INTEGER_WRAPPER: { int i = p.nextIntValue(-2); if (i != -2) { @@ -69,6 +70,7 @@ public Object readNext(JSONReader reader, JsonParser p) throws IOException } case SER_NUMBER_LONG: + case SER_NUMBER_LONG_WRAPPER: { long l = p.nextLongValue(-2L); if (l != -2L) { @@ -116,8 +118,16 @@ public Object read(JSONReader reader, JsonParser p) throws IOException // Number types: - case SER_NUMBER_FLOAT: // fall through + case SER_NUMBER_FLOAT_WRAPPER: + if (p.hasToken(JsonToken.VALUE_NULL)) { + return null; + } + case SER_NUMBER_FLOAT: return Float.valueOf((float) p.getValueAsDouble()); + case SER_NUMBER_DOUBLE_WRAPPER: + if (p.hasToken(JsonToken.VALUE_NULL)) { + return null; + } case SER_NUMBER_DOUBLE: return p.getValueAsDouble(); @@ -126,8 +136,16 @@ public Object read(JSONReader reader, JsonParser p) throws IOException case SER_NUMBER_SHORT: // fall through return (short) p.getValueAsInt(); + case SER_NUMBER_INTEGER_WRAPPER: + if (p.hasToken(JsonToken.VALUE_NULL)) { + return null; + } case SER_NUMBER_INTEGER: return p.getValueAsInt(); + case SER_NUMBER_LONG_WRAPPER: + if (p.hasToken(JsonToken.VALUE_NULL)) { + return null; + } case SER_NUMBER_LONG: return p.getValueAsLong(); 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 f7bf0a6a..05421f33 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 @@ -78,35 +78,39 @@ public abstract class ValueLocatorBase public final static int SER_NUMBER_BYTE = 13; public final static int SER_NUMBER_SHORT = 14; - + public final static int SER_NUMBER_INTEGER = 15; + public final static int SER_NUMBER_INTEGER_WRAPPER = 16; - public final static int SER_NUMBER_LONG = 16; + public final static int SER_NUMBER_LONG = 17; + public final static int SER_NUMBER_LONG_WRAPPER = 18; - public final static int SER_NUMBER_FLOAT = 17; + public final static int SER_NUMBER_FLOAT = 19; + public final static int SER_NUMBER_FLOAT_WRAPPER = 20; - public final static int SER_NUMBER_DOUBLE = 18; + public final static int SER_NUMBER_DOUBLE = 21; + public final static int SER_NUMBER_DOUBLE_WRAPPER = 22; - public final static int SER_NUMBER_BIG_INTEGER = 19; + public final static int SER_NUMBER_BIG_INTEGER = 23; - public final static int SER_NUMBER_BIG_DECIMAL = 20; + public final static int SER_NUMBER_BIG_DECIMAL = 24; // // // Other specific scalar types - public final static int SER_BOOLEAN = 21; - public final static int SER_BOOLEAN_WRAPPER = 22; - public final static int SER_CHAR = 23; + 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_ENUM = 24; + public final static int SER_ENUM = 28; - public final static int SER_DATE = 25; - public final static int SER_CALENDAR = 26; + public final static int SER_DATE = 29; + public final static int SER_CALENDAR = 30; - public final static int SER_CLASS = 27; - public final static int SER_FILE = 28; - public final static int SER_UUID = 29; - public final static int SER_URL = 30; - public final static int SER_URI = 31; + 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; // // // Iterate-able types @@ -115,7 +119,7 @@ public abstract class ValueLocatorBase * Anything that implements {@link java.lang.Iterable}, but not * {@link java.util.Collection}. */ - public final static int SER_ITERABLE = 32; + public final static int SER_ITERABLE = 36; /* /********************************************************************** @@ -174,16 +178,16 @@ protected int _findSimpleType(Class raw, boolean forSer) return SER_BOOLEAN_WRAPPER; } if (Number.class.isAssignableFrom(raw)) { - if (raw == Integer.class) return SER_NUMBER_INTEGER; - if (raw == Long.class) return SER_NUMBER_LONG; - if (raw == Byte.class) return SER_NUMBER_BYTE; - if (raw == Short.class) return SER_NUMBER_SHORT; - if (raw == Double.class) return SER_NUMBER_DOUBLE; - if (raw == Float.class) return SER_NUMBER_FLOAT; + if (raw == Integer.class) return SER_NUMBER_INTEGER_WRAPPER; + if (raw == Long.class) return SER_NUMBER_LONG_WRAPPER; + if (raw == Double.class) return SER_NUMBER_DOUBLE_WRAPPER; + if (raw == Float.class) return SER_NUMBER_FLOAT_WRAPPER; if (raw == BigDecimal.class) return SER_NUMBER_BIG_DECIMAL; if (raw == BigInteger.class) { return SER_NUMBER_BIG_INTEGER; } + if (raw == Byte.class) return SER_NUMBER_BYTE; + if (raw == Short.class) return SER_NUMBER_SHORT; // What numeric type is this? Could consider "string-like" but... return SER_UNKNOWN; } diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/failing/NullHandling78Test.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/failing/NullHandling78Test.java deleted file mode 100644 index f44b1ceb..00000000 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/failing/NullHandling78Test.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.fasterxml.jackson.jr.failing; - -import com.fasterxml.jackson.jr.ob.JSON; -import com.fasterxml.jackson.jr.ob.TestBase; - -public class NullHandling78Test extends TestBase -{ - // [jackson-jr#78] - static class IntegerWrapper { - public Integer value; - } - static class IntPrimitiveWrapper { - public int value; - } - static class LongWrapper { - public Long value; - } - static class LongPrimitiveWrapper { - public long value; - } - static class DoubleWrapper { - public Double value; - } - static class DoublePrimitiveWrapper { - public double value; - } - - // [jackson-jr#78], int/Integer - - public void testIntPrimitive() throws Exception - { - IntPrimitiveWrapper w = JSON.std.beanFrom(IntPrimitiveWrapper.class, - a2q("{'value':1}")); - assertEquals(1, w.value); - - w = JSON.std.beanFrom(IntPrimitiveWrapper.class, - a2q("{'value':null}")); - assertEquals(0, w.value); - } - - public void testIntWrapper() throws Exception - { - IntegerWrapper w = JSON.std.beanFrom(IntegerWrapper.class, - a2q("{'value':1}")); - assertEquals(Integer.valueOf(1), w.value); - - w = JSON.std.beanFrom(IntegerWrapper.class, - a2q("{'value':null}")); - assertNull(w.value); - } - - // [jackson-jr#78], long/Long - - public void testLongPrimitive() throws Exception - { - LongPrimitiveWrapper w = JSON.std.beanFrom(LongPrimitiveWrapper.class, - a2q("{'value':2}")); - assertEquals(2L, w.value); - - w = JSON.std.beanFrom(LongPrimitiveWrapper.class, - a2q("{'value':null}")); - assertEquals(0L, w.value); - } - - public void testLongWrapper() throws Exception - { - LongWrapper w = JSON.std.beanFrom(LongWrapper.class, - a2q("{'value':2}")); - assertEquals(Long.valueOf(2L), w.value); - - w = JSON.std.beanFrom(LongWrapper.class, - a2q("{'value':null}")); - assertNull(w.value); - } - - // [jackson-jr#78], boolean/Boolean - - public void testDoublePrimitive() throws Exception - { - DoublePrimitiveWrapper w = JSON.std.beanFrom(DoublePrimitiveWrapper.class, - a2q("{'value':0.25}")); - assertEquals(0.25, w.value); - - w = JSON.std.beanFrom(DoublePrimitiveWrapper.class, - a2q("{'value':null}")); - // yeah yeah, not kosher wrt epsilon etc but... - assertEquals(0.0, w.value); - } - - public void testDoubleWrapper() throws Exception - { - DoubleWrapper w = JSON.std.beanFrom(DoubleWrapper.class, - a2q("{'value':0.25}")); - assertEquals(Double.valueOf(0.25), w.value); - - w = JSON.std.beanFrom(DoubleWrapper.class, - a2q("{'value':null}")); - assertNull(w.value); - } -} diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/NullHandlingTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/NullHandlingTest.java index b4896907..b7c7ea8b 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/NullHandlingTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/NullHandlingTest.java @@ -13,6 +13,32 @@ static class StringBean { public String str = "a"; } + // [jackson-jr#78] + static class IntegerWrapper { + public Integer value; + } + static class IntPrimitiveWrapper { + public int value; + } + static class LongWrapper { + public Long value; + } + static class LongPrimitiveWrapper { + public long value; + } + static class FloatWrapper { + public Float value; + } + static class FloatPrimitiveWrapper { + public float value; + } + static class DoubleWrapper { + public Double value; + } + static class DoublePrimitiveWrapper { + public double value; + } + static class BooleanWrapper { public Boolean value; } @@ -50,6 +76,103 @@ public void testNullForByteArray() throws Exception assertNull(bean.b); } + // [jackson-jr#78], int/Integer + + public void testIntPrimitive() throws Exception + { + IntPrimitiveWrapper w = JSON.std.beanFrom(IntPrimitiveWrapper.class, + a2q("{'value':1}")); + assertEquals(1, w.value); + + w = JSON.std.beanFrom(IntPrimitiveWrapper.class, + a2q("{'value':null}")); + assertEquals(0, w.value); + } + + public void testIntWrapper() throws Exception + { + IntegerWrapper w = JSON.std.beanFrom(IntegerWrapper.class, + a2q("{'value':1}")); + assertEquals(Integer.valueOf(1), w.value); + + w = JSON.std.beanFrom(IntegerWrapper.class, + a2q("{'value':null}")); + assertNull(w.value); + } + + // [jackson-jr#78], long/Long + + public void testLongPrimitive() throws Exception + { + LongPrimitiveWrapper w = JSON.std.beanFrom(LongPrimitiveWrapper.class, + a2q("{'value':2}")); + assertEquals(2L, w.value); + + w = JSON.std.beanFrom(LongPrimitiveWrapper.class, + a2q("{'value':null}")); + assertEquals(0L, w.value); + } + + public void testLongWrapper() throws Exception + { + LongWrapper w = JSON.std.beanFrom(LongWrapper.class, + a2q("{'value':2}")); + assertEquals(Long.valueOf(2L), w.value); + + w = JSON.std.beanFrom(LongWrapper.class, + a2q("{'value':null}")); + assertNull(w.value); + } + + // [jackson-jr#78], float/Float + + public void testFloatPrimitive() throws Exception + { + FloatPrimitiveWrapper w = JSON.std.beanFrom(FloatPrimitiveWrapper.class, + a2q("{'value':0.25}")); + assertEquals(0.25f, w.value); + + w = JSON.std.beanFrom(FloatPrimitiveWrapper.class, + a2q("{'value':null}")); + assertEquals(0.0f, w.value); + } + + public void testFloatWrapper() throws Exception + { + FloatWrapper w = JSON.std.beanFrom(FloatWrapper.class, + a2q("{'value':0.25}")); + assertEquals(Float.valueOf(0.25f), w.value); + + w = JSON.std.beanFrom(FloatWrapper.class, + a2q("{'value':null}")); + assertNull(w.value); + } + + // [jackson-jr#78], double/Double + + public void testDoublePrimitive() throws Exception + { + DoublePrimitiveWrapper w = JSON.std.beanFrom(DoublePrimitiveWrapper.class, + a2q("{'value':0.25}")); + assertEquals(0.25, w.value); + + w = JSON.std.beanFrom(DoublePrimitiveWrapper.class, + a2q("{'value':null}")); + // yeah yeah, not kosher wrt epsilon etc but... + assertEquals(0.0, w.value); + } + + public void testDoubleWrapper() throws Exception + { + DoubleWrapper w = JSON.std.beanFrom(DoubleWrapper.class, + a2q("{'value':0.25}")); + assertEquals(Double.valueOf(0.25), w.value); + + w = JSON.std.beanFrom(DoubleWrapper.class, + a2q("{'value':null}")); + assertNull(w.value); + } + // [jackson-jr#78], boolean/Boolean public void testBooleanPrimitive() throws Exception @@ -73,5 +196,4 @@ public void testBooleanWrapper() throws Exception a2q("{'value':null}")); assertNull(w.value); } - } diff --git a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/impl/ValueWriterLocatorTest.java b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/impl/ValueWriterLocatorTest.java index 0a73b116..68b1f6e7 100644 --- a/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/impl/ValueWriterLocatorTest.java +++ b/jr-objects/src/test/java/com/fasterxml/jackson/jr/ob/impl/ValueWriterLocatorTest.java @@ -54,9 +54,15 @@ public void testBasicTypeDetectionForSer() { assertEquals(ValueWriterLocator.SER_COLLECTION, td.findSerializationType(LinkedHashSet.class)); assertEquals(ValueWriterLocator.SER_LIST, td.findSerializationType(ArrayList.class)); - assertEquals(ValueWriterLocator.SER_NUMBER_INTEGER, td.findSerializationType(Integer.class)); assertEquals(ValueWriterLocator.SER_NUMBER_INTEGER, td.findSerializationType(Integer.TYPE)); + assertEquals(ValueWriterLocator.SER_NUMBER_INTEGER_WRAPPER, td.findSerializationType(Integer.class)); + + assertEquals(ValueWriterLocator.SER_NUMBER_LONG, td.findSerializationType(Long.TYPE)); + assertEquals(ValueWriterLocator.SER_NUMBER_LONG_WRAPPER, td.findSerializationType(Long.class)); + assertEquals(ValueWriterLocator.SER_NUMBER_DOUBLE, td.findSerializationType(Double.TYPE)); + assertEquals(ValueWriterLocator.SER_NUMBER_DOUBLE_WRAPPER, td.findSerializationType(Double.class)); + // more specific types assertEquals(ValueWriterLocator.SER_CALENDAR, td.findSerializationType(Calendar.class)); assertEquals(ValueWriterLocator.SER_CALENDAR, td.findSerializationType(GregorianCalendar.class)); diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 59b09a39..144c61e6 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -13,7 +13,8 @@ Modules: 2.17.0 (not yet released) -- +#78: Deserializes "null" to "0.0" for `java.lang.Double` (wrapper) + (reported by @bill-phast) 2.16.1 (24-Dec-2023)