From d3714681f61581810680df8e45858a4d30a602da Mon Sep 17 00:00:00 2001 From: Ben Cox <1038350+ind1go@users.noreply.github.com> Date: Mon, 16 May 2022 18:00:10 +0100 Subject: [PATCH] Use BigDecimal instead of Double to avoid loss of precision --- .../codehaus/jettison/json/JSONTokener.java | 16 +++++++++-- .../jettison/json/JSONTokenerTest.java | 27 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/codehaus/jettison/json/JSONTokenerTest.java diff --git a/src/main/java/org/codehaus/jettison/json/JSONTokener.java b/src/main/java/org/codehaus/jettison/json/JSONTokener.java index bca76aa..4ce90a8 100644 --- a/src/main/java/org/codehaus/jettison/json/JSONTokener.java +++ b/src/main/java/org/codehaus/jettison/json/JSONTokener.java @@ -15,6 +15,8 @@ */ package org.codehaus.jettison.json; +import java.math.BigDecimal; + /** * A JSONTokener takes a source string and extracts characters and tokens from * it. It is used by the JSONObject and JSONArray constructors to parse @@ -24,6 +26,11 @@ */ public class JSONTokener { + private static final String USE_BIGDECIMAL_JSONTOKENER_KEY = "jettison.json.jsontokener.use_bigdecimal"; + public static final boolean USE_BIGDECIMAL_JSONTOKENER = Boolean.getBoolean( USE_BIGDECIMAL_JSONTOKENER_KEY ); + protected boolean useBigDecimal = USE_BIGDECIMAL_JSONTOKENER; + + /** * The index of the next character. */ @@ -308,7 +315,8 @@ public String nextTo(String delimiters) { /** - * Get the next value. The value can be a Boolean, Double, Integer, + * Get the next value. The value can be a Boolean, Double/BigDecimal + * (depending on -Djettison.json.jsontokener.use_bigdecimal), Integer, * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. * @throws JSONException If syntax error. * @@ -398,7 +406,11 @@ public Object nextValue() throws JSONException { return Long.valueOf(s); } catch (Exception f) { try { - return new Double(s); + if (useBigDecimal) { + return new BigDecimal(s); + } else { + return new Double(s); + } } catch (Exception g) { return s; } diff --git a/src/test/java/org/codehaus/jettison/json/JSONTokenerTest.java b/src/test/java/org/codehaus/jettison/json/JSONTokenerTest.java new file mode 100644 index 0000000..ccb609d --- /dev/null +++ b/src/test/java/org/codehaus/jettison/json/JSONTokenerTest.java @@ -0,0 +1,27 @@ +package org.codehaus.jettison.json; + +import java.math.BigDecimal; + +import junit.framework.TestCase; + +public class JSONTokenerTest extends TestCase { + + public void testDoublePrecision() throws Exception { + JSONTokener doubleTokener = new JSONTokener("9999999999999.9999"); + Object nextValue = doubleTokener.nextValue(); + assertEquals(Double.class, nextValue.getClass()); + assertEquals(Double.valueOf("1.0E13"), nextValue); + } + + public void testBigDecimalPrecision() throws Exception { + JSONTokener bigDecimalTokener = new JSONTokener("9999999999999.9999") { + { + this.useBigDecimal = true; + } + }; + Object nextValue = bigDecimalTokener.nextValue(); + assertEquals(BigDecimal.class, nextValue.getClass()); + assertEquals(new BigDecimal("9999999999999.9999"), nextValue); + } + +}