Repository: johnzon Updated Branches: refs/heads/master f784faf2c -> 50b8fc3e8
JOHNZON-177 blow up if java type range is exceeded thanks to Markus Bruckner for the report! Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/50b8fc3e Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/50b8fc3e Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/50b8fc3e Branch: refs/heads/master Commit: 50b8fc3e84678d0266530e47c1c3372255cfc469 Parents: f784faf Author: Mark Struberg <[email protected]> Authored: Wed Jul 18 21:50:05 2018 +0200 Committer: Mark Struberg <[email protected]> Committed: Wed Jul 18 21:53:51 2018 +0200 ---------------------------------------------------------------------- .../org/apache/johnzon/core/JsonLongImpl.java | 6 +- .../johnzon/mapper/MappingParserImpl.java | 36 +++--- .../org/apache/johnzon/mapper/MapperTest.java | 115 ++++++++++++++----- 3 files changed, 113 insertions(+), 44 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/50b8fc3e/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java index 5428a87..7637512 100644 --- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java @@ -48,7 +48,11 @@ public final class JsonLongImpl implements JsonNumber, Serializable { @Override public int intValueExact() { - return intValue(); + int intVal = intValue(); + if (intVal != value) { + throw new java.lang.ArithmeticException("Overflow"); + } + return intVal; } @Override http://git-wip-us.apache.org/repos/asf/johnzon/blob/50b8fc3e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java index c16ce92..3dbc337 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java @@ -523,20 +523,8 @@ public class MappingParserImpl implements MappingParser { final JsonNumber number = JsonNumber.class.cast(jsonValue); - if (type == Integer.class || type == int.class) { - return number.intValue(); - } - if (type == Long.class || type == long.class) { - return number.longValue(); - } - - if (type == Short.class || type == short.class) { - return (short) number.intValue(); - } - - if (type == Byte.class || type == byte.class) { - return (byte) number.intValue(); + return number.longValueExact(); } if (type == Float.class || type == float.class) { @@ -554,6 +542,28 @@ public class MappingParserImpl implements MappingParser { if (type == BigDecimal.class) { return number.bigDecimalValue(); } + + int intValue = number.intValueExact(); + if (type == Integer.class || type == int.class) { + return intValue; + } + + if (type == Short.class || type == short.class) { + short shortVal = (short) intValue; + if (intValue != shortVal) { + throw new java.lang.ArithmeticException("Overflow"); + } + return shortVal; + } + + if (type == Byte.class || type == byte.class) { + byte byteVal = (byte) intValue; + if (intValue != byteVal) { + throw new java.lang.ArithmeticException("Overflow"); + } + return byteVal; + } + } else if (JsonString.class.isInstance(jsonValue)) { if (JsonString.class == type) { return jsonValue; http://git-wip-us.apache.org/repos/asf/johnzon/blob/50b8fc3e/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java index 8c8c4ce..dc06ea7 100644 --- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java +++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java @@ -21,6 +21,7 @@ package org.apache.johnzon.mapper; import org.apache.johnzon.mapper.access.FieldAccessMode; import org.apache.johnzon.mapper.reflection.JohnzonCollectionType; import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType; +import org.junit.Assert; import org.junit.Test; import java.beans.ConstructorProperties; @@ -29,6 +30,7 @@ import java.io.ByteArrayOutputStream; import java.io.StringReader; import java.io.StringWriter; import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -52,11 +54,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class MapperTest { - private static final String BIG_OBJECT_STR = "{" + "\"name\":\"the string\"," + "\"integer\":56," + "\"longnumber\":118," - + "\"bool\":true," + "\"nested\":{" + "\"name\":\"another value\"," + "\"integer\":97," + "\"longnumber\":34" + "}," - + "\"array\":[" + "{" + "\"name\":\"a1\"," + "\"integer\":1," + "\"longnumber\":2" + "}," + "{" + "\"name\":\"a2\"," - + "\"integer\":3," + "\"longnumber\":4" + "}" + "]," + "\"list\":[" + "{" + "\"name\":\"a3\"," + "\"integer\":5," - + "\"longnumber\":6" + "}," + "{" + "\"name\":\"a4\"," + "\"integer\":7," + "\"longnumber\":8" + "}" + "]," + private static final String BIG_OBJECT_STR = "{" + "\"name\":\"the string\"," + "\"intVal\":56," + "\"longnumber\":118," + + "\"bool\":true," + "\"nested\":{" + "\"name\":\"another value\"," + "\"intVal\":97," + "\"longnumber\":34" + "}," + + "\"array\":[" + "{" + "\"name\":\"a1\"," + "\"intVal\":1," + "\"longnumber\":2" + "}," + "{" + "\"name\":\"a2\"," + + "\"intVal\":3," + "\"longnumber\":4" + "}" + "]," + "\"list\":[" + "{" + "\"name\":\"a3\"," + "\"intVal\":5," + + "\"longnumber\":6" + "}," + "{" + "\"name\":\"a4\"," + "\"intVal\":7," + "\"longnumber\":8" + "}" + "]," + "\"primitives\":[1,2,3,4,5]," + "\"collectionWrapper\":[1,2,3,4,5]," + "\"map\":{\"uno\":true,\"duos\":false}" + "}"; @Test @@ -405,23 +407,58 @@ public class MapperTest { mapper.writeObject(bsr, writer); assertEquals(expectedJson, writer.toString()); } - + + /** + * Verify that assigning a short or byte number + * which is too big to fit into the java field + * does raise a MapperException. + */ + @Test + public void tooLongShortAndByte() { + Mapper mapper = new MapperBuilder().build(); + expectMapperException(() -> mapper.readObject("{\"numShort\":123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"numShort\":-123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"shortW\":123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"shortW\":-123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"numByte\":123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"numByte\":-123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"byteW\":123456}", ByteShort.class)); + expectMapperException(() -> mapper.readObject("{\"byteW\":-123456}", ByteShort.class)); + } + + /** + * Verify that assigning a long or int number + * which is too big to fit into the java field + * does raise a MapperException. + */ + @Test + public void tooLongIntAndLong() { + Mapper mapper = new MapperBuilder().build(); + String intCap = new BigDecimal(Integer.MAX_VALUE).add(new BigDecimal(2L)).toString(); + String longCap = new BigDecimal(Long.MAX_VALUE).add(new BigDecimal(2L)).toString(); + expectMapperException(() -> mapper.readObject("{\"intVal\":" + intCap + "}", TheObject.class)); + expectMapperException(() -> mapper.readObject("{\"intVal\":-" + intCap + "}", TheObject.class)); + expectMapperException(() -> mapper.readObject("{\"longnumber\":" + longCap + "}", TheObject.class)); + expectMapperException(() -> mapper.readObject("{\"longnumber\":-" + longCap + "}", TheObject.class)); + } + + /*@Test public void byteArrayBase64Converter() { - + Mapper mapper = new MapperBuilder().setTreatByteArrayAsBase64(false).build(); - + ByteArray ba = new ByteArray(); ba.setByteArray(new byte[]{(byte) 1,(byte) 1,(byte) 1 }); - + final String expectedJson = "{\"shortW\":22,\"shortWA\":[7,-2],\"byteW\":7,\"numShortA\":[4,-2],\"numByteA\":\"Af8C\",\"byteWA\":[4,-12,2],\"numByte\":6,\"numShort\":-1}"; - + StringWriter writer = new StringWriter(); mapper.writeObject(ba, writer); assertEquals(expectedJson, writer.toString()); - + ByteShort bsr = mapper.readObject(new StringReader(expectedJson), ByteArray.class); - + writer = new StringWriter(); mapper.writeObject(bsr, writer); assertEquals(expectedJson, writer.toString()); @@ -538,26 +575,26 @@ public class MapperTest { assertNotNull(object); assertEquals("the string", object.name); - assertEquals(56, object.integer); + assertEquals(56, object.intVal); assertEquals(118, object.longnumber); assertTrue(object.bool); assertEquals("another value", object.nested.name); - assertEquals(97, object.nested.integer); + assertEquals(97, object.nested.intVal); assertEquals(34, object.nested.longnumber); assertFalse(object.nested.bool); assertNotNull(object.array); assertEquals(2, object.array.length); assertEquals("a1", object.array[0].name); - assertEquals(1, object.array[0].integer); + assertEquals(1, object.array[0].intVal); assertEquals(2, object.array[0].longnumber); assertEquals("a2", object.array[1].name); - assertEquals(3, object.array[1].integer); + assertEquals(3, object.array[1].intVal); assertEquals(4, object.array[1].longnumber); assertEquals("a3", object.list.get(0).name); - assertEquals(5, object.list.get(0).integer); + assertEquals(5, object.list.get(0).intVal); assertEquals(6, object.list.get(0).longnumber); assertEquals("a4", object.list.get(1).name); - assertEquals(7, object.list.get(1).integer); + assertEquals(7, object.list.get(1).intVal); assertEquals(8, object.list.get(1).longnumber); assertEquals(5, object.primitives.length); for (int i = 0; i < object.primitives.length; i++) { @@ -579,15 +616,15 @@ public class MapperTest { @Test public void readArray() { final TheObject[] object = new MapperBuilder().build().readArray( - new ByteArrayInputStream(("[" + "{" + "\"name\":\"a3\"," + "\"integer\":5," + "\"longnumber\":6" + "}," + "{" - + "\"name\":\"a4\"," + "\"integer\":7," + "\"longnumber\":8" + "}" + "]").getBytes()), TheObject.class); + new ByteArrayInputStream(("[" + "{" + "\"name\":\"a3\"," + "\"intVal\":5," + "\"longnumber\":6" + "}," + "{" + + "\"name\":\"a4\"," + "\"intVal\":7," + "\"longnumber\":8" + "}" + "]").getBytes()), TheObject.class); assertNotNull(object); assertEquals(2, object.length); assertEquals("a3", object[0].name); - assertEquals(5, object[0].integer); + assertEquals(5, object[0].intVal); assertEquals(6, object[0].longnumber); assertEquals("a4", object[1].name); - assertEquals(7, object[1].integer); + assertEquals(7, object[1].intVal); assertEquals(8, object[1].longnumber); } @@ -702,6 +739,15 @@ public class MapperTest { assertNotEquals(utf8, latin); // means encoding was considered, we don't need more here } + private void expectMapperException(Runnable runnable) { + try { + runnable.run(); + Assert.fail("MapperException expected!"); + } catch (MapperException me) { + // all fine! + } + } + public static class NanHolder { private Double nan = Double.NaN; @@ -716,7 +762,8 @@ public class MapperTest { public static class TheObject { private String name; - private int integer; + private int intVal; + private Integer integerVal; private long longnumber; private boolean bool; private TheObject nested; @@ -734,12 +781,20 @@ public class MapperTest { this.name = name; } - public int getInteger() { - return integer; + public int getIntVal() { + return intVal; + } + + public void setIntVal(final int intVal) { + this.intVal = intVal; + } + + public Integer getIntegerVal() { + return integerVal; } - public void setInteger(final int integer) { - this.integer = integer; + public void setIntegerVal(Integer integerVal) { + this.integerVal = integerVal; } public long getLongnumber() { @@ -808,7 +863,7 @@ public class MapperTest { @Override public String toString() { - return "TheObject [name=" + name + ", integer=" + integer + ", longnumber=" + longnumber + ", bool=" + bool + ", nested=" + return "TheObject [name=" + name + ", integer=" + intVal + ", longnumber=" + longnumber + ", bool=" + bool + ", nested=" + nested + ", array=" + Arrays.toString(array) + ", list=" + list + ", primitives=" + Arrays.toString(primitives) + ", collectionWrapper=" + collectionWrapper + ", map=" + map + "]"; } @@ -820,7 +875,7 @@ public class MapperTest { result = prime * result + Arrays.hashCode(array); result = prime * result + (bool ? 1231 : 1237); result = prime * result + ((collectionWrapper == null) ? 0 : collectionWrapper.hashCode()); - result = prime * result + integer; + result = prime * result + intVal; result = prime * result + ((list == null) ? 0 : list.hashCode()); result = prime * result + (int) (longnumber ^ (longnumber >>> 32)); result = prime * result + ((map == null) ? 0 : map.hashCode()); @@ -855,7 +910,7 @@ public class MapperTest { } else if (!collectionWrapper.equals(other.collectionWrapper)) { return false; } - if (integer != other.integer) { + if (intVal != other.intVal) { return false; } if (list == null) {
