aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release-notes/CREDITS-2.x4
-rw-r--r--release-notes/VERSION-2.x2
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java73
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java4
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/ser/jdk/BigDecimalPlain2230Test.java (renamed from src/test/java/com/fasterxml/jackson/failing/BigDecimalPlain2230Test.java)6
5 files changed, 83 insertions, 6 deletions
diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x
index 9bb079d17..b3b0cefe4 100644
--- a/release-notes/CREDITS-2.x
+++ b/release-notes/CREDITS-2.x
@@ -849,3 +849,7 @@ Christoph Breitkopf (bokesan@github)
Alexander Saites (saites@github)
* Reported #2189: `TreeTraversingParser` does not check int bounds
(2.10.0)
+
+Pavel Chervakov (pacher@github)
+ * Reported #2230: `WRITE_BIGDECIMAL_AS_PLAIN` is ignored if `@JsonFormat` is used
+ (2.10.0)
diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x
index 8ebbeb885..cb87de168 100644
--- a/release-notes/VERSION-2.x
+++ b/release-notes/VERSION-2.x
@@ -31,6 +31,8 @@ Project: jackson-databind
#2223: Add `missingNode()` method in `JsonNodeFactory`
#2227: Minor cleanup of exception message for `Enum` binding failure
(reported by RightHandedMonkey@github)
+#2230: `WRITE_BIGDECIMAL_AS_PLAIN` is ignored if `@JsonFormat` is used
+ (reported by Pavel C)
#2241: Add `JsonPropertyNamingStrategy.LOWER_DOT_CASE` for dot-delimited names
(contributed by zenglian@github.com)
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java
index 118079836..56b30737f 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializer.java
@@ -6,8 +6,10 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import com.fasterxml.jackson.annotation.JsonFormat;
+
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
+
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
@@ -29,6 +31,11 @@ public class NumberSerializer
*/
public final static NumberSerializer instance = new NumberSerializer(Number.class);
+ /**
+ * Copied from `jackson-core` class `GeneratorBase`
+ */
+ protected final static int MAX_BIG_DECIMAL_SCALE = 9999;
+
protected final boolean _isInt;
/**
@@ -48,6 +55,10 @@ public class NumberSerializer
if (format != null) {
switch (format.getShape()) {
case STRING:
+ // [databind#2264]: Need special handling for `BigDecimal`
+ if (((Class<?>) handledType()) == BigDecimal.class) {
+ return bigDecimalAsStringSerializer();
+ }
return ToStringSerializer.instance;
default:
}
@@ -91,8 +102,7 @@ public class NumberSerializer
if (_isInt) {
visitIntFormat(visitor, typeHint, JsonParser.NumberType.BIG_INTEGER);
} else {
- Class<?> h = handledType();
- if (h == BigDecimal.class) {
+ if (((Class<?>) handledType()) == BigDecimal.class) {
visitFloatFormat(visitor, typeHint, JsonParser.NumberType.BIG_DECIMAL);
} else {
// otherwise bit unclear what to call... but let's try:
@@ -100,4 +110,61 @@ public class NumberSerializer
}
}
}
-} \ No newline at end of file
+
+ /**
+ * @since 2.10
+ */
+ public static JsonSerializer<?> bigDecimalAsStringSerializer() {
+ return BigDecimalAsStringSerializer.BD_INSTANCE;
+ }
+
+ final static class BigDecimalAsStringSerializer
+ extends ToStringSerializerBase
+ {
+ final static BigDecimalAsStringSerializer BD_INSTANCE = new BigDecimalAsStringSerializer();
+
+ public BigDecimalAsStringSerializer() {
+ super(BigDecimal.class);
+ }
+
+ @Override
+ public boolean isEmpty(SerializerProvider prov, Object value) {
+ return valueToString(value).isEmpty();
+ }
+
+ @Override
+ public void serialize(Object value, JsonGenerator gen, SerializerProvider provider)
+ throws IOException
+ {
+ final String text;
+ if (gen.isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN)) {
+ final BigDecimal bd = (BigDecimal) value;
+ // 24-Aug-2016, tatu: [core#315] prevent possible DoS vector, so we need this
+ if (!_verifyBigDecimalRange(gen, bd)) {
+ // ... but wouldn't it be nice to trigger error via generator? Alas,
+ // no method to do that. So we'll do...
+ final String errorMsg = String.format(
+ "Attempt to write plain `java.math.BigDecimal` (see JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) with illegal scale (%d): needs to be between [-%d, %d]",
+ bd.scale(), MAX_BIG_DECIMAL_SCALE, MAX_BIG_DECIMAL_SCALE);
+ provider.reportMappingProblem(errorMsg);
+ }
+ text = bd.toPlainString();
+ } else {
+ text = value.toString();
+ }
+ gen.writeString(text);
+ }
+
+ @Override
+ public String valueToString(Object value) {
+ // should never be called
+ throw new IllegalStateException();
+ }
+
+ // 24-Aug-2016, tatu: [core#315] prevent possible DoS vector, so we need this
+ protected boolean _verifyBigDecimalRange(JsonGenerator gen, BigDecimal value) throws IOException {
+ int scale = value.scale();
+ return ((scale >= -MAX_BIG_DECIMAL_SCALE) && (scale <= MAX_BIG_DECIMAL_SCALE));
+ }
+ }
+}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java
index 8af633d5b..8fd2b875f 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/NumberSerializers.java
@@ -2,6 +2,7 @@ package com.fasterxml.jackson.databind.ser.std;
import java.io.IOException;
import java.lang.reflect.Type;
+import java.math.BigDecimal;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -97,6 +98,9 @@ public class NumberSerializers {
if (format != null) {
switch (format.getShape()) {
case STRING:
+ if (((Class<?>) handledType()) == BigDecimal.class) {
+ return NumberSerializer.bigDecimalAsStringSerializer();
+ }
return ToStringSerializer.instance;
default:
}
diff --git a/src/test/java/com/fasterxml/jackson/failing/BigDecimalPlain2230Test.java b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/BigDecimalPlain2230Test.java
index 36dd49d29..fdbe0880b 100644
--- a/src/test/java/com/fasterxml/jackson/failing/BigDecimalPlain2230Test.java
+++ b/src/test/java/com/fasterxml/jackson/databind/ser/jdk/BigDecimalPlain2230Test.java
@@ -1,4 +1,4 @@
-package com.fasterxml.jackson.failing;
+package com.fasterxml.jackson.databind.ser.jdk;
import java.math.BigDecimal;
@@ -26,12 +26,12 @@ public class BigDecimalPlain2230Test extends BaseMapTest
final BigDecimal BD_VALUE = new BigDecimal(NORM_VALUE);
final BigDecimalAsString INPUT = new BigDecimalAsString(BD_VALUE);
// by default, use the default `toString()`
- assertEquals("{\"value\":\""+BD_VALUE.toString()+"\"", MAPPER.writeValueAsString(INPUT));
+ assertEquals("{\"value\":\""+BD_VALUE.toString()+"\"}", MAPPER.writeValueAsString(INPUT));
// but can force to "plain" notation
final ObjectMapper m = jsonMapperBuilder()
.enable(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN)
.build();
- assertEquals("{\"value\":\""+NORM_VALUE+"\"", m.writeValueAsString(INPUT));
+ assertEquals("{\"value\":\""+NORM_VALUE+"\"}", m.writeValueAsString(INPUT));
}
}