Repository: alibaba/fastjson2
Pull request #3257 (2025-01-06 04:03:09)

refactor: 同步 `mark` 为 `true/false` 的两个分支的代码的逻辑
### What this PR does / why we need it?

`v2.0.53` 在使用 `JSONObject#toJavaObject` 函数将 `JSONObject` 转换为 `Kotlin` 的对象时，如果构造函数带有默认值，转换将会出现错误。

该 bug 已经在 [pull#3175](https://github.com/alibaba/fastjson2/pull/3175) 中修复，但我认为最合理的修复方式应当是将 `ConstructorFunction.java` 中两个分支的代码逻辑改成一样的，所以换了一种修复方法。

在这个 issue 中我们进行了一些讨论：https://github.com/alibaba/fastjson2/issues/3152#issuecomment-2570040419

### Summary of your change

1. 回滚了 pull #3175 中对 `ObjectReaderNoneDefaultConstructor.java` 的修复
2. 为 `ConstructorFunction.java` 将 `mark = true` 时的分支的代码添加类型检查和转换逻辑（与为 `false` 时逻辑一致）
3. 补充了一组测试样例

#### Please indicate you've done the following:

- [x] Made sure tests are passing and test coverage is added if needed.
- [x] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/).
- [x] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.


CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/alibaba/fastjson2?pullRequest=3257) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/alibaba/fastjson2?pullRequest=3257) before we can accept your contribution.<br/><hr/>**maenzhi** seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please [add the email address used for this commit to your account](https://help.github.com/articles/why-are-my-commits-linked-to-the-wrong-user/#commits-are-not-linked-to-any-user).<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/alibaba/fastjson2?pullRequest=3257) it.</sub>

Patch:
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java
index a490793f6..b1203ef0b 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java
@@ -27,8 +27,7 @@ import java.util.function.Supplier;
 import static com.alibaba.fastjson2.JSONFactory.*;
 import static com.alibaba.fastjson2.JSONReader.BigIntegerCreator.BIG_INTEGER_CREATOR;
 import static com.alibaba.fastjson2.util.JDKUtils.*;
-import static com.alibaba.fastjson2.util.TypeUtils.toBigDecimal;
-import static com.alibaba.fastjson2.util.TypeUtils.toDate;
+import static com.alibaba.fastjson2.util.TypeUtils.*;
 
 public abstract class JSONReader
         implements Closeable {
@@ -48,6 +47,7 @@ public abstract class JSONReader
     static final byte JSON_TYPE_INT64 = 11;
     static final byte JSON_TYPE_FLOAT = 12;
     static final byte JSON_TYPE_DOUBLE = 13;
+    static final byte JSON_TYPE_NaN = 14;
 
     static final char EOI = 0x1A;
     static final long SPACE = (1L << ' ') | (1L << '\n') | (1L << '\r') | (1L << '\f') | (1L << '\t') | (1L << '\b');
@@ -808,8 +808,19 @@ public abstract class JSONReader
             case JSON_TYPE_INT8:
             case JSON_TYPE_INT16:
             case JSON_TYPE_INT:
-                if (mag1 == 0 && mag2 == 0 && mag3 != Integer.MIN_VALUE) {
-                    return negative ? -mag3 : mag3;
+                if (mag1 == 0 && mag2 == 0) {
+                    if (negative) {
+                        if (mag3 == Integer.MIN_VALUE) {
+                            return mag3;
+                        }
+                        if (mag3 >= 0) {
+                            return -mag3;
+                        }
+                    } else {
+                        if (mag3 >= 0) {
+                            return mag3;
+                        }
+                    }
                 }
                 Number number = getNumber();
                 if (number instanceof Long) {
@@ -883,8 +894,19 @@ public abstract class JSONReader
             case JSON_TYPE_INT8:
             case JSON_TYPE_INT16:
             case JSON_TYPE_INT:
-                if (mag1 == 0 && mag2 == 0 && mag3 != Integer.MIN_VALUE) {
-                    return negative ? -mag3 : mag3;
+                if (mag1 == 0 && mag2 == 0) {
+                    if (negative) {
+                        if (mag3 == Integer.MIN_VALUE) {
+                            return mag3;
+                        }
+                        if (mag3 >= 0) {
+                            return -mag3;
+                        }
+                    } else {
+                        if (mag3 >= 0) {
+                            return mag3;
+                        }
+                    }
                 }
                 Number number = getNumber();
                 if (number instanceof BigInteger) {
@@ -932,6 +954,80 @@ public abstract class JSONReader
         }
     }
 
+    public final double getDoubleValue() {
+        switch (valueType) {
+            case JSON_TYPE_NaN:
+                return Double.NaN;
+            case JSON_TYPE_INT8:
+            case JSON_TYPE_INT16:
+            case JSON_TYPE_INT:
+                if (mag1 == 0 && mag2 == 0 && mag3 != Integer.MIN_VALUE) {
+                    return negative ? -mag3 : mag3;
+                }
+                Number number = getNumber();
+                if (number instanceof BigInteger) {
+                    BigInteger bigInt = (BigInteger) number;
+                    if ((context.features & Feature.NonErrorOnNumberOverflow.mask) != 0) {
+                        return bigInt.longValue();
+                    }
+                    try {
+                        return bigInt.longValueExact();
+                    } catch (ArithmeticException e) {
+                        throw numberError();
+                    }
+                }
+                return number.doubleValue();
+            case JSON_TYPE_DEC:
+            case JSON_TYPE_INT64:
+            case JSON_TYPE_FLOAT:
+            case JSON_TYPE_DOUBLE:
+                return getNumber().doubleValue();
+            case JSON_TYPE_BOOL:
+                return boolValue ? 1 : 0;
+            case JSON_TYPE_NULL:
+                if ((context.features & Feature.ErrorOnNullForPrimitives.mask) != 0) {
+                    throw new JSONException(info("long value not support input null"));
+                }
+                return 0;
+            case JSON_TYPE_STRING: {
+                try {
+                    return toDoubleValue(stringValue);
+                } catch (NumberFormatException e) {
+                    throw new JSONException(info(e.getMessage()));
+                }
+            }
+            case JSON_TYPE_OBJECT: {
+                Map map = (Map) complex;
+                if (map == null || map.isEmpty()) {
+                    wasNull = true;
+                    return 0;
+                }
+                return toDoubleValue(map);
+            }
+            case JSON_TYPE_ARRAY: {
+                Collection list = (Collection) complex;
+                if (list == null || list.isEmpty()) {
+                    wasNull = true;
+                    return 0;
+                }
+                return toDoubleValue(complex);
+            }
+            case JSON_TYPE_BIG_DEC:
+                try {
+                    return getBigDecimal()
+                            .doubleValue();
+                } catch (ArithmeticException e) {
+                    throw numberError();
+                }
+            default:
+                throw new JSONException("TODO : " + valueType);
+        }
+    }
+
+    public final float getFloatValue() {
+        return (float) getDoubleValue();
+    }
+
     public long[] readInt64ValueArray() {
         if (nextIfNull()) {
             return null;
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java
index ccc2d4c21..64c934652 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java
@@ -10,6 +10,7 @@ import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
 import static com.alibaba.fastjson2.JSONFactory.*;
+import static com.alibaba.fastjson2.util.IOUtils.NULL_32;
 import static com.alibaba.fastjson2.util.JDKUtils.*;
 
 class JSONReaderASCII
@@ -79,8 +80,17 @@ class JSONReaderASCII
                 && bytes[offset + 2] == 'l'
         ) {
             offset += 3;
-        } else if ((first == '"' || first == '\'') && offset < end && bytes[offset] == first) {
-            offset++;
+        } else if (first == '"' || first == '\'') {
+            if (offset < end && bytes[offset] == first) {
+                offset++;
+            } else if (offset + 4 < end
+                    && UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset) == NULL_32
+                    && bytes[offset + 4] == first
+            ) {
+                offset += 5;
+            } else {
+                return false;
+            }
         } else {
             return false;
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java
index 0edbe00d9..657df73ca 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java
@@ -14,7 +14,10 @@ import java.time.*;
 import java.util.*;
 
 import static com.alibaba.fastjson2.JSONFactory.*;
+import static com.alibaba.fastjson2.util.IOUtils.*;
+import static com.alibaba.fastjson2.util.IOUtils.INT_32_MULT_MIN_10;
 import static com.alibaba.fastjson2.util.JDKUtils.*;
+import static java.lang.Long.MIN_VALUE;
 
 class JSONReaderUTF16
         extends JSONReader {
@@ -606,8 +609,17 @@ class JSONReaderUTF16
                 && chars[offset + 2] == 'l'
         ) {
             offset += 3;
-        } else if ((first == '"' || first == '\'') && offset < end && chars[offset] == first) {
-            offset++;
+        } else if (first == '"' || first == '\'') {
+            if (offset < end && chars[offset] == first) {
+                offset++;
+            } else if (offset + 4 < end
+                    && UNSAFE.getLong(chars, ARRAY_BYTE_BASE_OFFSET + ((long) offset << 1)) == NULL_64
+                    && chars[offset + 4] == first
+            ) {
+                offset += 5;
+            } else {
+                return false;
+            }
         } else {
             return false;
         }
@@ -2373,38 +2385,49 @@ class JSONReaderUTF16
 
     @Override
     public final int readInt32Value() {
-        boolean negative = false;
         char ch = this.ch;
         int offset = this.offset, end = this.end;
         final char[] chars = this.chars;
 
-        int intValue = 0;
-
         int quote = '\0';
         if (ch == '"' || ch == '\'') {
             quote = ch;
             ch = chars[offset++];
         }
 
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
-        } else if (ch == '+') {
-            ch = chars[offset++];
+        int result = 0;
+        boolean inRange, negative;
+        if ((negative = (ch == '-')) || ch == '+') {
+            ch = offset == end ? EOI : chars[offset++];
         } else if (ch == ',') {
             throw numberError();
         }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            int intValue10 = intValue * 10 + (ch - '0');
-            if (intValue10 < intValue) {
-                overflow = true;
-                break;
-            } else {
-                intValue = intValue10;
+        if (inRange = IOUtils.isDigit(ch)) {
+            result = '0' - ch;
+        }
+        int limit = Integer.MIN_VALUE + (negative ? 0 : 1);
+        int digit;
+        while (inRange
+                && offset + 1 < end
+                && (digit = IOUtils.digit2(chars, offset)) != -1
+        ) {
+            // max digits is 19, no need to check inRange (result == MULT_MIN_100 && digit <= (MULT_MIN_100 * 100 - limit))
+            if (inRange = (result > INT_32_MULT_MIN_100)) {
+                result = result * 100 - digit;
+                offset += 2;
+            }
+        }
+        if (inRange) {
+            if (offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                digit = ch - '0';
+                if (inRange = (result > INT_32_MULT_MIN_10 || (result == INT_32_MULT_MIN_10 && digit <= (INT_32_MULT_MIN_10 * 10 - limit)))) {
+                    result = result * 10 - digit;
+                    offset++;
+                }
+            }
+            if (inRange) {
+                ch = offset == end ? EOI : chars[offset++];
             }
-            ch = offset == end ? EOI : chars[offset++];
         }
 
         if (ch == '.'
@@ -2417,10 +2440,10 @@ class JSONReaderUTF16
                 || ch == '['
                 || (quote != 0 && ch != quote)
         ) {
-            overflow = true;
+            inRange = false;
         }
 
-        if (overflow) {
+        if (!inRange) {
             readNumber0();
             return getInt32Value();
         }
@@ -2438,7 +2461,7 @@ class JSONReaderUTF16
         }
 
         if (comma = (ch == ',')) {
-            ch = offset == end ? EOI : chars[offset++];
+            ch = offset == end ? EOI : (char) chars[offset++];
             while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
                 ch = offset == end ? EOI : chars[offset++];
             }
@@ -2447,17 +2470,22 @@ class JSONReaderUTF16
         this.ch = ch;
         this.offset = offset;
 
-        return negative ? -intValue : intValue;
+        return negative ? result : -result;
     }
 
     @Override
     public final Integer readInt32() {
-        boolean negative = false;
-        char ch = this.ch;
-        int offset = this.offset;
-        final char[] chars = this.chars;
+        int ch = this.ch;
+        if ((ch == '"' || ch == '\'' || ch == 'n') && nextIfNullOrEmptyString()) {
+            return null;
+        }
+        return readInt32Value();
+    }
 
-        int intValue = 0;
+    public final long readInt64Value() {
+        int ch = this.ch;
+        int offset = this.offset, end = this.end;
+        final char[] chars = this.chars;
 
         int quote = '\0';
         if (ch == '"' || ch == '\'') {
@@ -2465,25 +2493,38 @@ class JSONReaderUTF16
             ch = chars[offset++];
         }
 
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
-        } else if (ch == '+') {
-            ch = chars[offset++];
+        long result = 0;
+        boolean inRange, negative;
+        if ((negative = (ch == '-')) || ch == '+') {
+            ch = offset == end ? EOI : chars[offset++];
         } else if (ch == ',') {
             throw numberError();
         }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            int intValue10 = intValue * 10 + (ch - '0');
-            if (intValue10 < intValue) {
-                overflow = true;
-                break;
-            } else {
-                intValue = intValue10;
+        if (inRange = IOUtils.isDigit(ch)) {
+            result = '0' - ch;
+        }
+        long limit = MIN_VALUE + (negative ? 0L : 1L);
+        int digit;
+        while (inRange
+                && offset + 1 < end
+                && (digit = IOUtils.digit2(chars, offset)) != -1
+        ) {
+            if (inRange = (result > INT_64_MULT_MIN_100 || (result == INT_64_MULT_MIN_100 && digit <= (INT_64_MULT_MIN_100 * 100 - limit)))) {
+                result = result * 100 - digit;
+                offset += 2;
+            }
+        }
+        if (inRange) {
+            if (offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                digit = ch - '0';
+                if (inRange = (result > INT_64_MULT_MIN_10) || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit))) {
+                    result = result * 10 - digit;
+                    offset++;
+                }
+            }
+            if (inRange) {
+                ch = offset == end ? EOI : chars[offset++];
             }
-            ch = offset == end ? EOI : chars[offset++];
         }
 
         if (ch == '.'
@@ -2496,15 +2537,12 @@ class JSONReaderUTF16
                 || ch == '['
                 || (quote != 0 && ch != quote)
         ) {
-            overflow = true;
+            inRange = false;
         }
 
-        if (overflow) {
+        if (!inRange) {
             readNumber0();
-            if (wasNull) {
-                return null;
-            }
-            return getInt32Value();
+            return getInt64Value();
         }
 
         if (quote != 0) {
@@ -2520,162 +2558,168 @@ class JSONReaderUTF16
         }
 
         if (comma = (ch == ',')) {
-            ch = offset == end ? EOI : chars[offset++];
+            ch = offset == end ? EOI : (char) chars[offset++];
             while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
                 ch = offset == end ? EOI : chars[offset++];
             }
         }
 
-        this.ch = ch;
+        this.ch = (char) ch;
         this.offset = offset;
 
-        return negative ? -intValue : intValue;
+        return negative ? result : -result;
     }
 
     @Override
-    public final long readInt64Value() {
-        boolean negative = false;
-        char ch = this.ch;
-        int offset = this.offset;
-        final char[] chars = this.chars;
+    public final Long readInt64() {
+        int ch = this.ch;
+        if ((ch == '"' || ch == '\'' || ch == 'n') && nextIfNullOrEmptyString()) {
+            return null;
+        }
+        return readInt64Value();
+    }
 
-        long longValue = 0;
+    @Override
+    public final double readDoubleValue() {
+        boolean value = false;
+        double doubleValue = 0;
 
-        char quote = '\0';
+        final char[] chars = this.chars;
+        int quote = '\0';
+        int ch = this.ch;
+        int offset = this.offset, end = this.end;
         if (ch == '"' || ch == '\'') {
             quote = ch;
-            ch = chars[offset++];
-        }
-
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
-        } else if (ch == '+') {
-            ch = chars[offset++];
-        } else if (ch == ',') {
-            throw numberError();
-        }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            long intValue10 = longValue * 10 + (ch - '0');
-            if (intValue10 < longValue) {
-                overflow = true;
-                break;
-            } else {
-                longValue = intValue10;
-            }
             ch = offset == end ? EOI : chars[offset++];
         }
 
-        if (ch == '.'
-                || ch == 'e'
-                || ch == 'E'
-                || ch == 't'
-                || ch == 'f'
-                || ch == 'n'
-                || ch == '{'
-                || ch == '['
-                || (quote != 0 && ch != quote)
-        ) {
-            overflow = true;
-        }
-
-        if (overflow) {
-            readNumber0();
-            return getInt64Value();
-        }
-
-        if (quote != 0) {
-            ch = offset == end ? EOI : chars[offset++];
-        }
-
-        if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-            ch = offset == end ? EOI : chars[offset++];
-        }
-
-        while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = offset == end ? EOI : chars[offset++];
-        }
-
-        if (comma = (ch == ',')) {
+        boolean inRange, negative;
+        boolean wasNull = false;
+        if (quote != 0 && ch == quote) {
             ch = offset == end ? EOI : chars[offset++];
-            while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
+            wasNull = true;
+            inRange = true;
+        } else {
+            long result = 0;
+            if ((negative = (ch == '-')) || ch == '+') {
                 ch = offset == end ? EOI : chars[offset++];
+            } else if (ch == ',') {
+                throw numberError();
             }
-        }
 
-        this.ch = ch;
-        this.offset = offset;
+            long limit = MIN_VALUE + (negative ? 1L : 0L);
+            int digit;
 
-        return negative ? -longValue : longValue;
-    }
+            if (ch == '.') {
+                inRange = true;
+            } else if (inRange = IOUtils.isDigit(ch)) {
+                result = '0' - ch;
 
-    @Override
-    public final Long readInt64() {
-        boolean negative = false;
-        char ch = this.ch;
-        int offset = this.offset;
-        final char[] chars = this.chars;
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(chars, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100)) {
+                        result = result * 100 - digit;
+                        offset += 2;
+                    }
+                }
+                if (offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                    }
+                }
+                ch = offset == end ? EOI : chars[offset++];
+            }
 
-        long longValue = 0;
+            int scale = 0;
+            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
+                ch = offset == end ? EOI : chars[offset++];
+            } else if (ch == '.') {
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(chars, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100 || (result == INT_64_MULT_MIN_100 && digit <= (INT_64_MULT_MIN_100 * 100 - limit)))) {
+                        result = result * 100 - digit;
+                        offset += 2;
+                        scale += 2;
+                    }
+                }
+                if (inRange && offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                        scale++;
+                    }
+                }
 
