package com.fasterxml.jackson.databind.ser.std;
import java.io.IOException;
import java.lang.reflect.Type;
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;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
@JacksonStdImpl
@SuppressWarnings("serial")
public class NumberSerializer
extends StdScalarSerializer<Number>
implements ContextualSerializer
{
public final static NumberSerializer instance = new NumberSerializer(Number.class);
protected final static int MAX_BIG_DECIMAL_SCALE = 9999;
protected final boolean _isInt;
public NumberSerializer(Class<? extends Number> rawType) {
super(rawType, false);
_isInt = (rawType == BigInteger.class);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov,
BeanProperty property) throws JsonMappingException
{
JsonFormat.Value format = findFormatOverrides(prov, property, handledType());
if (format != null) {
switch (format.getShape()) {
case STRING:
if (((Class<?>) handledType()) == BigDecimal.class) {
return bigDecimalAsStringSerializer();
}
return ToStringSerializer.instance;
default:
}
}
return this;
}
@Override
public void serialize(Number value, JsonGenerator g, SerializerProvider provider) throws IOException
{
if (value instanceof BigDecimal) {
g.writeNumber((BigDecimal) value);
} else if (value instanceof BigInteger) {
g.writeNumber((BigInteger) value);
} else if (value instanceof Long) {
g.writeNumber(value.longValue());
} else if (value instanceof Double) {
g.writeNumber(value.doubleValue());
} else if (value instanceof Float) {
g.writeNumber(value.floatValue());
} else if (value instanceof Integer || value instanceof Byte || value instanceof Short) {
g.writeNumber(value.intValue());
} else {
g.writeNumber(value.toString());
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
return createSchemaNode(_isInt ? "integer" : "number", true);
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException
{
if (_isInt) {
visitIntFormat(visitor, typeHint, JsonParser.NumberType.BIG_INTEGER);
} else {
if (((Class<?>) handledType()) == BigDecimal.class) {
visitFloatFormat(visitor, typeHint, JsonParser.NumberType.BIG_DECIMAL);
} else {
visitor.expectNumberFormat(typeHint);
}
}
}
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 false;
}
@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;
if (!_verifyBigDecimalRange(gen, bd)) {
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) {
throw new IllegalStateException();
}
protected boolean _verifyBigDecimalRange(JsonGenerator gen, BigDecimal value) throws IOException {
int scale = value.scale();
return ((scale >= -MAX_BIG_DECIMAL_SCALE) && (scale <= MAX_BIG_DECIMAL_SCALE));
}
}
}