From 85fe45ca2da6d7b79ec03014c928075bca01e588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Mon, 17 Jul 2023 14:37:45 +0200 Subject: [PATCH 1/3] BigInteger scale limit counts absolute value now. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- .../org/eclipse/parsson/JsonNumberImpl.java | 15 +++---- .../org/eclipse/parsson/api/JsonConfig.java | 4 +- .../tests/JsonBigDecimalScaleLimitTest.java | 21 ++++++++- .../eclipse/parsson/tests/JsonNumberTest.java | 44 ++++++++++++++++++- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java index 3e34d7ab..a0251467 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java @@ -28,6 +28,9 @@ */ abstract class JsonNumberImpl implements JsonNumber { + private static final String SCALE_LIMIT_EXCEPTION_MESSAGE + = "Scale value %d of this BigInteger exceeded maximal allowed absolute value of %d"; + private int hashCode; private final int bigIntegerScaleLimit; @@ -287,25 +290,21 @@ public double doubleValue() { @Override public BigInteger bigIntegerValue() { BigDecimal bd = bigDecimalValue(); - if (bd.scale() <= bigIntegerScaleLimit) { + if (Math.abs(bd.scale()) <= bigIntegerScaleLimit) { return bd.toBigInteger(); } throw new UnsupportedOperationException( - String.format( - "Scale value %d of this BigInteger exceeded maximal allowed value of %d", - bd.scale(), bigIntegerScaleLimit)); + String.format(SCALE_LIMIT_EXCEPTION_MESSAGE, bd.scale(), bigIntegerScaleLimit)); } @Override public BigInteger bigIntegerValueExact() { BigDecimal bd = bigDecimalValue(); - if (bd.scale() <= bigIntegerScaleLimit) { + if (Math.abs(bd.scale()) <= bigIntegerScaleLimit) { return bd.toBigIntegerExact(); } throw new UnsupportedOperationException( - String.format( - "Scale value %d of this BigInteger exceeded maximal allowed value of %d", - bd.scale(), bigIntegerScaleLimit)); + String.format(SCALE_LIMIT_EXCEPTION_MESSAGE, bd.scale(), bigIntegerScaleLimit)); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/api/JsonConfig.java b/impl/src/main/java/org/eclipse/parsson/api/JsonConfig.java index 343a255c..6e0db85d 100644 --- a/impl/src/main/java/org/eclipse/parsson/api/JsonConfig.java +++ b/impl/src/main/java/org/eclipse/parsson/api/JsonConfig.java @@ -19,8 +19,8 @@ public interface JsonConfig { /** - * Configuration property to limit maximum value of BigInteger scale value. - * This property limits maximum value of scale value to be allowed + * Configuration property to limit maximum absolute value of BigInteger scale. + * This property limits maximum absolute value of scale to be allowed * in {@link jakarta.json.JsonNumber#bigIntegerValue()} * and {@link jakarta.json.JsonNumber#bigIntegerValueExact()} implemented methods. * Default value is set to {@code 100000}. diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java index ed59a5c4..c3410187 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java @@ -62,7 +62,26 @@ public void testSystemPropertyBigIntegerScaleAboveLimit() { } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown assertEquals( - "Scale value 50001 of this BigInteger exceeded maximal allowed value of 50000", + "Scale value 50001 of this BigInteger exceeded maximal allowed absolute value of 50000", + e.getMessage()); + } + System.clearProperty("org.eclipse.parsson.maxBigIntegerScale"); + } + + // Test BigInteger scale value limit set from system property using value above limit. + // Call shall throw specific UnsupportedOperationException exception. + // Default value is 100000 and system property lowered it to 50000 so value with scale -50001 + // test shall fail with exception message matching modified limits. + public void testSystemPropertyBigIntegerNegScaleAboveLimit() { + BigDecimal value = new BigDecimal("3.1415926535897932384626433") + .setScale(-50001, RoundingMode.HALF_UP); + try { + Json.createValue(value).bigIntegerValue(); + fail("No exception was thrown from bigIntegerValue with scale over limit"); + } catch (UnsupportedOperationException e) { + // UnsupportedOperationException is expected to be thrown + assertEquals( + "Scale value -50001 of this BigInteger exceeded maximal allowed absolute value of 50000", e.getMessage()); } System.clearProperty("org.eclipse.parsson.maxBigIntegerScale"); diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java index c47a0b61..7b0b2c54 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java @@ -284,7 +284,23 @@ public void testDefaultBigIntegerScaleAboveLimit() { } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown assertEquals( - "Scale value 100001 of this BigInteger exceeded maximal allowed value of 100000", + "Scale value 100001 of this BigInteger exceeded maximal allowed absolute value of 100000", + e.getMessage()); + } + } + + // Test default BigInteger scale value limit using value above limit. + // Call shall throw specific UnsupportedOperationException exception. + public void testDefaultBigIntegerNegScaleAboveLimit() { + BigDecimal value = new BigDecimal("3.1415926535897932384626433") + .setScale(-100001, RoundingMode.HALF_UP); + try { + Json.createValue(value).bigIntegerValue(); + fail("No exception was thrown from bigIntegerValue with scale over limit"); + } catch (UnsupportedOperationException e) { + // UnsupportedOperationException is expected to be thrown + assertEquals( + "Scale value -100001 of this BigInteger exceeded maximal allowed absolute value of 100000", e.getMessage()); } } @@ -308,7 +324,31 @@ public void testConfigBigIntegerScaleAboveLimit() { } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown assertEquals( - "Scale value 50001 of this BigInteger exceeded maximal allowed value of 50000", + "Scale value 50001 of this BigInteger exceeded maximal allowed absolute value of 50000", + e.getMessage()); + } + } + + // Test BigInteger scale value limit set from config Map using value above limit. + // Call shall throw specific UnsupportedOperationException exception. + // Config Map limit is stored in target JsonObject and shall be present for later value manipulation. + // Default value is 100000 and config Map property lowered it to 50000 so value with scale -50001 + // test shall fail with exception message matching modified limits. + public void testConfigBigIntegerNegScaleAboveLimit() { + BigDecimal value = new BigDecimal("3.1415926535897932384626433") + .setScale(-50001, RoundingMode.HALF_UP); + Map config = Map.of(JsonConfig.MAX_BIGINTEGER_SCALE, "50000"); + try { + JsonObject jsonObject = Json.createBuilderFactory(config) + .createObjectBuilder() + .add("bigDecimal", value) + .build(); + jsonObject.getJsonNumber("bigDecimal").bigIntegerValue(); + fail("No exception was thrown from bigIntegerValue with scale over limit"); + } catch (UnsupportedOperationException e) { + // UnsupportedOperationException is expected to be thrown + assertEquals( + "Scale value -50001 of this BigInteger exceeded maximal allowed absolute value of 50000", e.getMessage()); } } From 84764ffbe3d0376da242b27a9a526138d0dfb8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Mon, 17 Jul 2023 15:40:04 +0200 Subject: [PATCH 2/3] Exception message moved to messages bundle. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- .../org/eclipse/parsson/JsonMessages.java | 4 +++ .../org/eclipse/parsson/JsonNumberImpl.java | 7 ++-- .../org/eclipse/parsson/messages.properties | 2 ++ .../tests/JsonBigDecimalScaleLimitTest.java | 14 ++++---- .../eclipse/parsson/tests/JsonNumberTest.java | 35 +++++++++++-------- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/impl/src/main/java/org/eclipse/parsson/JsonMessages.java b/impl/src/main/java/org/eclipse/parsson/JsonMessages.java index 26f08a6a..9fd77e6d 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonMessages.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonMessages.java @@ -162,6 +162,10 @@ static String READER_READ_ALREADY_CALLED() { return localize("reader.read.already.called"); } + // JSON number messages + static String NUMBER_SCALE_LIMIT_EXCEPTION(int value, int limit) { + return localize("number.scale.limit.exception", value, limit); + } // obj builder messages static String OBJBUILDER_NAME_NULL() { diff --git a/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java index a0251467..2dcb552d 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java @@ -28,9 +28,6 @@ */ abstract class JsonNumberImpl implements JsonNumber { - private static final String SCALE_LIMIT_EXCEPTION_MESSAGE - = "Scale value %d of this BigInteger exceeded maximal allowed absolute value of %d"; - private int hashCode; private final int bigIntegerScaleLimit; @@ -294,7 +291,7 @@ public BigInteger bigIntegerValue() { return bd.toBigInteger(); } throw new UnsupportedOperationException( - String.format(SCALE_LIMIT_EXCEPTION_MESSAGE, bd.scale(), bigIntegerScaleLimit)); + JsonMessages.NUMBER_SCALE_LIMIT_EXCEPTION(bd.scale(), bigIntegerScaleLimit)); } @Override @@ -304,7 +301,7 @@ public BigInteger bigIntegerValueExact() { return bd.toBigIntegerExact(); } throw new UnsupportedOperationException( - String.format(SCALE_LIMIT_EXCEPTION_MESSAGE, bd.scale(), bigIntegerScaleLimit)); + JsonMessages.NUMBER_SCALE_LIMIT_EXCEPTION(bd.scale(), bigIntegerScaleLimit)); } @Override diff --git a/impl/src/main/resources/org/eclipse/parsson/messages.properties b/impl/src/main/resources/org/eclipse/parsson/messages.properties index 1c693105..20181cce 100644 --- a/impl/src/main/resources/org/eclipse/parsson/messages.properties +++ b/impl/src/main/resources/org/eclipse/parsson/messages.properties @@ -58,6 +58,8 @@ writer.write.already.called=write/writeObject/writeArray/close method is already reader.read.already.called=read/readObject/readArray/close method is already called +number.scale.limit.exception=Scale value {0} of this BigInteger exceeded maximal allowed absolute value of {1} + objbuilder.name.null=Name in JsonObject's name/value pair cannot be null objbuilder.value.null=Value in JsonObject's name/value pair cannot be null objbuilder.object.builder.null=Object builder that is used to create a value in JsonObject's name/value pair cannot be null diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java index c3410187..960c2c88 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonBigDecimalScaleLimitTest.java @@ -28,13 +28,15 @@ */ public class JsonBigDecimalScaleLimitTest extends TestCase { + private static final int MAX_BIGINTEGER_SCALE = 50000; + public JsonBigDecimalScaleLimitTest(String testName) { super(testName); } @Override protected void setUp() { - System.setProperty(JsonConfig.MAX_BIGINTEGER_SCALE, "50000"); + System.setProperty(JsonConfig.MAX_BIGINTEGER_SCALE, Integer.toString(MAX_BIGINTEGER_SCALE)); } @Override @@ -61,9 +63,8 @@ public void testSystemPropertyBigIntegerScaleAboveLimit() { fail("No exception was thrown from bigIntegerValue with scale over limit"); } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown - assertEquals( - "Scale value 50001 of this BigInteger exceeded maximal allowed absolute value of 50000", - e.getMessage()); + JsonNumberTest.assertExceptionMessageContainsNumber(e, 50001); + JsonNumberTest.assertExceptionMessageContainsNumber(e, MAX_BIGINTEGER_SCALE); } System.clearProperty("org.eclipse.parsson.maxBigIntegerScale"); } @@ -80,9 +81,8 @@ public void testSystemPropertyBigIntegerNegScaleAboveLimit() { fail("No exception was thrown from bigIntegerValue with scale over limit"); } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown - assertEquals( - "Scale value -50001 of this BigInteger exceeded maximal allowed absolute value of 50000", - e.getMessage()); + JsonNumberTest.assertExceptionMessageContainsNumber(e, -50001); + JsonNumberTest.assertExceptionMessageContainsNumber(e, MAX_BIGINTEGER_SCALE); } System.clearProperty("org.eclipse.parsson.maxBigIntegerScale"); } diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java index 7b0b2c54..8f97feee 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonNumberTest.java @@ -21,6 +21,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.text.MessageFormat; import java.util.Map; import jakarta.json.Json; @@ -61,6 +62,9 @@ public class JsonNumberTest extends TestCase { // π as JsonNumber with 1101 source characters private static final String Π_1101 = Π_1100 + "5"; + // Default maximum value of BigInteger scale value limit from JsonContext + private static final int DEFAULT_MAX_BIGINTEGER_SCALE = 100000; + public JsonNumberTest(String testName) { super(testName); } @@ -273,7 +277,7 @@ public void testDefaultBigIntegerScaleBellowLimit() { Json.createValue(value).bigIntegerValue(); } - // Test default BigInteger scale value limit using value above limit. + // Test default BigInteger scale value limit using positive value above limit. // Call shall throw specific UnsupportedOperationException exception. public void testDefaultBigIntegerScaleAboveLimit() { BigDecimal value = new BigDecimal("3.1415926535897932384626433") @@ -283,13 +287,12 @@ public void testDefaultBigIntegerScaleAboveLimit() { fail("No exception was thrown from bigIntegerValue with scale over limit"); } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown - assertEquals( - "Scale value 100001 of this BigInteger exceeded maximal allowed absolute value of 100000", - e.getMessage()); + assertExceptionMessageContainsNumber(e, 100001); + assertExceptionMessageContainsNumber(e, DEFAULT_MAX_BIGINTEGER_SCALE); } } - // Test default BigInteger scale value limit using value above limit. + // Test default BigInteger scale value limit using negative value above limit. // Call shall throw specific UnsupportedOperationException exception. public void testDefaultBigIntegerNegScaleAboveLimit() { BigDecimal value = new BigDecimal("3.1415926535897932384626433") @@ -299,9 +302,8 @@ public void testDefaultBigIntegerNegScaleAboveLimit() { fail("No exception was thrown from bigIntegerValue with scale over limit"); } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown - assertEquals( - "Scale value -100001 of this BigInteger exceeded maximal allowed absolute value of 100000", - e.getMessage()); + assertExceptionMessageContainsNumber(e, -100001); + assertExceptionMessageContainsNumber(e, DEFAULT_MAX_BIGINTEGER_SCALE); } } @@ -323,9 +325,8 @@ public void testConfigBigIntegerScaleAboveLimit() { fail("No exception was thrown from bigIntegerValue with scale over limit"); } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown - assertEquals( - "Scale value 50001 of this BigInteger exceeded maximal allowed absolute value of 50000", - e.getMessage()); + assertExceptionMessageContainsNumber(e, 50001); + assertExceptionMessageContainsNumber(e, 50000); } } @@ -347,9 +348,8 @@ public void testConfigBigIntegerNegScaleAboveLimit() { fail("No exception was thrown from bigIntegerValue with scale over limit"); } catch (UnsupportedOperationException e) { // UnsupportedOperationException is expected to be thrown - assertEquals( - "Scale value -50001 of this BigInteger exceeded maximal allowed absolute value of 50000", - e.getMessage()); + assertExceptionMessageContainsNumber(e, -50001); + assertExceptionMessageContainsNumber(e, 50000); } } @@ -405,6 +405,13 @@ public void testLargeBigDecimalAboveCustomLimit() { } } + static void assertExceptionMessageContainsNumber(Exception e, int number) { + // Format the number as being written to message from messages bundle + String numberString = MessageFormat.format("{0}", number); + assertTrue("Substring \"" + numberString + "\" was not found in \"" + e.getMessage() + "\"", + e.getMessage().contains(numberString)); + } + private static class CustomNumber extends Number { private static final long serialVersionUID = 1L; From ab239fee273cb262910890f1a6fe666ae92cd623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Mon, 17 Jul 2023 16:12:15 +0200 Subject: [PATCH 3/3] Eexception message moved to messages bundle in JsonParserImpl. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- impl/src/main/java/org/eclipse/parsson/JsonMessages.java | 6 +++++- impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java | 2 +- .../main/resources/org/eclipse/parsson/messages.properties | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/impl/src/main/java/org/eclipse/parsson/JsonMessages.java b/impl/src/main/java/org/eclipse/parsson/JsonMessages.java index 9fd77e6d..09ab8cda 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonMessages.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonMessages.java @@ -116,7 +116,11 @@ static String PARSER_INPUT_ENC_DETECT_FAILED() { static String PARSER_INPUT_ENC_DETECT_IOERR() { return localize("parser.input.enc.detect.ioerr"); } - + + static String PARSER_INPUT_NESTED_TOO_DEEP(int limit) { + return localize("parser.input.nested.too.deep", limit); + } + static String DUPLICATE_KEY(String name) { return localize("parser.duplicate.key", name); } diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java index 5c0002c9..217af798 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java @@ -393,7 +393,7 @@ private static final class Stack { private void push(Context context) { if (++size >= limit) { - throw new RuntimeException("Input is too deeply nested " + size); + throw new RuntimeException(JsonMessages.PARSER_INPUT_NESTED_TOO_DEEP(size)); } context.next = head; head = context; diff --git a/impl/src/main/resources/org/eclipse/parsson/messages.properties b/impl/src/main/resources/org/eclipse/parsson/messages.properties index 20181cce..6162b37b 100644 --- a/impl/src/main/resources/org/eclipse/parsson/messages.properties +++ b/impl/src/main/resources/org/eclipse/parsson/messages.properties @@ -44,6 +44,7 @@ parser.scope.err=Cannot be called for value {0} parser.input.enc.detect.failed=Cannot auto-detect encoding, not enough chars parser.input.enc.detect.ioerr=I/O error while auto-detecting the encoding of stream parser.duplicate.key=Duplicate key ''{0}'' is not allowed +parser.input.nested.too.deep=Input is too deeply nested {0} generator.flush.io.err=I/O error while flushing generated JSON generator.close.io.err=I/O error while closing JsonGenerator