diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java index 36d8713edb..e515badc16 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReader.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReader.java @@ -3868,6 +3868,37 @@ public Boolean readBool() { return boolValue; } + protected final boolean getBooleanValue() { + return (context.features & Feature.NonZeroNumberCastToBooleanAsTrue.mask) != 0 + ? isNonZeroNumber() + : isOneNumber(); + } + + private boolean isNonZeroNumber() { + return mag0 != 0 || mag1 != 0 || mag2 != 0 || mag3 != 0; + } + + private boolean isOneNumber() { + if (valueType == JSON_TYPE_INT) { + return isOneInt(); + } + + return isOneDecimal(); + } + + private boolean isOneInt() { + return mag0 == 0 + && mag1 == 0 + && mag2 == 0 + && mag3 == 1; + } + + private boolean isOneDecimal() { + return getBigDecimal() + .abs() + .compareTo(BigDecimal.ONE) == 0; + } + /** * Reads a boolean value from JSON data as a primitive boolean. * diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java index 0ac783904b..3bd083b808 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java @@ -5471,17 +5471,7 @@ public final boolean readBoolValue() { val = false; } else if (ch == '-' || (ch >= '0' && ch <= '9')) { readNumber(); - if (valueType == JSON_TYPE_INT) { - if ((context.features & Feature.NonZeroNumberCastToBooleanAsTrue.mask) != 0) { - return mag0 != 0 || mag1 != 0 || mag2 != 0 || mag3 != 0; - } else { - return mag0 == 0 - && mag1 == 0 - && mag2 == 0 - && mag3 == 1; - } - } - return false; + return getBooleanValue(); } else if (ch == 'n' && offset + 2 < chars.length && chars[offset] == 'u' && chars[offset + 1] == 'l' diff --git a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java index 267d6d61c7..0457ed09d1 100644 --- a/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java +++ b/core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java @@ -7569,17 +7569,7 @@ private boolean readBoolValue0() { val = false; } else if (ch == '-' || (ch >= '0' && ch <= '9')) { readNumber(); - if (valueType == JSON_TYPE_INT) { - if ((context.features & Feature.NonZeroNumberCastToBooleanAsTrue.mask) != 0) { - return mag0 != 0 || mag1 != 0 || mag2 != 0 || mag3 != 0; - } else { - return mag0 == 0 - && mag1 == 0 - && mag2 == 0 - && mag3 == 1; - } - } - return false; + return getBooleanValue(); } else if (ch == 'n' && offset + 2 < bytes.length && bytes[offset] == 'u' && bytes[offset + 1] == 'l' diff --git a/core/src/test/java/com/alibaba/fastjson2/JSONReaderBooleanTest.java b/core/src/test/java/com/alibaba/fastjson2/JSONReaderBooleanTest.java new file mode 100644 index 0000000000..d4e1584fe9 --- /dev/null +++ b/core/src/test/java/com/alibaba/fastjson2/JSONReaderBooleanTest.java @@ -0,0 +1,97 @@ +package com.alibaba.fastjson2; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class JSONReaderBooleanTest { + @Test + public void numberNotation() { + assertValue(true, "1"); + assertValue(true, "1.0"); + assertValue(true, "1.00"); + assertValue(true, "1e0"); + assertValue(true, "10e-1"); + assertValue(true, "-1"); + assertValue(true, "-1.0"); + assertValue(false, "2"); + assertValue(false, "2.0"); + assertValue(false, "-2"); + assertValue(false, "-2.0"); + assertValue(false, "0"); + assertValue(false, "0.0"); + assertValue(false, "0.5"); + } + + @Test + public void nonZeroNumberFeature() { + for (String value : new String[]{"1", "1.0", "-1", "-1.0", "2", "2.0", "0.5", "-0.5"}) { + assertFeatureValue(true, value); + } + + for (String value : new String[]{"0", "0.0", "0e10"}) { + assertFeatureValue(false, value); + } + } + + @Test + public void stringAndNullBehavior() { + assertValue(true, "\"1\""); + assertValue(true, "\"true\""); + assertValue(false, "null"); + assertThrows(JSONException.class, () -> parse("\"yes\"")); + } + + private static void assertValue(boolean expected, String value) { + String json = "{\"enabled\":" + value + "}"; + assertEquals(expected, JSON.parseObject(json, Bean.class).enabled, value); + assertEquals(expected, JSON.parseObject(json.toCharArray(), Bean.class).enabled, value); + assertEquals( + expected, + JSON.parseObject(json.getBytes(StandardCharsets.UTF_8), Bean.class).enabled, + value + ); + } + + private static boolean parse(String value) { + return JSON.parseObject("{\"enabled\":" + value + "}", Bean.class).enabled; + } + + private static void assertFeatureValue(boolean expected, String value) { + String json = "{\"enabled\":" + value + "}"; + assertEquals( + expected, + JSON.parseObject( + json, + Bean.class, + JSONReader.Feature.NonZeroNumberCastToBooleanAsTrue + ).enabled, + value + ); + assertEquals( + expected, + JSON.parseObject( + json.toCharArray(), + Bean.class, + JSONReader.Feature.NonZeroNumberCastToBooleanAsTrue + ).enabled, + value + ); + assertEquals( + expected, + JSON.parseObject( + json.getBytes(StandardCharsets.UTF_8), + Bean.class, + JSONReader.Feature.NonZeroNumberCastToBooleanAsTrue + ).enabled, + value + ); + } + + public static class Bean { + public boolean enabled; + } +}