Skip to content

Commit

Permalink
Fix #2230
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Feb 5, 2019
1 parent a475c0d commit e287a62
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 6 deletions.
4 changes: 4 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -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 [email protected])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
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;
Expand All @@ -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;

/**
Expand All @@ -48,6 +55,10 @@ public JsonSerializer<?> createContextual(SerializerProvider prov,
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:
}
Expand Down Expand Up @@ -91,13 +102,69 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t
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:
/*JsonNumberFormatVisitor v2 =*/ visitor.expectNumberFormat(typeHint);
}
}
}
}

/**
* @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));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonFormat;
Expand Down Expand Up @@ -97,6 +98,9 @@ public JsonSerializer<?> createContextual(SerializerProvider prov,
if (format != null) {
switch (format.getShape()) {
case STRING:
if (((Class<?>) handledType()) == BigDecimal.class) {
return NumberSerializer.bigDecimalAsStringSerializer();
}
return ToStringSerializer.instance;
default:
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.failing;
package com.fasterxml.jackson.databind.ser.jdk;

import java.math.BigDecimal;

Expand Down Expand Up @@ -26,12 +26,12 @@ public void testBigIntegerAsPlainTest() throws Exception
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));
}
}

0 comments on commit e287a62

Please sign in to comment.