serialize BigInteger/BigDecimal as strings by default in jsonb
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 28c85b8..520f8c1 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
@@ -56,8 +56,6 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
@@ -236,9 +234,15 @@
Integer.parseInt(it.toString()))
.ifPresent(builder::setSnippetMaxLength);
- // drop johnzon-mapper BigInteger/BigDecimal built in adapters to not serialize those types as JsonString. See JSON-B spec 3.4.1
- builder.getAdapters().remove(new AdapterKey(BigDecimal.class, String.class));
- builder.getAdapters().remove(new AdapterKey(BigInteger.class, String.class));
+ config.getProperty("johnzon.use-biginteger-stringadapter")
+ .or(() -> Optional.ofNullable(System.getProperty("johnzon.use-biginteger-stringadapter")))
+ .map(Object::toString).map(Boolean::parseBoolean)
+ .ifPresent(builder::setUseBigIntegerStringAdapter);
+
+ config.getProperty("johnzon.use-bigdecimal-stringadapter")
+ .or(() -> Optional.ofNullable(System.getProperty("johnzon.use-bigdecimal-stringadapter")))
+ .map(Object::toString).map(Boolean::parseBoolean)
+ .ifPresent(builder::setUseBigDecimalStringAdapter);
// user adapters
final Types types = new Types();
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbTypesTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbTypesTest.java
index 49e4c25..2c5987b 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbTypesTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbTypesTest.java
@@ -65,7 +65,7 @@
final LocalDate localDate = LocalDate.of(2015, 1, 1);
final LocalTime localTime = LocalTime.of(1, 2, 3);
final LocalDateTime localDateTime = LocalDateTime.of(2015, 1, 1, 1, 1);
- final String expected = "{\"bigDecimal\":1.5,\"bigInteger\":1," +
+ final String expected = "{\"bigDecimal\":\"1.5\",\"bigInteger\":\"1\"," +
"\"calendar\":\"2015-01-01T01:01:00Z[UTC]\",\"date\":\"2015-01-01T01:01:00Z[UTC]\"," +
"\"duration\":\"PT30S\",\"gregorianCalendar\":\"2015-01-01T01:01:00Z[UTC]\"," +
"\"instant\":\"2015-01-01T00:00:00Z\",\"localDate\":\"2015-01-01\"," +
@@ -109,6 +109,23 @@
}
@Test
+ public void testReadAndWriteBigIntDecimalAsNumbers() throws Exception {
+ final String expected = "{\"bigDecimal\":1.5,\"bigInteger\":1}";
+ final Jsonb jsonb = newJsonb(
+ new JsonbConfig()
+ .setProperty("johnzon.use-biginteger-stringadapter", false)
+ .setProperty("johnzon.use-bigdecimal-stringadapter", false));
+
+ final Types types = jsonb.fromJson(new StringReader(expected), Types.class);
+ assertEquals(BigInteger.valueOf(1), types.bigInteger);
+ assertEquals(BigDecimal.valueOf(1.5), types.bigDecimal);
+
+ assertEquals(expected, jsonb.toJson(types));
+
+ jsonb.close();
+ }
+
+ @Test
public void readAndWriteWithDateFormats() throws Exception {
readAndWriteWithDateFormat(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"), "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
readAndWriteWithDateFormat(DateTimeFormatter.ofPattern("yyyyMMdd+HHmmssZ"), "yyyyMMdd+HHmmssZ");
@@ -139,7 +156,7 @@
}
private static Jsonb newJsonb() {
- return newJsonb(null);
+ return newJsonb((String) null);
}
private static Jsonb newJsonb(String dateFormat) {
@@ -147,12 +164,17 @@
if (!StringUtils.isEmpty(dateFormat)){
jsonbConfig.withDateFormat(dateFormat, Locale.getDefault());
}
- return JsonbProvider.provider().create().withConfig(jsonbConfig.setProperty("johnzon.attributeOrder", new Comparator<String>() {
+
+ return newJsonb(jsonbConfig.setProperty("johnzon.attributeOrder", new Comparator<String>() {
@Override
public int compare(final String o1, final String o2) {
return o1.compareTo(o2);
}
- })).build();
+ }));
+ }
+
+ private static Jsonb newJsonb(JsonbConfig jsonbConfig) {
+ return JsonbProvider.provider().create().withConfig(jsonbConfig).build();
}
public static class Types {
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..a217f80 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
@@ -266,6 +266,16 @@
return this;
}
+ public MapperBuilder setUseBigIntegerStringAdapter(final boolean convertBigIntegerToString) {
+ adapters.setUseBigIntegerStringAdapter(convertBigIntegerToString);
+ return this;
+ }
+
+ public MapperBuilder setUseBigDecimalStringAdapter(final boolean convertBigDecimalToString) {
+ adapters.setUseBigDecimalStringAdapter(convertBigDecimalToString);
+ return this;
+ }
+
public MapperBuilder setAdaptersDateTimeFormatterString(final String dateTimeFormatter) {
adapters.setDateTimeFormatter(DateTimeFormatter.ofPattern(dateTimeFormatter));
return this;
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/map/LazyConverterMap.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/map/LazyConverterMap.java
index 9c12067..2a6c0bc 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/map/LazyConverterMap.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/map/LazyConverterMap.java
@@ -55,7 +55,6 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
-import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
@@ -64,7 +63,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
@@ -94,13 +92,8 @@
private boolean useShortISO8601Format = true;
private DateTimeFormatter dateTimeFormatter;
-
- private List<AdapterKey> builtInAdapterKeys = Stream.of(Date.class, URI.class, URL.class, Class.class, String.class,
- BigDecimal.class, BigInteger.class, Locale.class, Period.class, Duration.class, Calendar.class, GregorianCalendar.class,
- TimeZone.class, ZoneId.class, ZoneOffset.class, SimpleTimeZone.class, Instant.class, LocalDateTime.class, LocalDate.class,
- ZonedDateTime.class, OffsetDateTime.class, OffsetTime.class, LocalTime.class)
- .map(it -> new AdapterKey(it, String.class, true))
- .collect(Collectors.toList());
+ private boolean useBigIntegerStringAdapter = true;
+ private boolean useBigDecimalStringAdapter = true;
public void setUseShortISO8601Format(final boolean useShortISO8601Format) {
this.useShortISO8601Format = useShortISO8601Format;
@@ -110,13 +103,12 @@
this.dateTimeFormatter = dateTimeFormatter;
}
- @Override
- public Adapter<?, ?> remove(Object key) {
- if (key instanceof AdapterKey) {
- builtInAdapterKeys.remove(key);
- }
+ public void setUseBigDecimalStringAdapter(boolean useBigDecimalStringAdapter) {
+ this.useBigDecimalStringAdapter = useBigDecimalStringAdapter;
+ }
- return super.remove(key);
+ public void setUseBigIntegerStringAdapter(boolean useBigIntegerStringAdapter) {
+ this.useBigIntegerStringAdapter = useBigIntegerStringAdapter;
}
@Override
@@ -130,7 +122,7 @@
return null;
}
final AdapterKey k = AdapterKey.class.cast(key);
- if (builtInAdapterKeys.contains(k)) {
+ if (k.getTo() == String.class) {
final Adapter<?, ?> adapter = doLazyLookup(k);
if (adapter != null) {
return adapter;
@@ -150,8 +142,14 @@
}
public Set<AdapterKey> adapterKeys() {
- return Stream.concat(super.keySet().stream(), builtInAdapterKeys.stream())
- .filter(it -> super.get(it) != NO_ADAPTER)
+ return Stream.concat(
+ super.keySet().stream()
+ .filter(it -> super.get(it) != NO_ADAPTER),
+ Stream.of(Date.class, URI.class, URL.class, Class.class, String.class, BigDecimal.class, BigInteger.class,
+ Locale.class, Period.class, Duration.class, Calendar.class, GregorianCalendar.class, TimeZone.class,
+ ZoneId.class, ZoneOffset.class, SimpleTimeZone.class, Instant.class, LocalDateTime.class, LocalDate.class,
+ ZonedDateTime.class, OffsetDateTime.class, OffsetTime.class)
+ .map(it -> new AdapterKey(it, String.class, true)))
.collect(toSet());
}
@@ -172,10 +170,10 @@
if (from == String.class) {
return add(key, new ConverterAdapter<>(new StringConverter(), String.class));
}
- if (from == BigDecimal.class) {
+ if (from == BigDecimal.class && useBigIntegerStringAdapter) {
return add(key, new ConverterAdapter<>(new BigDecimalConverter(), BigDecimal.class));
}
- if (from == BigInteger.class) {
+ if (from == BigInteger.class && useBigDecimalStringAdapter) {
return add(key, new ConverterAdapter<>(new BigIntegerConverter(), BigInteger.class));
}
if (from == Locale.class) {
diff --git a/pom.xml b/pom.xml
index baf9653..6b93056 100644
--- a/pom.xml
+++ b/pom.xml
@@ -347,7 +347,7 @@
<property name="ignorePattern" value="@version|@see" />
</module>
<module name="MethodLength">
- <property name="max" value="258" />
+ <property name="max" value="264" />
</module>
<module name="ParameterNumber">
<property name="max" value="13" />