前言

在公司某次订单上区块链时候通过http形式传输数据到区块链中心,数据是以Json字符串形式传输,但是区块链中心接收到的数据(BigDecimal类型)丢失了无用的0,导致两边签名校验一直失败。记录该痛点,毕竟当时定位问题就花了近一天时间,比如0.000000数据通过json格式http传输到对方那边就变成了0;100.0000500000,则变成了100.00005。

解决分析

解决方式两个思路:

  • 要么在传输前将BigDecimal转换成String类型的数据,因为双引号包裹住的数据一定不会被转换舍弃。
  • 要么在传输过程中让http保留。

显然第一种对于我们会更加容易,第二种我也不会。

尝试两种思路

第一种试用注解

由于我的传输字段有七八十个,比较笨的方法我每个BigDecimal上面都试用Json注解( @JsonSerialize(using = JsonMessageSerialize.class))该注解maven依赖为

 <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

JsonMessageSerialize为我自定义的一个类

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;
import java.math.RoundingMode;

public class JsonMessageSerialize extends JsonSerializer<BigDecimal> {
    @Override
    public void serialize(BigDecimal bigDecimal, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (bigDecimal !=null){
            BigDecimal decimal=bigDecimal.setScale(2, RoundingMode.HALF_UP);
            jsonGenerator.writeString(decimal.toString());
        }else {
            jsonGenerator.writeString(String.valueOf((Object) null));
        }
}
}

这个时候要注意了,如果想使得注解起作用也必须得试用jackson的序列化方式,比如我的是:

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonMapper {

    public static String objectToString(Object o){
        ObjectMapper mapper=new ObjectMapper();
        mapper.setSerializationInclusion(Include.NON_NULL);
        try {
            return mapper.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

这个确实可以解决我的问题,但是我个人比较懒,我不想在七八十个字段里面去找BigDecimal然后一个个加注解。

使用字段过滤器

我项目本身使用的Json序列化方式是fastJson,所以在不引入其他jar的情况下选择这种方式最快捷的。只需要在JSON.toJsonString方法里面加入字段过滤就好了,这个也是我之前没见过的方式。

第一回我使用的是:

    public static String objectToJson(final Object o) {
     //过滤空的字段,日期格式化为yyyy-MM-dd HH:mm:ss,将BigDecimal转成String
    private static final SerializerFeature[] IGNORE_NULL = {
            SerializerFeature.WriteDateUseDateFormat
            ,SerializerFeature.WriteBigDecimalAsPlain};
        return JSON.toJSONString(o,IGNORE_NULL);
    }

但是很可惜这里并没法儿对BigDecimal转换,后来查阅资料说是这是fastJson的一个bug

最终我采用了字段过滤:

   public static String objectToJson(final Object o) {
        return JSON.toJSONString(o,new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                if(value instanceof BigDecimal) {
                    return((BigDecimal)value).toPlainString();
                }
                if(value instanceof Date) {
                    return new SimpleDateFormat("yyyy-MM-dd").format(value);
                }
                return value;
            }
        });
    }

果然行得通这类的转换,也成功将这枚多字段里面的BigDecimal转为了String类型。这里做一个记录点

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 3 个月前
8c391e04 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