-        char quote = '\0';
-        if (ch == '"' || ch == '\'') {
-            quote = ch;
-            ch = chars[offset++];
-        }
+                ch = offset == end ? EOI : chars[offset++];
+            }
 
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
-        } else if (ch == '+') {
-            ch = chars[offset++];
-        } else if (ch == ',') {
-            throw numberError();
-        }
+            int expValue = 0;
+            if (ch == 'e' || ch == 'E') {
+                boolean negativeExp;
+                ch = offset == end ? EOI : chars[offset++];
+                if ((negativeExp = (ch == '-')) || ch == '+') {
+                    ch = offset == end ? EOI : chars[offset++];
+                } else if (ch == ',') {
+                    throw numberError();
+                }
+                if (inRange = IOUtils.isDigit(ch)) {
+                    expValue = ch - '0';
+                }
 
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            long intValue10 = longValue * 10 + (ch - '0');
-            if (intValue10 < longValue) {
-                overflow = true;
-                break;
-            } else {
-                longValue = intValue10;
+                while (offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                    digit = ch - '0';
+                    expValue = expValue * 10 + digit;
+                    if (expValue > MAX_EXP) {
+                        throw new JSONException("too large exp value : " + expValue);
+                    }
+                    offset++;
+                }
+                if (negativeExp) {
+                    expValue = -expValue;
+                }
+                scale -= expValue;
+                ch = offset == end ? EOI : chars[offset++];
             }
-            ch = offset == end ? EOI : chars[offset++];
-        }
-
-        if (ch == '.'
-                || ch == 'e'
-                || ch == 'E'
-                || ch == 't'
-                || ch == 'f'
-                || ch == 'n'
-                || ch == '{'
-                || ch == '['
-                || (quote != 0 && ch != quote)
-        ) {
-            overflow = true;
-        }
 
-        if (overflow) {
-            readNumber0();
-            if (wasNull) {
-                return null;
+            if (inRange && quote != 0 && (inRange = (ch == quote))) {
+                ch = offset == end ? EOI : chars[offset++];
             }
-            return getInt64Value();
-        } else {
-            wasNull = false;
-        }
 
-        if (quote != 0) {
-            ch = offset == end ? EOI : chars[offset++];
+            if (inRange) {
+                if (!negative) {
+                    result = -result;
+                }
+                if (scale == 0) {
+                    doubleValue = (double) result;
+                } else if ((long) (double) result == result) {
+                    if (0 < scale && scale < DOUBLE_10_POW.length) {
+                        doubleValue = (double) result / DOUBLE_10_POW[scale];
+                        value = true;
+                    } else if (0 > scale && scale > -DOUBLE_10_POW.length) {
+                        doubleValue = (double) result * DOUBLE_10_POW[-scale];
+                        value = true;
+                    }
+                }
+                if (!value) {
+                    if (scale > -128 && scale < 128) {
+                        doubleValue = TypeUtils.doubleValue(negative ? -1 : 1, Math.abs(result), scale);
+                    } else {
+                        inRange = false;
+                    }
+                }
+            }
         }
 
-        if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-            ch = offset == end ? EOI : chars[offset++];
+        if (!inRange) {
+            readNumber0();
+            return getDoubleValue();
         }
 
         while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
@@ -2689,603 +2733,170 @@ class JSONReaderUTF16
             }
         }
 
-        this.ch = ch;
+        this.wasNull = wasNull;
+        this.ch = (char) ch;
         this.offset = offset;
-
-        return negative ? -longValue : longValue;
+        return doubleValue;
     }
 
     @Override
