From f1e51f5cfa939f6dfc31899e5381e93d3604d1b7 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Sun, 21 Apr 2019 16:28:01 +0800 Subject: [PATCH] add bigdecimal cast to int/long support --- .../com/alibaba/fastjson/util/TypeUtils.java | 37 +- .../parser/TypeUtils_parseDouble_Test.java | 11 + .../bvt/parser/TypeUtils_parseFloat_Test.java | 1 + .../parser/number/NumberValueTest_cast.java | 18 + .../number/NumberValueTest_error_13.java | 360 ++++++++++++++++++ 5 files changed, 420 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_cast.java create mode 100644 src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_error_13.java diff --git a/src/main/java/com/alibaba/fastjson/util/TypeUtils.java b/src/main/java/com/alibaba/fastjson/util/TypeUtils.java index 6e7c740657..fedd52ee9f 100755 --- a/src/main/java/com/alibaba/fastjson/util/TypeUtils.java +++ b/src/main/java/com/alibaba/fastjson/util/TypeUtils.java @@ -349,7 +349,13 @@ public static final Date castToDate(Object value) { long longValue = -1; if (value instanceof BigDecimal) { - longValue = ((BigDecimal) value).longValueExact(); + BigDecimal decimal = (BigDecimal) value; + int scale = decimal.scale(); + if (scale >= -100 && scale <= 100) { + longValue = decimal.longValue(); + } else { + longValue = decimal.longValueExact(); + } } else if (value instanceof Number) { longValue = ((Number) value).longValue(); } else if (value instanceof String) { @@ -401,7 +407,13 @@ public static final Long castToLong(Object value) { } if (value instanceof BigDecimal) { - return ((BigDecimal) value).longValueExact(); + BigDecimal decimal = (BigDecimal) value; + int scale = decimal.scale(); + if (scale >= -100 && scale <= 100) { + return decimal.longValue(); + } + + return decimal.longValueExact(); } if (value instanceof Number) { @@ -446,7 +458,14 @@ public static final Integer castToInt(Object value) { } if (value instanceof BigDecimal) { - return ((BigDecimal) value).intValueExact(); + BigDecimal decimal = (BigDecimal) value; + + int scale = decimal.scale(); + if (scale >= -100 && scale <= 100) { + return decimal.intValue(); + } + + return decimal.intValueExact(); } if (value instanceof Number) { @@ -673,7 +692,7 @@ public static final T castToEnum(Object obj, Class clazz, ParserConfig ma } else { return (T) Enum.valueOf((Class) clazz, name); } - } else if (obj instanceof Number) { + } else if (obj instanceof Integer || obj instanceof Long) { int ordinal = ((Number) obj).intValue(); Object[] values = clazz.getEnumConstants(); if (ordinal < values.length) { @@ -726,9 +745,11 @@ public static final T cast(Object obj, ParameterizedType type, ParserConfig if (obj instanceof List) { List listObj = (List) obj; - ArrayList arrayList = new ArrayList(listObj.size()); - for (int i = 0; i < listObj.size(); i++) { + int listObjSize = listObj.size(); + ArrayList arrayList = new ArrayList(listObjSize); + + for (int i = 0; i < listObjSize; i++) { Object item = listObj.get(i); Object itemValue; @@ -839,6 +860,8 @@ public static final T castToJavaBean(Map map, Class clazz Number value = (Number) map.get("lineNumber"); if (value == null) { lineNumber = 0; + } else if (value instanceof BigDecimal) { + lineNumber = ((BigDecimal) value).intValueExact(); } else { lineNumber = value.intValue(); } @@ -1750,7 +1773,7 @@ public static boolean getArgument(Type[] typeArgs, TypeVariable[] typeVariables, public static double parseDouble(String str) { final int len = str.length(); - if (len >= 10) { + if (len > 10) { return Double.parseDouble(str); } diff --git a/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseDouble_Test.java b/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseDouble_Test.java index 589e97fad6..46a04583f6 100644 --- a/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseDouble_Test.java +++ b/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseDouble_Test.java @@ -15,6 +15,16 @@ public void test_0() throws Exception { } } + public void test_0_d() throws Exception { + Random r = new Random(); + + for (int i = 0; i < 1000 * 1000; ++i) { + String str = Double.toString(r.nextDouble()); + assertEquals(Double.parseDouble(str), TypeUtils.parseDouble(str)); + } + } + + public void test_1() throws Exception { Random r = new Random(); @@ -44,6 +54,7 @@ public void test_3() throws Exception { public void test_4() throws Exception { String[] array = new String[] { + "0.34856254", "1", "12", "123", diff --git a/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseFloat_Test.java b/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseFloat_Test.java index cd85a2e4d3..3db0fdd265 100644 --- a/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseFloat_Test.java +++ b/src/test/java/com/alibaba/json/bvt/parser/TypeUtils_parseFloat_Test.java @@ -44,6 +44,7 @@ public void test_3() throws Exception { public void test_4() throws Exception { String[] array = new String[] { + "0.34856254", "1", "12", "123", diff --git a/src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_cast.java b/src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_cast.java new file mode 100644 index 0000000000..76e89e723c --- /dev/null +++ b/src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_cast.java @@ -0,0 +1,18 @@ +package com.alibaba.json.bvt.parser.number; + +import com.alibaba.fastjson.JSONObject; +import junit.framework.TestCase; + +import java.math.BigDecimal; + +public class NumberValueTest_cast extends TestCase { + public void test_0() throws Exception { + JSONObject object = new JSONObject(); + object.put("val", new BigDecimal("23.4")); + + assertEquals(23, object.getByteValue("val")); + assertEquals(23, object.getShortValue("val")); + assertEquals(23, object.getIntValue("val")); + assertEquals(23, object.getLongValue("val")); + } +} diff --git a/src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_error_13.java b/src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_error_13.java new file mode 100644 index 0000000000..07d3e72d70 --- /dev/null +++ b/src/test/java/com/alibaba/json/bvt/parser/number/NumberValueTest_error_13.java @@ -0,0 +1,360 @@ +package com.alibaba.json.bvt.parser.number; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.util.TypeUtils; +import junit.framework.TestCase; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Timestamp; +import java.util.concurrent.TimeUnit; + +public class NumberValueTest_error_13 extends TestCase { + + public void test_0() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v0\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_1() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v1\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_2() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v2\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_3() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v3\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_5() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v5\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_6() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v6\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_7() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v7\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertTrue(error.getCause() instanceof ArithmeticException); + } + + public void test_8() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v8\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertEquals(NumberFormatException.class, error.getCause().getClass()); + } + + public void test_9() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v9\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_10() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v10\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_11() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v11\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertEquals(ArithmeticException.class, error.getCause().getClass()); + } + + public void test_11_new() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v11\":new Date(49e99999999)}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_12() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v12\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + assertEquals(ArithmeticException.class, error.getCause().getClass()); + } + + public void test_13() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v13\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + + public void test_14() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v14\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_15() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v15\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + + public void test_16() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v16\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_17() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v17\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_17_1() throws Exception { + Exception error = null; + try { + JSONObject jsonObject = JSON.parseObject("{\"v17\":49e99999999}"); + jsonObject.getObject("v17", TimeUnit.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + + public void test_18() throws Exception { + Exception error = null; + try { + JSON.parseObject("{\"v18\":49e99999999}", Model.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + + public void test_20() throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("v", new BigDecimal("49e99999999")); + Exception error = null; + try { + jsonObject.getIntValue("v"); + } catch (ArithmeticException ex) { + error = ex; + } + assertNotNull(error); + } + + + public void test_20_long() throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("v", new BigDecimal("49e99999999")); + Exception error = null; + try { + jsonObject.getLongValue("v"); + } catch (ArithmeticException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_21() throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("v", new BigDecimal("49e99999999")); + Exception error = null; + try { + jsonObject.getDate("v"); + } catch (ArithmeticException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_22() throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("v", new BigDecimal("49e99999999")); + Exception error = null; + try { + jsonObject.getObject("v", java.sql.Date.class); + } catch (Exception ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_23() throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("v", new BigDecimal("49e99999999")); + Exception error = null; + try { + jsonObject.getObject("v", Timestamp.class); + } catch (Exception ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_24() throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("v", new BigDecimal("49e99999999")); + Exception error = null; + try { + jsonObject.getObject("v", java.time.LocalDateTime.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_25() throws Exception { + JSONObject jsonObject = JSON.parseObject("{\"lineNumber\":49e99999999}"); + Exception error = null; + try { + jsonObject.toJavaObject(StackTraceElement.class); + } catch (JSONException ex) { + error = ex; + } + assertNotNull(error); + } + + public void test_26() throws Exception { + JSONObject jsonObject = JSON.parseObject("{\"v\":49e99999999}"); + Exception error = null; + try { + jsonObject.getObject("v", java.sql.Time.class); + } catch (Exception ex) { + error = ex; + } + assertNotNull(error); + } + + public static class Model { + public byte v0; + public short v1; + public int v2; + public long v3; + public Byte v4; + + public Short v5; + public Integer v6; + public Long v7; + public BigInteger v8; + + public Timestamp v9; + public java.sql.Date v10; + public java.util.Date v11; + public java.util.Calendar v12; + public Timestamp v13; + public java.time.LocalDateTime v14; + + public boolean v15; + public Boolean v16; + public TimeUnit v17; + public java.sql.Time v18; + } + + public static class M1 { + public BigDecimal val; + + public M1(BigDecimal val) { + this.val = val; + } + } +}