From 68c985bd8d7e026f3f7196113bac170bded78799 Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Mon, 5 Mar 2018 10:20:49 +0800 Subject: [PATCH] fix #167, if dot found, should always parse as double --- .../com/jsoniter/IterImplForStreaming.java | 31 ++++++++++++++----- src/main/java/com/jsoniter/JsonIterator.java | 20 ++++++++---- .../jsoniter/IterImplForStreamingTest.java | 3 +- src/test/java/com/jsoniter/TestFloat.java | 3 ++ 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/jsoniter/IterImplForStreaming.java b/src/main/java/com/jsoniter/IterImplForStreaming.java index 34fb0872..7e29f770 100644 --- a/src/main/java/com/jsoniter/IterImplForStreaming.java +++ b/src/main/java/com/jsoniter/IterImplForStreaming.java @@ -539,15 +539,22 @@ static int readIntSlowPath(final JsonIterator iter, int value) throws IOExceptio public static final double readDoubleSlowPath(final JsonIterator iter) throws IOException { try { - String numberAsStr = readNumber(iter); - return Double.valueOf(numberAsStr); + numberChars numberChars = readNumber(iter); + return Double.valueOf(new String(numberChars.chars, 0, numberChars.charsLength)); } catch (NumberFormatException e) { throw iter.reportError("readDoubleSlowPath", e.toString()); } } - public static final String readNumber(final JsonIterator iter) throws IOException { + static class numberChars { + char[] chars; + int charsLength; + boolean dotFound; + } + + public static final numberChars readNumber(final JsonIterator iter) throws IOException { int j = 0; + boolean dotFound = false; for (; ; ) { for (int i = iter.head; i < iter.tail; i++) { if (j == iter.reusableChars.length) { @@ -557,11 +564,13 @@ public static final String readNumber(final JsonIterator iter) throws IOExceptio } byte c = iter.buf[i]; switch (c) { - case '-': - case '+': case '.': case 'e': case 'E': + dotFound = true; + // fallthrough + case '-': + case '+': case '0': case '1': case '2': @@ -576,12 +585,20 @@ public static final String readNumber(final JsonIterator iter) throws IOExceptio break; default: iter.head = i; - return new String(iter.reusableChars, 0, j); + numberChars numberChars = new numberChars(); + numberChars.chars = iter.reusableChars; + numberChars.charsLength = j; + numberChars.dotFound = dotFound; + return numberChars; } } if (!IterImpl.loadMore(iter)) { iter.head = iter.tail; - return new String(iter.reusableChars, 0, j); + numberChars numberChars = new numberChars(); + numberChars.chars = iter.reusableChars; + numberChars.charsLength = j; + numberChars.dotFound = dotFound; + return numberChars; } } } diff --git a/src/main/java/com/jsoniter/JsonIterator.java b/src/main/java/com/jsoniter/JsonIterator.java index 9a613ca2..33f224d3 100644 --- a/src/main/java/com/jsoniter/JsonIterator.java +++ b/src/main/java/com/jsoniter/JsonIterator.java @@ -190,7 +190,8 @@ public final boolean readArray() throws IOException { } public String readNumberAsString() throws IOException { - return IterImplForStreaming.readNumber(this); + IterImplForStreaming.numberChars numberChars = IterImplForStreaming.readNumber(this); + return new String(numberChars.chars, 0, numberChars.charsLength); } public static interface ReadArrayCallback { @@ -239,7 +240,8 @@ public final BigDecimal readBigDecimal() throws IOException { if (valueType != ValueType.NUMBER) { throw reportError("readBigDecimal", "not number"); } - return new BigDecimal(IterImplForStreaming.readNumber(this)); + IterImplForStreaming.numberChars numberChars = IterImplForStreaming.readNumber(this); + return new BigDecimal(numberChars.chars, 0, numberChars.charsLength); } public final BigInteger readBigInteger() throws IOException { @@ -252,7 +254,8 @@ public final BigInteger readBigInteger() throws IOException { if (valueType != ValueType.NUMBER) { throw reportError("readBigDecimal", "not number"); } - return new BigInteger(IterImplForStreaming.readNumber(this)); + IterImplForStreaming.numberChars numberChars = IterImplForStreaming.readNumber(this); + return new BigInteger(new String(numberChars.chars, 0, numberChars.charsLength)); } public final Any readAny() throws IOException { @@ -288,9 +291,14 @@ public final Object read() throws IOException { case STRING: return readString(); case NUMBER: - double number = readDouble(); - if (number == Math.floor(number) && !Double.isInfinite(number)) { - long longNumber = (long) number; + IterImplForStreaming.numberChars numberChars = IterImplForStreaming.readNumber(this); + Double number = Double.valueOf(new String(numberChars.chars, 0, numberChars.charsLength)); + if (numberChars.dotFound) { + return number; + } + double doubleNumber = number; + if (doubleNumber == Math.floor(doubleNumber) && !Double.isInfinite(doubleNumber)) { + long longNumber = (long) doubleNumber; if (longNumber <= Integer.MAX_VALUE && longNumber >= Integer.MIN_VALUE) { return (int) longNumber; } diff --git a/src/test/java/com/jsoniter/IterImplForStreamingTest.java b/src/test/java/com/jsoniter/IterImplForStreamingTest.java index 4efee7e3..c190d469 100644 --- a/src/test/java/com/jsoniter/IterImplForStreamingTest.java +++ b/src/test/java/com/jsoniter/IterImplForStreamingTest.java @@ -7,7 +7,8 @@ public class IterImplForStreamingTest extends TestCase { public void testReadMaxDouble() throws Exception { String maxDouble = "1.7976931348623157e+308"; JsonIterator iter = JsonIterator.parse("1.7976931348623157e+308"); - String number = IterImplForStreaming.readNumber(iter); + IterImplForStreaming.numberChars numberChars = IterImplForStreaming.readNumber(iter); + String number = new String(numberChars.chars, 0, numberChars.charsLength); assertEquals(maxDouble, number); } } \ No newline at end of file diff --git a/src/test/java/com/jsoniter/TestFloat.java b/src/test/java/com/jsoniter/TestFloat.java index f67a9eaf..b1e9d82c 100644 --- a/src/test/java/com/jsoniter/TestFloat.java +++ b/src/test/java/com/jsoniter/TestFloat.java @@ -1,5 +1,6 @@ package com.jsoniter; +import com.fasterxml.jackson.databind.ObjectMapper; import junit.framework.TestCase; import org.junit.experimental.categories.Category; @@ -86,5 +87,7 @@ public void testBigDecimal() { public void testChooseDouble() { Object number = JsonIterator.deserialize("1.1", Object.class); assertEquals(1.1, number); + number = JsonIterator.deserialize("1.0", Object.class); + assertEquals(1.0, number); } }