Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need Jackson serializer for Double and need to specify precision at runtime

There are many posts about creating Jackson serializers for numbers, currency, etc. For engineering applications, there is often a need to set the precision on numbers based on the units or other criteria.

For example, spatial coordinates might be constrained to 5 or 6 digits after the decimal point, and temperature might be constrained to 2 digits after the decimal point. Default serializer behavior that has too many digits or truncated exponential notation is not good. What I need is something like:

@JsonSerialize(using=MyDoubleSerializer.class, precision=6) double myValue;

and better yet be able to specify the precision at run-time. I am also using a MixIn. I could write a serializer for each class but hoped to specify on specific values.

Any ideas would be appreciated.

like image 543
smalers Avatar asked May 22 '17 10:05

smalers


People also ask

What is Jackson serializer?

The Jackson Object mapper can parse JSON into objects of classes developed by you, or into objects of the built-in JSON tree model explained later in this tutorial. By the way, the reason it is called ObjectMapper is because it maps JSON into Java Objects (deserialization), or Java Objects into JSON (serialization).

Does Jackson need serializable?

Note that Jackson does not use java. io. Serializable for anything: there is no real value for adding that. It gets ignored.


1 Answers

You may use Jackson's ContextualSerializer to achieve desired serialization as shown below.

Firstly, create an annotation to capture precision

@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Precision {
    int precision();
}

Next, create a contextual serializer for Double type which looks for Precision annotation on the field to be serialized and then create a new serializer for the specified precision.

public class DoubleContextualSerializer extends JsonSerializer<Double> implements ContextualSerializer {

    private int precision = 0;

    public DoubleContextualSerializer (int precision) {
        this.precision = precision;
    }

    public DoubleContextualSerializer () {

    }

    @Override
    public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
        if (precision == 0) {
            gen.writeNumber(value.doubleValue());
        } else {
            BigDecimal bd = new BigDecimal(value);
            bd = bd.setScale(precision, RoundingMode.HALF_UP);
            gen.writeNumber(bd.doubleValue());
        }

    }
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Precision precision = property.getAnnotation(Precision.class);
        if (precision != null) {
            return new DoubleContextualSerializer (precision.precision());
        }
        return this;
    }
}

Finally, annotate your field to use custom serializer and set precision

public class Bean{

   @JsonSerialize(using = DoubleContextualSerializer .class)
   @Precision(precision = 2)
   private double doubleNumber;

}

Hope this helps!!

like image 83
Justin Jose Avatar answered Sep 21 '22 13:09

Justin Jose