-    public final double readDoubleValue() {
-        boolean valid = false;
-        this.wasNull = false;
-
+    public final float readFloatValue() {
         boolean value = false;
-        double doubleValue = 0;
+        float floatValue = 0;
 
         final char[] chars = this.chars;
-        char quote = '\0';
-        char ch = this.ch;
-        int offset = this.offset;
+        int quote = '\0';
+        int ch = this.ch;
+        int offset = this.offset, end = this.end;
         if (ch == '"' || ch == '\'') {
             quote = ch;
-            ch = chars[offset++];
+            ch = offset == end ? EOI : chars[offset++];
+        }
 
-            if (ch == quote) {
+        boolean inRange, negative;
+        boolean wasNull = false;
+        if (quote != 0 && ch == quote) {
+            ch = offset == end ? EOI : chars[offset++];
+            wasNull = true;
+            inRange = true;
+        } else {
+            long result = 0;
+            if ((negative = (ch == '-')) || ch == '+') {
                 ch = offset == end ? EOI : chars[offset++];
-                while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                    ch = offset == end ? EOI : chars[offset++];
-                }
-                this.ch = ch;
-                this.offset = offset;
-                nextIfComma();
-                wasNull = true;
-                return 0;
+            } else if (ch == ',') {
+                throw numberError();
             }
-        }
 
-        final int start = offset;
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
-        } else {
-            negative = false;
-            if (ch == '+') {
-                ch = chars[offset++];
-            }
-        }
-
-        valueType = JSON_TYPE_INT;
-        boolean overflow = false;
-        long longValue = 0;
-        while (ch >= '0' && ch <= '9') {
-            valid = true;
-            if (!overflow) {
-                long intValue10 = longValue * 10 + (ch - '0');
-                if (intValue10 < longValue) {
-                    overflow = true;
-                } else {
-                    longValue = intValue10;
-                }
-            }
+            long limit = MIN_VALUE + (negative ? 1L : 0L);
+            int digit;
 
-            if (offset == end) {
-                ch = EOI;
-                offset++;
-                break;
-            }
-            ch = chars[offset++];
-        }
+            if (ch == '.') {
+                inRange = true;
+            } else if (inRange = IOUtils.isDigit(ch)) {
+                result = '0' - ch;
 
-        this.scale = 0;
-        if (ch == '.') {
-            valueType = JSON_TYPE_DEC;
-            ch = chars[offset++];
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                this.scale++;
-                if (!overflow) {
-                    long intValue10 = longValue * 10 + (ch - '0');
-                    if (intValue10 < longValue) {
-                        overflow = true;
-                    } else {
-                        longValue = intValue10;
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(chars, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100)) {
+                        result = result * 100 - digit;
+                        offset += 2;
                     }
                 }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
-                }
-                ch = chars[offset++];
-            }
-        }
-
-        int expValue = 0;
-        if (ch == 'e' || ch == 'E') {
-            boolean negativeExp = false;
-            ch = chars[offset++];
-
-            if (ch == '-') {
-                negativeExp = true;
-                ch = chars[offset++];
-            } else if (ch == '+') {
-                ch = chars[offset++];
-            }
-
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                int byteVal = (ch - '0');
-                expValue = expValue * 10 + byteVal;
-                if (expValue > MAX_EXP) {
-                    throw new JSONException("too large exp value : " + expValue);
-                }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
-                }
-                ch = chars[offset++];
-            }
-
-            if (negativeExp) {
-                expValue = -expValue;
-            }
-
-            this.exponent = (short) expValue;
-            valueType = JSON_TYPE_DEC;
-        }
-
-        if (offset == start) {
-            if (ch == 'n' && chars[offset] == 'u' && chars[offset + 1] == 'l' && chars[offset + 2] == 'l') {
-                offset += 3;
-                valid = true;
-                if ((context.features & Feature.ErrorOnNullForPrimitives.mask) != 0) {
-                    throw new JSONException(info("long value not support input null"));
+                if (offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                    }
                 }
-
-                wasNull = true;
-                value = true;
                 ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 't' && chars[offset] == 'r' && chars[offset + 1] == 'u' && chars[offset + 2] == 'e') {
-                offset += 3;
-                valid = true;
-                value = true;
-                doubleValue = 1;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 'f' && chars[offset] == 'a' && chars[offset + 1] == 'l' && chars[offset + 2] == 's' && chars[offset + 3] == 'e') {
-                valid = true;
-                offset += 4;
-                doubleValue = 0;
-                value = true;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 'N' && chars[offset] == 'a' && chars[offset + 1] == 'N') {
-                valid = true;
-                offset += 2;
-                doubleValue = Double.NaN;
-                value = true;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == '{' && quote == 0) {
-                valid = true;
-                this.ch = ch;
-                this.offset = offset;
-                Map<String, Object> obj = readObject();
-                if (!obj.isEmpty()) {
-                    throw new JSONException(info());
-                }
-                offset = this.offset;
-                ch = this.ch;
-                value = true;
-                wasNull = true;
-            } else if (ch == '[' && quote == 0) {
-                valid = true;
-                this.ch = ch;
-                this.offset = offset;
-                List array = readArray();
-                if (!array.isEmpty()) {
-                    throw new JSONException(info());
-                }
-                offset = this.offset;
-                ch = this.ch;
-                value = true;
-                wasNull = true;
             }
-        }
-
-        int len = offset - start;
-
-        String str = null;
-        if (quote != 0) {
-            if (ch != quote) {
-                this.offset = offset - 1;
-                this.ch = quote;
-                str = readString();
-                offset = this.offset;
-            }
-
-            ch = offset == end ? EOI : chars[offset++];
-        }
-
-        if (!value) {
-            if (!overflow) {
-                if (longValue == 0) {
-                    if (scale == 1) {
-                        doubleValue = 0;
-                        value = true;
-                    }
-                } else {
-                    int scale = this.scale - expValue;
-                    if (scale == 0) {
-                        doubleValue = (double) longValue;
-                        if (negative) {
-                            doubleValue = -doubleValue;
-                        }
-                        value = true;
-                    } else if ((long) (double) longValue == longValue) {
-                        if (0 < scale && scale < DOUBLE_10_POW.length) {
-                            doubleValue = (double) longValue / DOUBLE_10_POW[scale];
-                            if (negative) {
-                                doubleValue = -doubleValue;
-                            }
-                            value = true;
-                        } else if (0 > scale && scale > -DOUBLE_10_POW.length) {
-                            doubleValue = (double) longValue * DOUBLE_10_POW[-scale];
-                            if (negative) {
-                                doubleValue = -doubleValue;
-                            }
-                            value = true;
-                        }
-                    }
 
-                    if (!value && scale > -128 && scale < 128) {
-                        doubleValue = TypeUtils.doubleValue(negative ? -1 : 1, longValue, scale);
-                        value = true;
+            int scale = 0;
+            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
+                ch = offset == end ? EOI : chars[offset++];
+            } else if (ch == '.') {
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(chars, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100 || (result == INT_64_MULT_MIN_100 && digit <= (INT_64_MULT_MIN_100 * 100 - limit)))) {
+                        result = result * 100 - digit;
+                        offset += 2;
+                        scale += 2;
                     }
                 }
-            }
-
-            if (!value) {
-                if (str != null) {
-                    try {
-                        doubleValue = Double.parseDouble(str);
-                    } catch (NumberFormatException ex) {
-                        throw new JSONException(info(), ex);
+                if (inRange && offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                        scale++;
                     }
-                } else {
-                    doubleValue = TypeUtils.parseDouble(chars, start - 1, len);
                 }
-            }
-
-            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-                ch = offset == end ? EOI : chars[offset++];
-            }
-        }
-
-        while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = offset == end ? EOI : chars[offset++];
-        }
 
-        if (comma = (ch == ',')) {
-            ch = offset == end ? EOI : chars[offset++];
-            while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
                 ch = offset == end ? EOI : chars[offset++];
             }
