確保金融系統中的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後,保持精度的例子:

作者:張人傑  某互聯網公司架構師

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