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

前端 未结 2 515
一个人的身影
一个人的身影 2021-01-11 14:22

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

2条回答
  •  灰色年华
    2021-01-11 15:29

    I used most of the suggested code but did the following, which uses DecimalFormat to do the formatting, which required outputting the raw text:

    import java.io.IOException;
    import java.text.DecimalFormat;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.BeanProperty;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.ser.ContextualSerializer;
    
    /**
     * Custom serializer to serialize Double to a specified precision in output string.
     * The @FormatterPrecision(precision=2) annotation needs to have been specified, for example:
     * 
     * @JsonSerialize(using=JacksonJsonDoubleSerializer.class) @FormatterPrecision(precision=6) abstract Double getLatitude();
     * 
    * @author sam * */ public class JacksonJsonDoubleSerializer extends JsonSerializer implements ContextualSerializer { /** * Precision = number of digits after the decimal point to display. * Last digit will be rounded depending on the value of the next digit. */ private int precision = 4; /** * Default constructor. */ public JacksonJsonDoubleSerializer ( ) { } /** * Constructor. * @param precision number of digits after the decimal to format numbers. */ public JacksonJsonDoubleSerializer ( int precision ) { this.precision = precision; } /** * Format to use. Create an instance so it is shared between serialize calls. */ private DecimalFormat format = null; /** * */ @Override public JsonSerializer createContextual(SerializerProvider provider, BeanProperty property ) throws JsonMappingException { FormatterPrecision precision = property.getAnnotation(FormatterPrecision.class); if ( precision != null ) { return new JacksonJsonDoubleSerializer(precision.precision()); } return this; } /** * Check that the format has been created. */ private DecimalFormat getFormat () { if ( this.format == null ) { // No format so create it StringBuilder b = new StringBuilder("0."); for ( int i = 0; i < this.precision; i++ ) { b.append("0"); } this.format = new DecimalFormat(b.toString()); } return this.format; } /** * Serialize a double */ @Override public void serialize(Double value, JsonGenerator jgen, SerializerProvider provider ) throws IOException { if ( (value == null) || value.isNaN() ) { jgen.writeNull(); } else { DecimalFormat format = getFormat(); jgen.writeRawValue(format.format(value)); } } }

    I am using a MixIn, so that class has:

    public abstract class StationJacksonMixIn {
    
        @JsonCreator
        public StationJacksonMixIn () {
    
        }
    
        // Serializers to control formatting
        @JsonSerialize(using=JacksonJsonDoubleSerializer.class) 
        @FormatterPrecision(precision=6) abstract Double getLatitude();
        @JsonSerialize(using=JacksonJsonDoubleSerializer.class) 
        @FormatterPrecision(precision=6) abstract Double getLongitude();
    }
    

    And, finally, enable the MixIn in the ObjectMapper:

    ObjectMapper objectMapper = new ObjectMapper().
                    addMixIn(Station.class,StationJacksonMixIn.class);
    

    It works well to provide a precision where it applies globally on the data field.

提交回复
热议问题