如何使用Jackson 2.0.2实现指定格式的JSON浮点数输出
解决Jackson序列化浮点数格式不一致的问题
咱们先还原下你的场景:用Jackson 2.0.2版本,执行代码后得到了两种不同的输出,而你想要的是结合两者的优点——data保持10000000.00的格式,data2变成0.0。
先说说为什么会出现这种差异:
- 第一个开启了
USE_BIG_DECIMAL_FOR_FLOATS的ObjectMapper,会把JSON里的浮点数解析成BigDecimal类型,序列化时会保留原始的数字字符串格式,所以0E-7就原样输出了; - 第二个默认的
ObjectMapper会把浮点数解析成Double类型,序列化时用Double的默认规则,把10000000.00转成科学计数法1.0E7,同时把0E-7转成0.0。
要实现你想要的输出,咱们可以通过自定义BigDecimal序列化器来控制格式,具体步骤如下:
步骤1:编写自定义BigDecimal序列化器
这个序列化器会针对不同的BigDecimal值做特殊处理:0值统一输出为0.0,其他值保留原始的小数格式。
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.math.BigDecimal; public class CustomBigDecimalSerializer extends JsonSerializer<BigDecimal> { @Override public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (BigDecimal.ZERO.compareTo(value) == 0) { // 所有0值统一输出为0.0 gen.writeNumber("0.0"); } else { // 其他值保留原始的小数格式 gen.writeNumber(value.toPlainString()); } } }
步骤2:配置ObjectMapper并使用
把自定义序列化器注册到开启了USE_BIG_DECIMAL_FOR_FLOATS的ObjectMapper中,这样解析和序列化时就会按照我们的规则来:
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; public class Main { public static void main(String[] args) throws Exception { String jsonString = "{\"data\":10000000.00, \"data2\" : 0E-7}"; ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); // 注册自定义序列化器 SimpleModule module = new SimpleModule(); module.addSerializer(BigDecimal.class, new CustomBigDecimalSerializer()); mapper.registerModule(module); JsonNode jsonNode = mapper.readTree(jsonString); System.out.println(jsonNode.toString()); } }
执行这段代码后,就能得到你想要的输出:{"data":10000000.00,"data2":0.0}。
如果你的场景里只有个别字段需要调整,也可以不用全局注册序列化器,而是直接修改JsonNode的对应节点值,比如:
((ObjectNode) jsonNode).put("data2", BigDecimal.ZERO.setScale(1));
这种方式更适合字段固定的简单场景。
内容的提问来源于stack exchange,提问作者user636856
相关产品推荐
相关产品推荐

