确保金融系统中的BigDecimal数据转换为json的精度不丢失

我们知道数值2.9传递给一个double型的变量a时,a就变成了2.899999999999999911182158029987476766109466552734375,而不是2.9。所以,也有了double值比较是否相等时需要比较一个范围的if判断方式。

而在金融系统中,数值计算往往需要精确的计算和表达,这就在java系统中引入了BigDecimal数据类型,但是普通的程序员会记得在java中使用BigDecimal,而往往忽视在json接口开发中,java对象转换成json,再由json转换成java对象时的精度丢失。

因为:java转换成json对象时,BigDecimal就变成了double表达,结果是{"value":2.899999999999999911182158029987476766109466552734375};(这一步丢失了精度)

而再由json转换成java时,调用的是new BigDecimal(double)方法,而不是new BigDecimal(String)方法;因此,数据就在这又丢失了精度(原始数据为2.899999999999999911182158029987476766109466552734375,而转换后成了2.9)。

下图是精度丢失的例子,转换使用的是fasterxml.jackson:

为此,在所有的json接口编码中,我们需要规范数值的传递必须使用BigDecimal的String方式,也就有了我的架构代码中的下方这个标注处理类:
 

package com.zhrenjie04.alex.core;

import java.io.IOException;
import java.math.BigDecimal;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
 * 用于@JsonSerialize标注序列化BigDecimal为字符串
 * 用法:@JsonSerialize(using=AlexBigDecimalSerializer.class)
 * @author Alex.Zhang 作者:张人杰
 * 使用、引用,请保留作者信息
 */
public class AlexBigDecimalSerializer extends JsonSerializer<BigDecimal> {
	
	@Override
	public void serialize(BigDecimal value, JsonGenerator gen, SerializerProvider serializers)
			throws IOException, JsonProcessingException {
		if(value!=null) {
			gen.writeString(value.toString());
		}else {
			gen.writeNull();
		}
	}
}

 用法也很简单:
 

public class BigDecimalToJsonExample {
	@JsonSerialize(using=AlexBigDecimalSerializer.class)
	private BigDecimal value;

	public BigDecimal getValue() {
		return value;
	}
	public void setValue(BigDecimal value) {
		this.value = value;
	}
	public static void main(String[] args) {
		BigDecimal d=new BigDecimal("2.9");
		BigDecimalToJsonExample example=new BigDecimalToJsonExample();
		example.setValue(d);
		String s=JsonUtil.stringify(example);
		System.out.println(s);
		example=JsonUtil.parse(s, BigDecimalToJsonExample.class);
		System.out.println(example.getValue());
	}
	
}

这样,在BigDecimal的数据转换后,就变成了:{"value":"2.9"},再由json转换为BigDecimal时调用的就是new BigDecimal(String),这就保证了数值精度的不丢失。下面是使用AlexBigDecimalSerializer后,保持精度的例子:

作者:张人杰  某互联网公司架构师

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章