diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b0b4ae12..6ca1e8f11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.4.5 (2020-10-09) +# 5.4.5 (2020-10-11) ### 新特性 * 【core 】 ConsoleTable代码优化(pr#190@Gitee) @@ -18,6 +18,7 @@ ### Bug修复 * 【core 】 解决农历判断节日未判断大小月导致的问题(issue#I1XHSF@Gitee) * 【core 】 解决ListUtil计算总量可能的int溢出问题(pr#1150@Github) +* 【json 】 解决JSON中转换为double小数精度丢失问题(pr#192@Gitee) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java index 8bc0e6d27..c47ac3df6 100644 --- a/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java +++ b/hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java @@ -140,12 +140,14 @@ final class InternalJSONUtil { * @return A simple JSON value. */ protected static Object stringToValue(String string) { + // null处理 if (null == string || "null".equalsIgnoreCase(string)) { return JSONNull.NULL; } - if (StrUtil.EMPTY.equals(string)) { - return string; + // boolean处理 + if (0 == string.length()) { + return StrUtil.EMPTY; } if ("true".equalsIgnoreCase(string)) { return Boolean.TRUE; @@ -154,17 +156,22 @@ final class InternalJSONUtil { return Boolean.FALSE; } - /* If it might be a number, try converting it. If a number cannot be produced, then the value will just be a string. */ + // Number处理 char b = string.charAt(0); if ((b >= '0' && b <= '9') || b == '-') { try { - if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1) { + if (StrUtil.containsAnyIgnoreCase(string, ".", "e")) { + // pr#192@Gitee,Double会出现小数精度丢失问题,此处使用BigDecimal + //double d = Double.parseDouble(string); + //if (false == Double.isInfinite(d) && false == Double.isNaN(d)) { + // return d; + //} return new BigDecimal(string); } else { - Long myLong = new Long(string); - if (string.equals(myLong.toString())) { - if (myLong == myLong.intValue()) { - return myLong.intValue(); + final long myLong = Long.parseLong(string); + if (string.equals(Long.toString(myLong))) { + if (myLong == (int) myLong) { + return (int) myLong; } else { return myLong; } @@ -173,6 +180,8 @@ final class InternalJSONUtil { } catch (Exception ignore) { } } + + // 其它情况返回原String值下 return string; } diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java index 086c941d4..c132b6758 100644 --- a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java +++ b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java @@ -349,7 +349,7 @@ public class JSONTokener { this.back(); string = sb.toString().trim(); - if ("".equals(string)) { + if (0 == string.length()) { throw this.syntaxError("Missing value"); } return InternalJSONUtil.stringToValue(string); diff --git a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java index fba18df9d..5a6382ba3 100644 --- a/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java +++ b/hutool-json/src/test/java/cn/hutool/json/JSONUtilTest.java @@ -10,10 +10,8 @@ import cn.hutool.json.test.bean.UserC; import org.junit.Assert; import org.junit.Test; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; public class JSONUtilTest { @@ -126,15 +124,6 @@ public class JSONUtilTest { // Assert.assertEquals("{\"age\":18,\"gender\":\"男\"}", user.getProp()); } - @Test - public void toBeanTest3() { - // 测试数字类型精度丢失的情况 - String number = "1234.123456789123456"; - String jsonString = "{\"create\":{\"details\":[{\"price\":" + number + "}]}}"; - WebCreate create = JSONUtil.toBean(jsonString, WebCreate.class); - Assert.assertEquals(number,create.getCreate().getDetails().get(0).getPrice().toString()); - } - @Test public void putByPathTest() { JSONObject json = new JSONObject(); @@ -172,62 +161,5 @@ public class JSONUtilTest { final JSONObject jsonObject = JSONUtil.parseObj(json); Assert.assertEquals("12.00", jsonObject.getBigDecimal("test").setScale(2).toString()); } - - - class WebCreate { - private Create create; - @Override - public String toString() { - return "WebCreate{" + - "create=" + create + - '}'; - } - - public void setCreate(Create create) { - this.create = create; - } - - public Create getCreate() { - return create; - } - } - - class Create { - @Override - public String toString() { - return "Create{" + - "details=" + details + - '}'; - } - - private List details; - - public void setDetails(List details) { - this.details = details; - } - - public List getDetails() { - return details; - } - } - - class Detail { - private BigDecimal price; - - public void setPrice(BigDecimal price) { - this.price = price; - } - - @Override - public String toString() { - return "Detail{" + - "price=" + price + - '}'; - } - - public BigDecimal getPrice() { - return price; - } - } } diff --git a/hutool-json/src/test/java/cn/hutool/json/Pr192Test.java b/hutool-json/src/test/java/cn/hutool/json/Pr192Test.java new file mode 100644 index 000000000..5aafdd65d --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/Pr192Test.java @@ -0,0 +1,75 @@ +package cn.hutool.json; + +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.List; + +public class Pr192Test { + + @Test + public void toBeanTest3() { + // 测试数字类型精度丢失的情况 + String number = "1234.123456789123456"; + String jsonString = "{\"create\":{\"details\":[{\"price\":" + number + "}]}}"; + WebCreate create = JSONUtil.toBean(jsonString, WebCreate.class); + Assert.assertEquals(number,create.getCreate().getDetails().get(0).getPrice().toString()); + } + + static class WebCreate { + private Create create; + @Override + public String toString() { + return "WebCreate{" + + "create=" + create + + '}'; + } + + public void setCreate(Create create) { + this.create = create; + } + + public Create getCreate() { + return create; + } + } + + static class Create { + @Override + public String toString() { + return "Create{" + + "details=" + details + + '}'; + } + + private List details; + + public void setDetails(List details) { + this.details = details; + } + + public List getDetails() { + return details; + } + } + + static class Detail { + private BigDecimal price; + + public void setPrice(BigDecimal price) { + this.price = price; + } + + @Override + public String toString() { + return "Detail{" + + "price=" + price + + '}'; + } + + public BigDecimal getPrice() { + return price; + } + } +}