fix(JOHNZON-397): Create configuration option to set the BigDecimal scale limit

Signed-off-by: Jean-Louis Monteiro <jlmonteiro@tomitribe.com>
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonNumberImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonNumberImpl.java
index 73443ea..60fd4a8 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonNumberImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonNumberImpl.java
@@ -69,13 +69,13 @@
 
     @Override
     public BigInteger bigIntegerValue() {
-        checkBigIntegerScale();
+        checkBigDecimalScale();
         return value.toBigInteger();
     }
 
     @Override
     public BigInteger bigIntegerValueExact() {
-        checkBigIntegerScale();
+        checkBigDecimalScale();
         return value.toBigIntegerExact();
     }
 
@@ -120,7 +120,7 @@
         }
     }
 
-    private void checkBigIntegerScale() {
+    private void checkBigDecimalScale() {
         // should be fine enough. Maybe we should externalize so users can pick something better if they need to
         // it becomes their responsibility to fix the limit and may expose them to a DoS attack
         final int limit = 1_000;
diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
index 57e824c..334a142 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
@@ -100,7 +100,7 @@
             long start = System.nanoTime();
             for (int i = 1; i < 100; i++) {
                 // if it takes a second in any machine, that's already too much
-                // depends on the allowed scale in JsonNumberImpl#checkBigIntegerScale
+                // depends on the allowed scale in JsonNumberImpl#checkBigDecimalScale
                 if (TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start) > (30 * i)) {
                     fail("took too long: " + TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start) + " s" +
                          " to compute " + i + " conversions toBigInteger");
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
index 278e814..3275da0 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -110,7 +110,10 @@
 
         // todo: global spec toggle to disable all these ones at once?
         builder.setUseBigDecimalForObjectNumbers(
-                config.getProperty("johnzon.use-big-decimal-for-object").map(this::toBool).orElse(true));
+            config.getProperty("johnzon.use-big-decimal-for-object").map(this::toBool).orElse(true));
+        builder.setMaxBigDecimalScale(
+            config.getProperty("johnzon.max-big-decimal-scale").map(this::toInt).orElse(1000));
+
         builder.setSupportEnumContainerDeserialization( // https://github.com/eclipse-ee4j/jakartaee-tck/issues/103
                 toBool(System.getProperty("johnzon.support-enum-container-deserialization", config.getProperty("johnzon.support-enum-container-deserialization")
                         .map(String::valueOf).orElse("true"))));
@@ -368,6 +371,10 @@
         return !Boolean.class.isInstance(v) ? Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v);
     }
 
+    private Integer toInt(final Object v) {
+        return !Integer.class.isInstance(v) ? Integer.parseInt(v.toString()) : Integer.class.cast(v);
+    }
+
     private AccessMode toAccessMode(final Object s) {
         if (String.class.isInstance(s)) {
             try {
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index 91e6cd5..6fa89ad 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -104,6 +104,7 @@
     private Boolean deduplicateObjects = null;
     private boolean useJsRange;
     private boolean useBigDecimalForObjectNumbers;
+    private int maxBigDecimalScale = 1000;
     private boolean supportEnumContainerDeserialization = true;
     private Function<Class<?>, MapperConfig.CustomEnumConverter<?>> enumConverterFactory = type -> new EnumConverter(type);
     private boolean skipAccessModeWrapper;
@@ -234,7 +235,7 @@
                         treatByteArrayAsBase64, treatByteArrayAsBase64URL, readAttributeBeforeWrite,
                         accessMode, encoding, attributeOrder, failOnUnknownProperties,
                         serializeValueFilter, useBigDecimalForFloats, deduplicateObjects,
-                        interfaceImplementationMapping, useJsRange, useBigDecimalForObjectNumbers,
+                        interfaceImplementationMapping, useJsRange, useBigDecimalForObjectNumbers, maxBigDecimalScale,
                         supportEnumContainerDeserialization,
                         typeLoader, discriminatorMapper, discriminator,
                         deserializationPredicate, serializationPredicate,
@@ -531,6 +532,11 @@
         return this;
     }
 
+    public MapperBuilder setMaxBigDecimalScale(final int maxBigDecimalScale) {
+        this.maxBigDecimalScale = maxBigDecimalScale;
+        return this;
+    }
+
     public MapperBuilder setSupportEnumContainerDeserialization(final boolean supportEnumContainerDeserialization) {
         this.supportEnumContainerDeserialization = supportEnumContainerDeserialization;
         return this;
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
index dd0ab71..23b78dc 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
@@ -81,7 +81,7 @@
     private final Boolean deduplicateObjects;
     private final Map<Class<?>, Class<?>> interfaceImplementationMapping;
     private final boolean useBigDecimalForObjectNumbers;
-
+    private int maxBigDecimalScale;
     private final Function<String, Class<?>> typeLoader;
     private final Function<Class<?>, String> discriminatorMapper;
     private final Predicate<Class<?>> serializationPredicate;
@@ -118,6 +118,7 @@
                         final Map<Class<?>, Class<?>> interfaceImplementationMapping,
                         final boolean useJsRange,
                         final boolean useBigDecimalForObjectNumbers,
+                        final int maxBigDecimalScale,
                         final boolean supportEnumMapDeserialization,
                         final Function<String, Class<?>> typeLoader,
                         final Function<Class<?>, String> discriminatorMapper,
@@ -129,7 +130,7 @@
         this(adapters, objectConverterWriters, objectConverterReaders, version, close, skipNull, skipEmptyArray,
                 treatByteArrayAsBase64, treatByteArrayAsBase64URL, readAttributeBeforeWrite, accessMode, encoding,
                 attributeOrder, failOnUnknown, serializeValueFilter, useBigDecimalForFloats, deduplicateObjects, interfaceImplementationMapping,
-                useJsRange, useBigDecimalForObjectNumbers, supportEnumMapDeserialization, typeLoader,
+                useJsRange, useBigDecimalForObjectNumbers, maxBigDecimalScale, supportEnumMapDeserialization, typeLoader,
                 discriminatorMapper, discriminator, deserializationPredicate, serializationPredicate, enumConverterFactory,
                 JohnzonCores.snippetFactory(50, Json.createGeneratorFactory(emptyMap())), null);
     }
@@ -152,6 +153,7 @@
                         final Map<Class<?>, Class<?>> interfaceImplementationMapping,
                         final boolean useJsRange,
                         final boolean useBigDecimalForObjectNumbers,
+                        final int maxBigDecimalScale,
                         final boolean supportEnumMapDeserialization,
                         final Function<String, Class<?>> typeLoader,
                         final Function<Class<?>, String> discriminatorMapper,
@@ -175,6 +177,7 @@
         this.encoding = encoding;
         this.useJsRange = useJsRange;
         this.useBigDecimalForObjectNumbers = useBigDecimalForObjectNumbers;
+        this.maxBigDecimalScale = maxBigDecimalScale;
         this.supportEnumMapDeserialization = supportEnumMapDeserialization;
         this.typeLoader = typeLoader;
         this.discriminatorMapper = discriminatorMapper;
@@ -243,6 +246,10 @@
         return useBigDecimalForObjectNumbers;
     }
 
+    public int getMaxBigDecimalScale() {
+        return maxBigDecimalScale;
+    }
+
     public boolean isUseJsRange() {
         return useJsRange;
     }