-        }
-
-        if (!valid) {
-            throw new JSONException(info("illegal input error"));
-        }
-
-        this.ch = ch;
-        this.offset = offset;
-        return doubleValue;
-    }
-
-    @Override
-    public final float readFloatValue() {
-        boolean valid = false;
-        this.wasNull = false;
-
-        boolean value = false;
-        float floatValue = 0;
-        final char[] chars = this.chars;
-
-        char quote = '\0';
-        char ch = this.ch;
-        int offset = this.offset;
-        if (ch == '"' || ch == '\'') {
-            quote = ch;
-            ch = chars[offset++];
 
-            if (ch == quote) {
+            int expValue = 0;
+            if (ch == 'e' || ch == 'E') {
+                boolean negativeExp;
                 ch = offset == end ? EOI : chars[offset++];
-                while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
+                if ((negativeExp = (ch == '-')) || ch == '+') {
                     ch = offset == end ? EOI : chars[offset++];
+                } else if (ch == ',') {
+                    throw numberError();
                 }
-                this.ch = ch;
-                this.offset = offset;
-                nextIfComma();
-                wasNull = true;
-                return 0;
-            }
-        }
-
-        final int start = offset;
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
-        } else {
-            negative = false;
-            if (ch == '+') {
-                ch = chars[offset++];
-            }
-        }
-
-        valueType = JSON_TYPE_INT;
-        boolean overflow = false;
-        long longValue = 0;
-
-        while (ch >= '0' && ch <= '9') {
-            valid = true;
-            if (!overflow) {
-                long intValue10 = longValue * 10 + (ch - '0');
-                if (intValue10 < longValue) {
-                    overflow = true;
-                } else {
-                    longValue = intValue10;
+                if (inRange = IOUtils.isDigit(ch)) {
+                    expValue = ch - '0';
                 }
-            }
 
-            if (offset == end) {
-                ch = EOI;
-                offset++;
-                break;
-            }
-            ch = chars[offset++];
-        }
-
-        this.scale = 0;
-        if (ch == '.') {
-            valueType = JSON_TYPE_DEC;
-            ch = chars[offset++];
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                this.scale++;
-                if (!overflow) {
-                    long intValue10 = longValue * 10 + (ch - '0');
-                    if (intValue10 < longValue) {
-                        overflow = true;
-                    } else {
-                        longValue = intValue10;
+                while (offset < end && IOUtils.isDigit((ch = chars[offset]))) {
+                    digit = ch - '0';
+                    expValue = expValue * 10 + digit;
+                    if (expValue > MAX_EXP) {
+                        throw new JSONException("too large exp value : " + expValue);
                     }
-                }
-
-                if (offset == end) {
-                    ch = EOI;
                     offset++;
-                    break;
                 }
-                ch = chars[offset++];
-            }
-        }
-
-        int expValue = 0;
-        if (ch == 'e' || ch == 'E') {
-            boolean negativeExp = false;
-            ch = chars[offset++];
-
-            if (ch == '-') {
-                negativeExp = true;
-                ch = chars[offset++];
-            } else if (ch == '+') {
-                ch = chars[offset++];
-            }
-
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                int byteVal = (ch - '0');
-                expValue = expValue * 10 + byteVal;
-                if (expValue > MAX_EXP) {
-                    throw new JSONException("too large exp value : " + expValue);
-                }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
-                }
-                ch = chars[offset++];
-            }
-
-            if (negativeExp) {
-                expValue = -expValue;
-            }
-
-            this.exponent = (short) expValue;
-            valueType = JSON_TYPE_DEC;
-        }
-
-        if (offset == start) {
-            if (ch == 'n' && chars[offset] == 'u' && chars[offset + 1] == 'l' && chars[offset + 2] == 'l') {
-                offset += 3;
-                valid = true;
-                if ((context.features & Feature.ErrorOnNullForPrimitives.mask) != 0) {
-                    throw new JSONException(info("long value not support input null"));
+                if (negativeExp) {
+                    expValue = -expValue;
                 }
-                wasNull = true;
-                value = true;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 't' && chars[offset] == 'r' && chars[offset + 1] == 'u' && chars[offset + 2] == 'e') {
-                offset += 3;
-                valid = true;
-                value = true;
-                floatValue = 1;
+                scale -= expValue;
                 ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 'f'
-                    && chars[offset] == 'a'
-                    && chars[offset + 1] == 'l'
-                    && chars[offset + 2] == 's'
-                    && chars[offset + 3] == 'e') {
-                offset += 4;
-                valid = true;
-                floatValue = 0;
-                value = true;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 'N' && chars[offset] == 'a' && chars[offset + 1] == 'N') {
-                offset += 2;
-                valid = true;
-                value = true;
-                floatValue = Float.NaN;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == '{' && quote == 0) {
-                valid = true;
-                this.ch = ch;
-                this.offset = offset;
-                Map<String, Object> obj = readObject();
-                if (!obj.isEmpty()) {
-                    throw new JSONException(info());
-                }
-                ch = this.ch;
-                offset = this.offset;
-                value = true;
-                wasNull = true;
-            } else if (ch == '[' && quote == 0) {
-                this.ch = ch;
-                this.offset = offset;
-                valid = true;
-                List array = readArray();
-                if (!array.isEmpty()) {
-                    throw new JSONException(info());
-                }
-                ch = this.ch;
-                offset = this.offset;
-                value = true;
-                wasNull = true;
             }
-        }
 
-        int len = offset - start;
-
-        String str = null;
-        if (quote != 0) {
-            if (ch != quote) {
-                overflow = true;
-                this.offset = offset - 1;
-                this.ch = quote;
-                str = readString();
-                offset = this.offset;
+            if (inRange && quote != 0 && (inRange = (ch == quote))) {
+                ch = offset == end ? EOI : chars[offset++];
             }
 
-            ch = offset >= end ? EOI : chars[offset++];
-        }
-
-        if (!value) {
-            if (!overflow) {
-                int scale = this.scale - expValue;
+            if (inRange) {
+                if (!negative) {
+                    result = -result;
+                }
                 if (scale == 0) {
-                    floatValue = (float) longValue;
-                    if (negative) {
-                        floatValue = -floatValue;
-                    }
-                    value = true;
-                } else if ((long) (float) longValue == longValue) {
+                    floatValue = (float) result;
+                } else if ((long) (float) result == result) {
                     if (0 < scale && scale < FLOAT_10_POW.length) {
-                        floatValue = (float) longValue / FLOAT_10_POW[scale];
-                        if (negative) {
-                            floatValue = -floatValue;
-                        }
+                        floatValue = (float) result / FLOAT_10_POW[scale];
+                        value = true;
                     } else if (0 > scale && scale > -FLOAT_10_POW.length) {
-                        floatValue = (float) longValue * FLOAT_10_POW[-scale];
-                        if (negative) {
-                            floatValue = -floatValue;
-                        }
+                        floatValue = (float) result * FLOAT_10_POW[-scale];
+                        value = true;
                     }
                 }
-
-                if (!value && scale > -128 && scale < 128) {
-                    floatValue = TypeUtils.floatValue(negative ? -1 : 1, longValue, scale);
-                    value = true;
-                }
-            }
-
-            if (!value) {
-                if (str != null) {
-                    try {
-                        floatValue = Float.parseFloat(str);
-                    } catch (NumberFormatException ex) {
-                        throw new JSONException(info(), ex);
+                if (!value) {
+                    if (scale > -128 && scale < 128) {
+                        floatValue = TypeUtils.floatValue(negative ? -1 : 1, Math.abs(result), scale);
+                    } else {
+                        inRange = false;
                     }
-                } else {
-                    floatValue = TypeUtils.parseFloat(chars, start - 1, len);
                 }
             }
-
-            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-                ch = offset >= end ? EOI : chars[offset++];
-            }
-        }
-
-        while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = offset >= end ? EOI : chars[offset++];
-        }
-
-        if (this.comma = ch == ',') {
-            ch = offset >= end ? EOI : chars[offset++];
-            while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                ch = offset >= end ? EOI : chars[offset++];
-            }
         }
 
-        if (!valid) {
-            throw new JSONException(info("illegal input error"));
-        }
-
-        this.ch = ch;
-        this.offset = offset;
-        return floatValue;
-    }
-
-    private void skipString() {
-        char[] chars = this.chars;
-        int offset = this.offset;
-        char quote = this.ch;
-        char ch = chars[offset++];
-        for (; ; ) {
-            if (ch == '\\') {
-                if (offset >= end) {
-                    throw new JSONException(info("illegal string, end"));
-                }
-
-                ch = chars[offset++];
-                if (ch == 'u') {
-                    offset += 4;
-                } else if (ch == 'x') {
-                    offset += 2;
-                } else if (ch != '\\' && ch != '"') {
-                    char1(ch);
-                }
-                ch = chars[offset++];
-                continue;
-            }
-
-            if (ch == quote) {
-                ch = offset == end ? chars[offset++] : EOI;
-                break;
-            }
-
-            ch = offset == end ? chars[offset++] : EOI;
+        if (!inRange) {
+            readNumber0();
+            return getFloatValue();
         }
 
         while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = chars[offset++];
+            ch = offset == end ? EOI : chars[offset++];
         }
 
         if (comma = (ch == ',')) {
-            if (offset >= end) {
-                this.offset = offset;
-                this.ch = EOI;
-                return;
-            }
-
-            ch = chars[offset];
+            ch = offset == end ? EOI : chars[offset++];
             while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                offset++;
-                if (offset >= end) {
-                    this.offset = offset;
-                    this.ch = EOI;
-                    return;
-                }
-                ch = chars[offset];
+                ch = offset == end ? EOI : chars[offset++];
             }
-            offset++;
-        } else if (ch != '}' && ch != ']' && ch != EOI) {
-            throw error(offset, ch);
         }
 
+        this.wasNull = wasNull;
+        this.ch = (char) ch;
         this.offset = offset;
-        this.ch = ch;
+        return floatValue;
     }
 
     @Override
@@ -4051,6 +3662,12 @@ class JSONReaderUTF16
                 boolValue = false;
                 valueType = JSON_TYPE_BOOL;
                 ch = offset == end ? EOI : chars[offset++];
+            } else if (ch == 'N' && chars[offset] == 'a' && chars[offset + 1] == 'N') {
+                offset += 2;
+                valid = true;
+                boolValue = true;
+                valueType = JSON_TYPE_NaN;
+                ch = offset == end ? EOI : chars[offset++];
             } else if (ch == '{' && quote == 0) {
                 this.offset = offset;
                 this.ch = ch;
diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java
index 50a294868..640a08448 100644
--- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java
+++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java
@@ -11,8 +11,9 @@ import java.time.*;
 import java.util.*;
 
 import static com.alibaba.fastjson2.JSONFactory.*;
-import static com.alibaba.fastjson2.util.IOUtils.ALSE;
+import static com.alibaba.fastjson2.util.IOUtils.*;
 import static com.alibaba.fastjson2.util.JDKUtils.*;
+import static java.lang.Long.MIN_VALUE;
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
@@ -3486,38 +3487,49 @@ class JSONReaderUTF8
 
     @Override
     public final int readInt32Value() {
-        boolean negative = false;
         int ch = this.ch;
         int offset = this.offset, end = this.end;
         final byte[] bytes = this.bytes;
 
-        int intValue = 0;
-
         int quote = '\0';
         if (ch == '"' || ch == '\'') {
             quote = ch;
             ch = bytes[offset++];
         }
 
-        if (ch == '-') {
-            negative = true;
-            ch = bytes[offset++];
-        } else if (ch == '+') {
-            ch = bytes[offset++];
+        int result = 0;
+        boolean inRange, negative;
+        if ((negative = (ch == '-')) || ch == '+') {
+            ch = offset == end ? EOI : bytes[offset++];
         } else if (ch == ',') {
             throw numberError();
         }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            int intValue10 = intValue * 10 + (ch - '0');
-            if (intValue10 < intValue) {
-                overflow = true;
-                break;
-            } else {
-                intValue = intValue10;
+        if (inRange = IOUtils.isDigit(ch)) {
+            result = '0' - ch;
+        }
+        int limit = Integer.MIN_VALUE + (negative ? 0 : 1);
+        int digit;
+        while (inRange
+                && offset + 1 < end
+                && (digit = IOUtils.digit2(bytes, offset)) != -1
+        ) {
+            // max digits is 19, no need to check inRange (result == MULT_MIN_100 && digit <= (MULT_MIN_100 * 100 - limit))
+            if (inRange = (result > INT_32_MULT_MIN_100)) {
+                result = result * 100 - digit;
+                offset += 2;
+            }
+        }
+        if (inRange) {
+            if (offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                digit = ch - '0';
+                if (inRange = (result > INT_32_MULT_MIN_10 || (result == INT_32_MULT_MIN_10 && digit <= (INT_32_MULT_MIN_10 * 10 - limit)))) {
+                    result = result * 10 - digit;
+                    offset++;
+                }
+            }
+            if (inRange) {
+                ch = offset == end ? EOI : bytes[offset++];
             }
-            ch = offset == end ? EOI : bytes[offset++];
         }
 
         if (ch == '.'
@@ -3530,10 +3542,10 @@ class JSONReaderUTF8
                 || ch == '['
                 || (quote != 0 && ch != quote)
         ) {
-            overflow = true;
+            inRange = false;
         }
 
-        if (overflow) {
+        if (!inRange) {
             readNumber0();
             return getInt32Value();
         }
@@ -3551,7 +3563,7 @@ class JSONReaderUTF8
         }
 
         if (comma = (ch == ',')) {
-            ch = offset == end ? EOI : bytes[offset++];
+            ch = offset == end ? EOI : (char) bytes[offset++];
             while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
                 ch = offset == end ? EOI : bytes[offset++];
             }
@@ -3560,125 +3572,62 @@ class JSONReaderUTF8
         this.ch = (char) ch;
         this.offset = offset;
 
-        return negative ? -intValue : intValue;
+        return negative ? result : -result;
     }
 
     @Override
     public final Integer readInt32() {
-        boolean negative = false;
         int ch = this.ch;
-        int offset = this.offset;
-        final byte[] bytes = this.bytes;
-
-        int intValue = 0;
-
-        int quote = '\0';
-        if (ch == '"' || ch == '\'') {
-            quote = ch;
-            ch = bytes[offset++];
-        }
-
-        if (ch == '-') {
-            negative = true;
-            ch = bytes[offset++];
-        } else if (ch == '+') {
-            ch = bytes[offset++];
-        } else if (ch == ',') {
-            throw numberError();
-        }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            int intValue10 = intValue * 10 + (ch - '0');
-            if (intValue10 < intValue) {
-                overflow = true;
-                break;
-            } else {
-                intValue = intValue10;
-            }
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        if (ch == '.'
-                || ch == 'e'
-                || ch == 'E'
-                || ch == 't'
-                || ch == 'f'
-                || ch == 'n'
-                || ch == '{'
-                || ch == '['
-                || (quote != 0 && ch != quote)
-        ) {
-            overflow = true;
-        }
-
-        if (overflow) {
-            readNumber0();
-            if (wasNull) {
-                return null;
-            }
-            return getInt32Value();
-        }
-
-        if (quote != 0) {
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        if (comma = (ch == ',')) {
-            ch = offset == end ? EOI : bytes[offset++];
-            while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                ch = offset == end ? EOI : bytes[offset++];
-            }
+        if ((ch == '"' || ch == '\'' || ch == 'n') && nextIfNullOrEmptyString()) {
+            return null;
         }
-
-        this.ch = (char) ch;
-        this.offset = offset;
-
-        return negative ? -intValue : intValue;
+        return readInt32Value();
     }
 
     @Override
     public final long readInt64Value() {
-        boolean negative = false;
         int ch = this.ch;
-        int offset = this.offset;
+        int offset = this.offset, end = this.end;
         final byte[] bytes = this.bytes;
 
-        long longValue = 0;
-
         int quote = '\0';
         if (ch == '"' || ch == '\'') {
             quote = ch;
             ch = bytes[offset++];
         }
 
-        if (ch == '-') {
-            negative = true;
-            ch = bytes[offset++];
-        } else if (ch == '+') {
-            ch = bytes[offset++];
+        long result = 0;
+        boolean inRange, negative;
+        if ((negative = (ch == '-')) || ch == '+') {
+            ch = offset == end ? EOI : bytes[offset++];
         } else if (ch == ',') {
             throw numberError();
         }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            long intValue10 = longValue * 10 + (ch - '0');
-            if (intValue10 < longValue) {
-                overflow = true;
-                break;
-            } else {
-                longValue = intValue10;
+        if (inRange = IOUtils.isDigit(ch)) {
+            result = '0' - ch;
+        }
+        long limit = MIN_VALUE + (negative ? 0L : 1L);
+        int digit;
+        while (inRange
+                && offset + 1 < end
+                && (digit = IOUtils.digit2(bytes, offset)) != -1
+        ) {
+            if (inRange = (result > INT_64_MULT_MIN_100 || (result == INT_64_MULT_MIN_100 && digit <= (INT_64_MULT_MIN_100 * 100 - limit)))) {
+                result = result * 100 - digit;
+                offset += 2;
+            }
+        }
+        if (inRange) {
+            if (offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                digit = ch - '0';
+                if (inRange = (result > INT_64_MULT_MIN_10) || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit))) {
+                    result = result * 10 - digit;
+                    offset++;
+                }
+            }
+            if (inRange) {
+                ch = offset == end ? EOI : bytes[offset++];
             }
-            ch = offset == end ? EOI : bytes[offset++];
         }
 
         if (ch == '.'
@@ -3691,15 +3640,14 @@ class JSONReaderUTF8
                 || ch == '['
                 || (quote != 0 && ch != quote)
         ) {
-            overflow = true;
+            inRange = false;
         }
 
-        if (overflow) {
+        if (!inRange) {
             readNumber0();
             return getInt64Value();
         }
 
-        int end = this.end;
         if (quote != 0) {
             ch = offset == end ? EOI : bytes[offset++];
         }
@@ -3722,339 +3670,159 @@ class JSONReaderUTF8
         this.ch = (char) ch;
         this.offset = offset;
 
-        return negative ? -longValue : longValue;
+        return negative ? result : -result;
     }
 
     @Override
     public final Long readInt64() {
-        boolean negative = false;
         int ch = this.ch;
-        int offset = this.offset;
-        final byte[] bytes = this.bytes;
-
-        long longValue = 0;
-
-        int quote = '\0';
-        if (ch == '"' || ch == '\'') {
-            quote = ch;
-            ch = bytes[offset++];
-        }
-
-        if (ch == '-') {
-            negative = true;
-            ch = bytes[offset++];
-        } else if (ch == '+') {
-            ch = bytes[offset++];
-        } else if (ch == ',') {
-            throw numberError();
-        }
-
-        boolean overflow = ch < '0' || ch > '9';
-        while (ch >= '0' && ch <= '9') {
-            long intValue10 = longValue * 10 + (ch - '0');
-            if (intValue10 < longValue) {
-                overflow = true;
-                break;
-            } else {
-                longValue = intValue10;
-            }
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        if (ch == '.'
-                || ch == 'e'
-                || ch == 'E'
-                || ch == 't'
-                || ch == 'f'
-                || ch == 'n'
-                || ch == '{'
-                || ch == '['
-                || (quote != 0 && ch != quote)
-        ) {
-            overflow = true;
-        }
-
-        if (overflow) {
-            readNumber0();
-            if (wasNull) {
-                return null;
-            }
-            return getInt64Value();
-        } else {
-            wasNull = false;
-        }
-
-        if (quote != 0) {
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = offset == end ? EOI : bytes[offset++];
-        }
-
-        if (comma = (ch == ',')) {
-            ch = offset == end ? EOI : (char) bytes[offset++];
-            while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                ch = offset == end ? EOI : bytes[offset++];
-            }
+        if ((ch == '"' || ch == '\'' || ch == 'n') && nextIfNullOrEmptyString()) {
+            return null;
         }
-
-        this.ch = (char) ch;
-        this.offset = offset;
-
-        return negative ? -longValue : longValue;
+        return readInt64Value();
     }
 
     @Override
     public final double readDoubleValue() {
-        boolean valid = false;
-        this.wasNull = false;
-
         boolean value = false;
         double doubleValue = 0;
 
         final byte[] bytes = this.bytes;
         int quote = '\0';
         int ch = this.ch;
-        int offset = this.offset;
+        int offset = this.offset, end = this.end;
         if (ch == '"' || ch == '\'') {
             quote = ch;
-            ch = bytes[offset++];
-
-            if (ch == quote) {
-                ch = offset == end ? EOI : bytes[offset++];
-                while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                    ch = offset == end ? EOI : bytes[offset++];
-                }
-                this.ch = (char) ch;
-                this.offset = offset;
-                nextIfComma();
-                wasNull = true;
-                return 0;
-            }
+            ch = offset == end ? EOI : bytes[offset++];
         }
 
-        final int start = offset;
-        if (ch == '-') {
-            negative = true;
-            ch = bytes[offset++];
+        boolean inRange, negative;
+        boolean wasNull = false;
+        if (quote != 0 && ch == quote) {
+            ch = offset == end ? EOI : bytes[offset++];
+            wasNull = true;
+            inRange = true;
         } else {
-            negative = false;
-            if (ch == '+') {
-                ch = bytes[offset++];
-            }
-        }
-
-        valueType = JSON_TYPE_INT;
-        boolean overflow = false;
-        long longValue = 0;
-        while (ch >= '0' && ch <= '9') {
-            valid = true;
-            if (!overflow) {
-                long intValue10 = longValue * 10 + (ch - '0');
-                if (intValue10 < longValue) {
-                    overflow = true;
-                } else {
-                    longValue = intValue10;
-                }
-            }
-
-            if (offset == end) {
-                ch = EOI;
-                offset++;
-                break;
-            }
-            ch = bytes[offset++];
-        }
-
-        this.scale = 0;
-        if (ch == '.') {
-            valueType = JSON_TYPE_DEC;
-            ch = bytes[offset++];
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                this.scale++;
-                if (!overflow) {
-                    long intValue10 = longValue * 10 + (ch - '0');
-                    if (intValue10 < longValue) {
-                        overflow = true;
-                    } else {
-                        longValue = intValue10;
-                    }
-                }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
-                }
-                ch = bytes[offset++];
-            }
-        }
-
-        int expValue = 0;
-        if (ch == 'e' || ch == 'E') {
-            boolean negativeExp = false;
-            ch = bytes[offset++];
-
-            if (ch == '-') {
-                negativeExp = true;
-                ch = bytes[offset++];
-            } else if (ch == '+') {
-                ch = bytes[offset++];
-            }
-
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                int byteVal = (ch - '0');
-                expValue = expValue * 10 + byteVal;
-                if (expValue > MAX_EXP) {
-                    throw new JSONException("too large exp value : " + expValue);
-                }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
-                }
-                ch = bytes[offset++];
-            }
-
-            if (negativeExp) {
-                expValue = -expValue;
-            }
-
-            this.exponent = (short) expValue;
-            valueType = JSON_TYPE_DEC;
-        }
-
-        if (offset == start) {
-            if (ch == 'n' && bytes[offset] == 'u' && bytes[offset + 1] == 'l' && bytes[offset + 2] == 'l') {
-                offset += 3;
-                valid = true;
-                if ((context.features & Feature.ErrorOnNullForPrimitives.mask) != 0) {
-                    throw new JSONException(info("long value not support input null"));
-                }
-
-                wasNull = true;
-                value = true;
+            long result = 0;
+            if ((negative = (ch == '-')) || ch == '+') {
                 ch = offset == end ? EOI : bytes[offset++];
-            } else if (ch == 't' && bytes[offset] == 'r' && bytes[offset + 1] == 'u' && bytes[offset + 2] == 'e') {
-                offset += 3;
-                valid = true;
-                value = true;
-                doubleValue = 1;
-                ch = offset == end ? EOI : bytes[offset++];
-            } else if (ch == 'f' && bytes[offset] == 'a' && bytes[offset + 1] == 'l' && bytes[offset + 2] == 's' && bytes[offset + 3] == 'e') {
-                valid = true;
-                offset += 4;
-                doubleValue = 0;
-                value = true;
-                ch = offset == end ? EOI : bytes[offset++];
-            } else if (ch == 'N' && bytes[offset] == 'a' && bytes[offset + 1] == 'N') {
-                valid = true;
-                offset += 2;
-                doubleValue = Double.NaN;
-                value = true;
-                ch = offset == end ? EOI : bytes[offset++];
-            } else if (ch == '{' && quote == 0) {
-                valid = true;
-                this.ch = (char) ch;
-                this.offset = offset;
-                Map<String, Object> obj = readObject();
-                if (!obj.isEmpty()) {
-                    throw new JSONException(info());
-                }
-                offset = this.offset;
-                ch = this.ch;
-                value = true;
-                wasNull = true;
-            } else if (ch == '[' && quote == 0) {
-                valid = true;
-                this.ch = (char) ch;
-                this.offset = offset;
-                List array = readArray();
-                if (!array.isEmpty()) {
-                    throw new JSONException(info());
-                }
-                offset = this.offset;
-                ch = this.ch;
-                value = true;
-                wasNull = true;
+            } else if (ch == ',') {
+                throw numberError();
             }
-        }
-
-        int len = offset - start;
 
-        String str = null;
-        if (quote != 0) {
-            if (ch != quote) {
-                this.offset = offset - 1;
-                this.ch = (char) quote;
-                str = readString();
-                offset = this.offset;
-            }
+            long limit = MIN_VALUE + (negative ? 1L : 0L);
+            int digit;
 
-            ch = offset == end ? EOI : bytes[offset++];
-        }
+            if (ch == '.') {
+                inRange = true;
+            } else if (inRange = IOUtils.isDigit(ch)) {
+                result = '0' - ch;
 
-        if (!value) {
-            if (!overflow) {
-                if (longValue == 0) {
-                    if (scale == 1) {
-                        doubleValue = 0;
-                        value = true;
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(bytes, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100)) {
+                        result = result * 100 - digit;
+                        offset += 2;
                     }
-                } else {
-                    int scale = this.scale - expValue;
-                    if (scale == 0) {
-                        doubleValue = (double) longValue;
-                        if (negative) {
-                            doubleValue = -doubleValue;
-                        }
-                        value = true;
-                    } else if ((long) (double) longValue == longValue) {
-                        if (0 < scale && scale < DOUBLE_10_POW.length) {
-                            doubleValue = (double) longValue / DOUBLE_10_POW[scale];
-                            if (negative) {
-                                doubleValue = -doubleValue;
-                            }
-                            value = true;
-                        } else if (0 > scale && scale > -DOUBLE_10_POW.length) {
-                            doubleValue = (double) longValue * DOUBLE_10_POW[-scale];
-                            if (negative) {
-                                doubleValue = -doubleValue;
-                            }
-                            value = true;
-                        }
+                }
+                if (offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
                     }
+                }
+                ch = offset == end ? EOI : bytes[offset++];
+            }
 
-                    if (!value && scale > -128 && scale < 128) {
-                        doubleValue = TypeUtils.doubleValue(negative ? -1 : 1, longValue, scale);
-                        value = true;
+            int scale = 0;
+            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
+                ch = offset == end ? EOI : bytes[offset++];
+            } else if (ch == '.') {
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(bytes, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100 || (result == INT_64_MULT_MIN_100 && digit <= (INT_64_MULT_MIN_100 * 100 - limit)))) {
+                        result = result * 100 - digit;
+                        offset += 2;
+                        scale += 2;
+                    }
+                }
+                if (inRange && offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                        scale++;
                     }
                 }
+
+                ch = offset == end ? EOI : bytes[offset++];
             }
 
-            if (!value) {
-                if (str != null) {
-                    try {
-                        doubleValue = Double.parseDouble(str);
-                    } catch (NumberFormatException ex) {
-                        throw new JSONException(info(), ex);
+            int expValue = 0;
+            if (ch == 'e' || ch == 'E') {
+                boolean negativeExp;
+                ch = offset == end ? EOI : bytes[offset++];
+                if ((negativeExp = (ch == '-')) || ch == '+') {
+                    ch = offset == end ? EOI : bytes[offset++];
+                } else if (ch == ',') {
+                    throw numberError();
+                }
+                if (inRange = IOUtils.isDigit(ch)) {
+                    expValue = ch - '0';
+                }
+
+                while (offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                    digit = ch - '0';
+                    expValue = expValue * 10 + digit;
+                    if (expValue > MAX_EXP) {
+                        throw new JSONException("too large exp value : " + expValue);
                     }
-                } else {
-                    doubleValue = TypeUtils.parseDouble(bytes, start - 1, len);
+                    offset++;
                 }
+                if (negativeExp) {
+                    expValue = -expValue;
+                }
+                scale -= expValue;
+                ch = offset == end ? EOI : bytes[offset++];
             }
 
-            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
+            if (inRange && quote != 0 && (inRange = (ch == quote))) {
                 ch = offset == end ? EOI : bytes[offset++];
             }
+
+            if (inRange) {
+                if (!negative) {
+                    result = -result;
+                }
+                if (scale == 0) {
+                    doubleValue = (double) result;
+                } else if ((long) (double) result == result) {
+                    if (0 < scale && scale < DOUBLE_10_POW.length) {
+                        doubleValue = (double) result / DOUBLE_10_POW[scale];
+                        value = true;
+                    } else if (0 > scale && scale > -DOUBLE_10_POW.length) {
+                        doubleValue = (double) result * DOUBLE_10_POW[-scale];
+                        value = true;
+                    }
+                }
+                if (!value) {
+                    if (scale > -128 && scale < 128) {
+                        doubleValue = TypeUtils.doubleValue(negative ? -1 : 1, Math.abs(result), scale);
+                    } else {
+                        inRange = false;
+                    }
+                }
+            }
+        }
+
+        if (!inRange) {
+            readNumber0();
+            return getDoubleValue();
         }
 
         while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
@@ -4068,10 +3836,7 @@ class JSONReaderUTF8
             }
         }
 
-        if (!valid) {
-            throw new JSONException(info("illegal input error"));
-        }
-
+        this.wasNull = wasNull;
         this.ch = (char) ch;
         this.offset = offset;
         return doubleValue;
@@ -4079,263 +3844,159 @@ class JSONReaderUTF8
 
     @Override
     public final float readFloatValue() {
-        boolean valid = false;
-        this.wasNull = false;
-
         boolean value = false;
         float floatValue = 0;
-        final byte[] chars = this.bytes;
 
+        final byte[] bytes = this.bytes;
         int quote = '\0';
         int ch = this.ch;
-        int offset = this.offset;
+        int offset = this.offset, end = this.end;
         if (ch == '"' || ch == '\'') {
             quote = ch;
-            ch = chars[offset++];
-
-            if (ch == quote) {
-                ch = offset == end ? EOI : chars[offset++];
-                while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                    ch = offset == end ? EOI : chars[offset++];
-                }
-                this.ch = (char) ch;
-                this.offset = offset;
-                nextIfComma();
-                wasNull = true;
-                return 0;
-            }
+            ch = offset == end ? EOI : bytes[offset++];
         }
 
-        final int start = offset;
-        if (ch == '-') {
-            negative = true;
-            ch = chars[offset++];
+        boolean inRange, negative;
+        boolean wasNull = false;
+        if (quote != 0 && ch == quote) {
+            ch = offset == end ? EOI : bytes[offset++];
+            wasNull = true;
+            inRange = true;
         } else {
-            negative = false;
-            if (ch == '+') {
-                ch = chars[offset++];
+            long result = 0;
+            if ((negative = (ch == '-')) || ch == '+') {
+                ch = offset == end ? EOI : bytes[offset++];
+            } else if (ch == ',') {
+                throw numberError();
             }
-        }
-
-        valueType = JSON_TYPE_INT;
-        boolean overflow = false;
-        long longValue = 0;
 
-        while (ch >= '0' && ch <= '9') {
-            valid = true;
-            if (!overflow) {
-                long intValue10 = longValue * 10 + (ch - '0');
-                if (intValue10 < longValue) {
-                    overflow = true;
-                } else {
-                    longValue = intValue10;
-                }
-            }
+            long limit = MIN_VALUE + (negative ? 1L : 0L);
+            int digit;
 
-            if (offset == end) {
-                ch = EOI;
-                offset++;
-                break;
-            }
-            ch = chars[offset++];
-        }
+            if (ch == '.') {
+                inRange = true;
+            } else if (inRange = IOUtils.isDigit(ch)) {
+                result = '0' - ch;
 
-        this.scale = 0;
-        if (ch == '.') {
-            valueType = JSON_TYPE_DEC;
-            ch = chars[offset++];
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                this.scale++;
-                if (!overflow) {
-                    long intValue10 = longValue * 10 + (ch - '0');
-                    if (intValue10 < longValue) {
-                        overflow = true;
-                    } else {
-                        longValue = intValue10;
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(bytes, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100)) {
+                        result = result * 100 - digit;
+                        offset += 2;
                     }
                 }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
+                if (offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                    }
                 }
-                ch = chars[offset++];
-            }
-        }
-
-        int expValue = 0;
-        if (ch == 'e' || ch == 'E') {
-            boolean negativeExp = false;
-            ch = chars[offset++];
-
-            if (ch == '-') {
-                negativeExp = true;
-                ch = chars[offset++];
-            } else if (ch == '+') {
-                ch = chars[offset++];
+                ch = offset == end ? EOI : bytes[offset++];
             }
 
-            while (ch >= '0' && ch <= '9') {
-                valid = true;
-                int byteVal = (ch - '0');
-                expValue = expValue * 10 + byteVal;
-                if (expValue > MAX_EXP) {
-                    throw new JSONException("too large exp value : " + expValue);
+            int scale = 0;
+            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
+                ch = offset == end ? EOI : bytes[offset++];
+            } else if (ch == '.') {
+                while (inRange
+                        && offset + 1 < end
+                        && (digit = IOUtils.digit2(bytes, offset)) != -1
+                ) {
+                    if (inRange = (result > INT_64_MULT_MIN_100 || (result == INT_64_MULT_MIN_100 && digit <= (INT_64_MULT_MIN_100 * 100 - limit)))) {
+                        result = result * 100 - digit;
+                        offset += 2;
+                        scale += 2;
+                    }
                 }
-
-                if (offset == end) {
-                    ch = EOI;
-                    offset++;
-                    break;
+                if (inRange && offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                    digit = ch - '0';
+                    if (inRange = (result > INT_64_MULT_MIN_10 || (result == INT_64_MULT_MIN_10 && digit <= (INT_64_MULT_MIN_10 * 10 - limit)))) {
+                        result = result * 10 - digit;
+                        offset++;
+                        scale++;
+                    }
                 }
-                ch = chars[offset++];
-            }
 
-            if (negativeExp) {
-                expValue = -expValue;
+                ch = offset == end ? EOI : bytes[offset++];
             }
 
-            this.exponent = (short) expValue;
-            valueType = JSON_TYPE_DEC;
-        }
-
-        if (offset == start) {
-            if (ch == 'n' && chars[offset] == 'u' && chars[offset + 1] == 'l' && chars[offset + 2] == 'l') {
-                offset += 3;
-                valid = true;
-                if ((context.features & Feature.ErrorOnNullForPrimitives.mask) != 0) {
-                    throw new JSONException(info("long value not support input null"));
+            int expValue = 0;
+            if (ch == 'e' || ch == 'E') {
+                boolean negativeExp;
+                ch = offset == end ? EOI : bytes[offset++];
+                if ((negativeExp = (ch == '-')) || ch == '+') {
+                    ch = offset == end ? EOI : bytes[offset++];
+                } else if (ch == ',') {
+                    throw numberError();
                 }
-                wasNull = true;
-                value = true;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 't' && chars[offset] == 'r' && chars[offset + 1] == 'u' && chars[offset + 2] == 'e') {
-                offset += 3;
-                valid = true;
-                value = true;
-                floatValue = 1;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 'f'
-                    && chars[offset] == 'a'
-                    && chars[offset + 1] == 'l'
-                    && chars[offset + 2] == 's'
-                    && chars[offset + 3] == 'e') {
-                offset += 4;
-                valid = true;
-                floatValue = 0;
-                value = true;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == 'N' && chars[offset] == 'a' && chars[offset + 1] == 'N') {
-                offset += 2;
-                valid = true;
-                value = true;
-                floatValue = Float.NaN;
-                ch = offset == end ? EOI : chars[offset++];
-            } else if (ch == '{' && quote == 0) {
-                valid = true;
-                this.ch = (char) ch;
-                this.offset = offset;
-                Map<String, Object> obj = readObject();
-                if (!obj.isEmpty()) {
-                    throw new JSONException(info());
+                if (inRange = IOUtils.isDigit(ch)) {
+                    expValue = ch - '0';
                 }
-                ch = this.ch;
-                offset = this.offset;
-                value = true;
-                wasNull = true;
-            } else if (ch == '[' && quote == 0) {
-                this.ch = (char) ch;
-                this.offset = offset;
-                valid = true;
-                List array = readArray();
-                if (!array.isEmpty()) {
-                    throw new JSONException(info());
+
+                while (offset < end && IOUtils.isDigit((ch = bytes[offset]))) {
+                    digit = ch - '0';
+                    expValue = expValue * 10 + digit;
+                    if (expValue > MAX_EXP) {
+                        throw new JSONException("too large exp value : " + expValue);
+                    }
+                    offset++;
                 }
-                ch = this.ch;
-                offset = this.offset;
-                value = true;
-                wasNull = true;
+                if (negativeExp) {
+                    expValue = -expValue;
+                }
+                scale -= expValue;
+                ch = offset == end ? EOI : bytes[offset++];
             }
-        }
-
-        int len = offset - start;
 
-        String str = null;
-        if (quote != 0) {
-            if (ch != quote) {
-                overflow = true;
-                this.offset = offset - 1;
-                this.ch = (char) quote;
-                str = readString();
-                offset = this.offset;
+            if (inRange && quote != 0 && (inRange = (ch == quote))) {
+                ch = offset == end ? EOI : bytes[offset++];
             }
 
-            ch = offset >= end ? EOI : chars[offset++];
-        }
-
-        if (!value) {
-            if (!overflow) {
-                int scale = this.scale - expValue;
+            if (inRange) {
+                if (!negative) {
+                    result = -result;
+                }
                 if (scale == 0) {
-                    floatValue = (float) longValue;
-                    if (negative) {
-                        floatValue = -floatValue;
-                    }
-                    value = true;
-                } else if ((long) (float) longValue == longValue) {
+                    floatValue = (float) result;
+                } else if ((long) (float) result == result) {
                     if (0 < scale && scale < FLOAT_10_POW.length) {
-                        floatValue = (float) longValue / FLOAT_10_POW[scale];
-                        if (negative) {
-                            floatValue = -floatValue;
-                        }
+                        floatValue = (float) result / FLOAT_10_POW[scale];
+                        value = true;
                     } else if (0 > scale && scale > -FLOAT_10_POW.length) {
-                        floatValue = (float) longValue * FLOAT_10_POW[-scale];
-                        if (negative) {
-                            floatValue = -floatValue;
-                        }
+                        floatValue = (float) result * FLOAT_10_POW[-scale];
+                        value = true;
                     }
                 }
-
-                if (!value && scale > -128 && scale < 128) {
-                    floatValue = TypeUtils.floatValue(negative ? -1 : 1, longValue, scale);
-                    value = true;
-                }
-            }
-
-            if (!value) {
-                if (str != null) {
-                    try {
-                        floatValue = Float.parseFloat(str);
-                    } catch (NumberFormatException ex) {
-                        throw new JSONException(info(), ex);
+                if (!value) {
+                    if (scale > -128 && scale < 128) {
+                        floatValue = TypeUtils.floatValue(negative ? -1 : 1, Math.abs(result), scale);
+                    } else {
+                        inRange = false;
                     }
-                } else {
-                    floatValue = TypeUtils.parseFloat(chars, start - 1, len);
                 }
             }
+        }
 
-            if (ch == 'L' || ch == 'F' || ch == 'D' || ch == 'B' || ch == 'S') {
-                ch = offset >= end ? EOI : chars[offset++];
-            }
+        if (!inRange) {
+            readNumber0();
+            return getFloatValue();
         }
 
         while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-            ch = offset >= end ? EOI : chars[offset++];
+            ch = offset == end ? EOI : bytes[offset++];
         }
 
-        if (this.comma = ch == ',') {
-            ch = offset >= end ? EOI : chars[offset++];
+        if (comma = (ch == ',')) {
+            ch = offset == end ? EOI : bytes[offset++];
             while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
-                ch = offset >= end ? EOI : chars[offset++];
+                ch = offset == end ? EOI : bytes[offset++];
             }
         }
 
-        if (!valid) {
-            throw new JSONException(info("illegal input error"));
-        }
-
+        this.wasNull = wasNull;
         this.ch = (char) ch;
         this.offset = offset;
         return floatValue;
@@ -5366,12 +5027,11 @@ class JSONReaderUTF8
 
         final int start = offset;
 
-        final int multmin;
+        final int multmin = INT_32_MULT_MIN_10;
         if (ch == '-') {
             if (offset == end) {
                 throw new JSONException(info("illegal input"));
             }
-            multmin = -214748364; // limit / 10;
             negative = true;
             ch = bytes[offset++];
         } else {
@@ -5381,7 +5041,6 @@ class JSONReaderUTF8
                 }
                 ch = bytes[offset++];
             }
-            multmin = -214748364; // limit / 10;
         }
 
         // if (result < limit + digit) {
@@ -5514,6 +5173,12 @@ class JSONReaderUTF8
                     valueType = JSON_TYPE_BOOL;
                     ch = offset == end ? EOI : bytes[offset++];
                 }
+            } else if (ch == 'N' && bytes[offset] == 'a' && bytes[offset + 1] == 'N') {
+                offset += 2;
+                valid = true;
+                boolValue = true;
+                valueType = JSON_TYPE_NaN;
+                ch = offset == end ? EOI : bytes[offset++];
             } else if (ch == '{' && quote == 0) {
                 this.offset = offset;
                 this.ch = (char) ch;
@@ -7037,8 +6702,17 @@ class JSONReaderUTF8
                 && bytes[offset + 2] == 'l'
         ) {
             offset += 3;
-        } else if ((first == '"' || first == '\'') && offset < end && bytes[offset] == first) {
-            offset++;
+        } else if (first == '"' || first == '\'') {
+            if (offset < end && bytes[offset] == first) {
+                offset++;
+            } else if (offset + 4 < end
+                    && UNSAFE.getInt(bytes, ARRAY_BYTE_BASE_OFFSET + offset) == NULL_32
+                    && bytes[offset + 4] == first
+            ) {
+                offset += 5;
+            } else {
+                return false;
+            }
         } else {
             return false;
         }
diff --git a/core/src/main/java/com/alibaba/fastjson2/reader/ConstructorFunction.java b/core/src/main/java/com/alibaba/fastjson2/reader/ConstructorFunction.java
index 66efff8bd..c7ea0bbdb 100644
--- a/core/src/main/java/com/alibaba/fastjson2/reader/ConstructorFunction.java
+++ b/core/src/main/java/com/alibaba/fastjson2/reader/ConstructorFunction.java
@@ -180,14 +180,21 @@ final class ConstructorFunction<T>
         if (marker) {
             int i = 0, flag = 0;
             for (int n; i < size; i = n) {
+                Parameter parameter = parameters[i];
+                Class<?> paramClass = parameter.getType();
+                Type paramType = parameter.getParameterizedType();
                 Object arg = values.get(hashCodes[i]);
                 if (arg != null) {
+                    if (!paramClass.isInstance(arg)) {
+                        arg = TypeUtils.cast(arg, paramClass);
+                    } else if (paramType instanceof ParameterizedType) {
+                        arg = TypeUtils.cast(arg, paramType);
+                    }
                     args[i] = arg;
                 } else {
                     flag |= (1 << i);
-                    Class<?> paramType = parameters[i].getType();
-                    if (paramType.isPrimitive()) {
-                        args[i] = TypeUtils.getDefaultValue(paramType);
+                    if (paramClass.isPrimitive()) {
+                        args[i] = TypeUtils.getDefaultValue(paramClass);
                     }
                 }
                 n = i + 1;
diff --git a/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderNoneDefaultConstructor.java b/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderNoneDefaultConstructor.java
index e12d65b9a..a6364be2d 100644
--- a/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderNoneDefaultConstructor.java
+++ b/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderNoneDefaultConstructor.java
@@ -468,16 +468,9 @@ public class ObjectReaderNoneDefaultConstructor<T>
                     Class<?> valueClass = fieldValue.getClass();
                     Class fieldClass = fieldReader.fieldClass;
                     if (valueClass != fieldClass) {
-                        if (fieldValue instanceof JSONObject) {
-                            ObjectReader fieldObjectReader = provider.getObjectReader(fieldReader.fieldType);
-                            fieldValue = fieldObjectReader.createInstance((Map) fieldValue, features);
-                        } else if (fieldValue instanceof JSONArray) {
-                            fieldValue = ((JSONArray) fieldValue).to(fieldReader.fieldType, features);
-                        } else {
-                            Function typeConvert = provider.getTypeConvert(valueClass, fieldClass);
-                            if (typeConvert != null) {
-                                fieldValue = typeConvert.apply(fieldValue);
-                            }
+                        Function typeConvert = provider.getTypeConvert(valueClass, fieldClass);
+                        if (typeConvert != null) {
+                            fieldValue = typeConvert.apply(fieldValue);
                         }
                     }
                 }
diff --git a/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java b/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java
index 1911f1ee7..455aed880 100644
--- a/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java
+++ b/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java
@@ -21,6 +21,12 @@ public class IOUtils {
     public static final long ALSE_64 = BIG_ENDIAN ? 0x61006c00730065L : 0x650073006c0061L;
     public static final long DOT_X0 = BIG_ENDIAN ? 0x2e00L : 0x2eL;
 
+    public static final int INT_32_MULT_MIN_10 = Integer.MIN_VALUE / 10;
+    public static final int INT_32_MULT_MIN_100 = Integer.MIN_VALUE / 100;
+
+    public static final long INT_64_MULT_MIN_10 = Long.MIN_VALUE / 10;
+    public static final long INT_64_MULT_MIN_100 = Long.MIN_VALUE / 100;
+
     static final int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE};
 
     public static final int[] DIGITS_K_32 = new int[1000];
@@ -1607,4 +1613,8 @@ public class IOUtils {
                 + (v & 0xF);
         return v;
     }
+
+    public static boolean isDigit(int ch) {
+        return ch >= '0' && ch <= '9';
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fastjson2/util/TypeUtils.java b/core/src/main/java/com/alibaba/fastjson2/util/TypeUtils.java
index eb3fe6c8a..e83f4033e 100644
--- a/core/src/main/java/com/alibaba/fastjson2/util/TypeUtils.java
+++ b/core/src/main/java/com/alibaba/fastjson2/util/TypeUtils.java
@@ -3156,6 +3156,11 @@ public class TypeUtils {
             return Double.parseDouble(str);
         }
 
+        if ((value instanceof Collection && ((Collection<?>) value).isEmpty())
+                || (value instanceof Map && ((Map<?, ?>) value).isEmpty())) {
+            return 0;
+        }
+
         throw new JSONException("can not cast to decimal");
     }
 


Test patch:
diff --git a/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsParseUTF8BytesTest.java b/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsParseUTF8BytesTest.java
index cdcdd0b16..77ee17d75 100644
--- a/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsParseUTF8BytesTest.java
+++ b/benchmark/src/test/java/com/alibaba/fastjson2/benchmark/jjb/ClientsParseUTF8BytesTest.java
@@ -13,7 +13,7 @@ public class ClientsParseUTF8BytesTest {
             }
             long millis = System.currentTimeMillis() - start;
             System.out.println("fastjson2 millis : " + millis);
-            // zulu17.40.19 : 2417
+            // zulu17.40.19 : 2417 2236 2139 1985
             // oracle-jdk-17.0.6 :
             // oracle-jdk-17.0.6_vec :
             // oracle-jdk-17.0.6_reflect : 3566 3513 3476
diff --git a/core/src/test/java/com/alibaba/fastjson2/DoubleTest.java b/core/src/test/java/com/alibaba/fastjson2/DoubleTest.java
index 6b86df2ec..e6ccaea6c 100644
--- a/core/src/test/java/com/alibaba/fastjson2/DoubleTest.java
+++ b/core/src/test/java/com/alibaba/fastjson2/DoubleTest.java
@@ -213,6 +213,8 @@ public class DoubleTest {
 
     @Test
     public void test_str_array2() {
+//        assertEquals(0.0, JSON.parseObject("0.0", Double.class));
+        assertEquals(-2.147483648E9, JSON.parseObject("-2.147483648E9", Double.class));
         double[] primitiveValues = new double[values.length];
         for (int i = 0; i < values.length; i++) {
             if (values[i] == null) {
diff --git a/core/src/test/java/com/alibaba/fastjson2/JSONReaderTest.java b/core/src/test/java/com/alibaba/fastjson2/JSONReaderTest.java
index b369f2e3f..0dbd0c770 100644
--- a/core/src/test/java/com/alibaba/fastjson2/JSONReaderTest.java
+++ b/core/src/test/java/com/alibaba/fastjson2/JSONReaderTest.java
@@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test;
 import java.io.StringReader;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
 import java.time.LocalTime;
 import java.time.ZoneId;
@@ -1391,4 +1392,181 @@ public class JSONReaderTest {
                 }, false);
         assertEquals("123", ref.get());
     }
+
+    @Test
+    public void intOverFlow() {
+        {
+            String[] strings = new String[]{
+                    Integer.toString(Integer.MIN_VALUE + 1),
+                    Integer.toString(Integer.MIN_VALUE),
+                    Integer.toString(Integer.MAX_VALUE)
+            };
+            for (String str : strings) {
+                int expected = Integer.parseInt(str);
+                try (JSONReader jsonReader = JSONReader.of(str.getBytes(StandardCharsets.UTF_8))) {
+                    jsonReader.readNumber0();
+                    assertEquals(expected, jsonReader.getInt32Value());
+                }
+
+                assertEquals(expected,
+                        JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt32Value());
+                assertEquals(expected,
+                        JSONReader.of(str.toCharArray()).readInt32Value());
+            }
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            int expected = Integer.MIN_VALUE + i;
+            String str = Integer.toString(expected);
+
+            try (JSONReader jsonReader = JSONReader.of(str.getBytes(StandardCharsets.UTF_8))) {
+                jsonReader.readNumber0();
+                assertEquals(expected, jsonReader.getInt32Value());
+            }
+
+            assertEquals(expected,
+                    JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt32Value());
+            assertEquals(expected,
+                    JSONReader.of(str.toCharArray()).readInt32Value());
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            int expected = Integer.MAX_VALUE - i;
+            String str = Integer.toString(expected);
+
+            try (JSONReader jsonReader = JSONReader.of(str.getBytes(StandardCharsets.UTF_8))) {
+                jsonReader.readNumber0();
+                assertEquals(expected, jsonReader.getInt32Value());
+            }
+
+            assertEquals(expected,
+                    JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt32Value());
+            assertEquals(expected,
+                    JSONReader.of(str.toCharArray()).readInt32Value());
+        }
+
+        String[] strings = new String[]{
+                Long.toString(2147483649L),
+                Long.toString(-2147483650L),
+                Long.toString(Integer.MIN_VALUE - 1L),
+                Long.toString(Integer.MAX_VALUE + 1L)
+        };
+        for (String str : strings) {
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt32Value(),
+                    str);
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.toCharArray()).readInt32Value(),
+                    str);
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            String str = Long.toString(Integer.MIN_VALUE - 1L - i);
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt32Value(),
+                    str);
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.toCharArray()).readInt32Value(),
+                    str);
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            String str = Long.toString(Integer.MAX_VALUE + 1L + i);
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt32Value(),
+                    str);
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.toCharArray()).readInt32Value(),
+                    str);
+        }
+    }
+
+    @Test
+    public void int64OverFlow() {
+        {
+            String[] strings = new String[]{
+                    Long.toString(Long.MIN_VALUE),
+                    Long.toString(Long.MAX_VALUE)
+            };
+            for (String str : strings) {
+                assertEquals(Long.parseLong(str),
+                        JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt64Value());
+                assertEquals(Long.parseLong(str),
+                        JSONReader.of(str.toCharArray()).readInt64Value());
+            }
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            long expected = Integer.MIN_VALUE + i;
+            String str = Long.toString(expected);
+
+            try (JSONReader jsonReader = JSONReader.of(str.getBytes(StandardCharsets.UTF_8))) {
+                jsonReader.readNumber0();
+                assertEquals(expected, jsonReader.getInt32Value(), str);
+            }
+
+            assertEquals(expected,
+                    JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt64Value(),
+                    str);
+            assertEquals(expected,
+                    JSONReader.of(str.toCharArray()).readInt64Value(),
+                    str);
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            long expected = Integer.MAX_VALUE - i;
+            String str = Long.toString(expected);
+
+            try (JSONReader jsonReader = JSONReader.of(str.getBytes(StandardCharsets.UTF_8))) {
+                jsonReader.readNumber0();
+                assertEquals(expected, jsonReader.getInt64Value());
+            }
+
+            assertEquals(expected,
+                    JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt64Value(),
+                    str);
+            assertEquals(expected,
+                    JSONReader.of(str.toCharArray()).readInt64Value(),
+                    str);
+        }
+
+        String[] strings = new String[]{
+                BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE).toString(),
+                BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).toString()
+        };
+        for (String str : strings) {
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt64Value(),
+                    str);
+            assertThrows(JSONException.class,
+                    () -> JSONReader.of(str.toCharArray()).readInt64Value(),
+                    str);
+        }
+
+        {
+            BigInteger bigInt = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
+            for (int i = 0; i < 1000; i++) {
+                String str = bigInt.add(BigInteger.valueOf(i)).toString();
+                assertThrows(JSONException.class,
+                        () -> JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt64Value(),
+                        str);
+                assertThrows(JSONException.class,
+                        () -> JSONReader.of(str.toCharArray()).readInt64Value(),
+                        str);
+            }
+        }
+
+        {
+            BigInteger bigInt = BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE);
+            for (int i = 0; i < 1000; i++) {
+                String str = bigInt.subtract(BigInteger.valueOf(i)).toString();
+                assertThrows(JSONException.class,
+                        () -> JSONReader.of(str.getBytes(StandardCharsets.UTF_8)).readInt64Value(),
+                        str);
+                assertThrows(JSONException.class,
+                        () -> JSONReader.of(str.toCharArray()).readInt64Value(),
+                        str);
+            }
+        }
+    }
 }
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_1800/Issue1821.java b/core/src/test/java/com/alibaba/fastjson2/issues_1800/Issue1821.java
index e8d57b260..b7b4e2fc0 100644
--- a/core/src/test/java/com/alibaba/fastjson2/issues_1800/Issue1821.java
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_1800/Issue1821.java
@@ -49,7 +49,7 @@ public class Issue1821 {
                         new TypeReference<List<Float>>() {})
         );
         assertThrows(
-                NumberFormatException.class, () -> JSON.parseObject(
+                JSONException.class, () -> JSON.parseObject(
                         str0,
                         new TypeReference<List<Double>>() {})
         );
@@ -150,7 +150,7 @@ public class Issue1821 {
                         new TypeReference<List<Float>>() {})
         );
         assertThrows(
-                NumberFormatException.class, () -> JSON.parseObject(
+                JSONException.class, () -> JSON.parseObject(
                         str2,
                         new TypeReference<List<Double>>() {})
         );
diff --git a/core/src/test/java/com/alibaba/fastjson2/issues_3100/Issue3152.kt b/core/src/test/java/com/alibaba/fastjson2/issues_3100/Issue3152.kt
index 4463eeac1..6acce160f 100644
--- a/core/src/test/java/com/alibaba/fastjson2/issues_3100/Issue3152.kt
+++ b/core/src/test/java/com/alibaba/fastjson2/issues_3100/Issue3152.kt
@@ -8,12 +8,13 @@ import org.junit.jupiter.api.Test
 class Issue3152 {
 
     data class Foo(val int: Int = 1, val bar: Bar)
+    data class Foo2(val int: Int, val bar: Bar)
     data class Bar(val text: String)
 
     @Test
     fun test() {
         Assertions.assertEquals(
-            Foo(1, Bar("hello")),
+            Foo(bar = Bar("hello")),
             JSON.parseObject(
                 """
                     {
@@ -24,5 +25,19 @@ class Issue3152 {
                 """.trimIndent()
             ).toJavaObject(Foo::class.java)
         )
+
+        Assertions.assertEquals(
+            Foo2(1, Bar("hello")),
+            JSON.parseObject(
+                """
+                    {
+                        "int": 1,
+                        "bar": {
+                            "text" : "hello"
+                        }
+                    }
+                """.trimIndent()
+            ).to(Foo2::class.java)
+        )
     }
 }
diff --git a/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/DoubleTest.java b/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/DoubleTest.java
index 35ebcc148..f88004206 100644
--- a/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/DoubleTest.java
+++ b/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/DoubleTest.java
@@ -14,13 +14,8 @@ public class DoubleTest {
     @Test
     public void test_obj() throws Exception {
         String json = "{\"v1\":-0.012671709,\"v2\":0.22676692048907365,\"v3\":0.13231707,\"v4\":0.80090785,\"v5\":0.6192943}";
-        String json2 = "{\"v1\":\"-0.012671709\",\"v2\":\"0.22676692048907365\",\"v3\":\"0.13231707\",\"v4\":\"0.80090785\",\"v5\":\"0.6192943\"}";
-
         Model m1 = JSON.parseObject(json, Model.class);
-        Model m2 = JSON.parseObject(json2, Model.class);
-
         assertNotNull(m1);
-        assertNotNull(m2);
 
         assertEquals(-0.012671709D, m1.v1);
         assertEquals(0.22676692048907365D, m1.v2);
@@ -28,6 +23,9 @@ public class DoubleTest {
         assertEquals(0.80090785D, m1.v4);
         assertEquals(0.6192943D, m1.v5);
 
+        String json2 = "{\"v1\":\"-0.012671709\",\"v2\":\"0.22676692048907365\",\"v3\":\"0.13231707\",\"v4\":\"0.80090785\",\"v5\":\"0.6192943\"}";
+        Model m2 = JSON.parseObject(json2, Model.class);
+        assertNotNull(m2);
         assertEquals(-0.012671709D, m2.v1);
         assertEquals(0.22676692048907365D, m2.v2);
         assertEquals(0.13231707D, m2.v3);
diff --git a/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/LongNullTest.java b/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/LongNullTest.java
index 111b10d6f..35d63aaf6 100644
--- a/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/LongNullTest.java
+++ b/core/src/test/java/com/alibaba/fastjson2/v1issues/basicType/LongNullTest.java
@@ -4,6 +4,8 @@ import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONReader.Feature;
 import org.junit.jupiter.api.Test;
 
+import java.nio.charset.StandardCharsets;
+
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
@@ -13,18 +15,93 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 public class LongNullTest {
     @Test
     public void test_null() throws Exception {
-        Model model = JSON.parseObject("{\"v1\":null,\"v2\":null}", Model.class);
-        assertNotNull(model);
-        assertNull(model.v1);
-        assertNull(model.v2);
+        {
+            Model model = JSON.parseObject("{\"v1\":null,\"v2\":null}", Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject("{\"v1\":null,\"v2\":null}".getBytes(StandardCharsets.UTF_8), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject("{\"v1\":null,\"v2\":null}".toCharArray(), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+    }
+
+    @Test
+    public void test_null_0() throws Exception {
+        String str = "{\"v1\":null,\"v2\":null,\"v3\":\"中\"}";
+        {
+            Model model = JSON.parseObject(str, Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject(str.getBytes(StandardCharsets.UTF_8), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject(str.toCharArray(), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
     }
 
     @Test
     public void test_null_quote() throws Exception {
-        Model model = JSON.parseObject("{\"v1\":\"null\",\"v2\":\"null\"}", Model.class);
-        assertNotNull(model);
-        assertNull(model.v1);
-        assertNull(model.v2);
+        String str = "{\"v1\":\"null\",\"v2\":\"null\"}";
+        {
+            Model model = JSON.parseObject(str, Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject(str.getBytes(StandardCharsets.UTF_8), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject(str.toCharArray(), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+    }
+
+    @Test
+    public void test_null_empty() throws Exception {
+        String str = "{\"v1\":\"\",\"v2\":\"\"}";
+        {
+            Model model = JSON.parseObject(str, Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject(str.getBytes(StandardCharsets.UTF_8), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
+        {
+            Model model = JSON.parseObject(str.toCharArray(), Model.class);
+            assertNotNull(model);
+            assertNull(model.v1);
+            assertNull(model.v2);
+        }
     }
 
     @Test