配置SerializerFeature.WriteBigDecimalAsPlain无效现象:
@Getter
@Setter
public static class TradeAccount{
private BigDecimal amount;
}
@Test
public void testLog(){
BigDecimal bigDecimal = new BigDecimal("0.00000005");
HashMap map = new HashMap<>();
map.put("amount", bigDecimal);
System.out.println(JSON.toJSONString(map, SerializerFeature.WriteBigDecimalAsPlain));
TradeAccount tradeAccount = new TradeAccount();
tradeAccount.setAmount(bigDecimal);
System.out.println(JSON.toJSONString(tradeAccount, SerializerFeature.WriteBigDecimalAsPlain));
}
结果:
{"amount":0.00000005}
{"amount":5E-8}
说明SerializerFeature.WriteBigDecimalAsPlain配置没有效果 查看源码:
public void writeFieldValue(char seperator, String name, BigDecimal value) {
write(seperator);
writeFieldName(name);
if (value == null) {
writeNull();
} else {
write(value.toString());//value.toString()导致
}
这个可能是fastjson的一个bug.
解决方法有三种
方法一.添加一个SerializeFilter
@Test
public void testLog(){
TradeAccount tradeAccount = new TradeAccount();
tradeAccount.setAmount(new BigDecimal("0.00000005"));
System.out.println(JSON.toJSONString(tradeAccount, new ValueFilter() {
@Override
public Object process(Object object, String name, Object value) {
if(value instanceof BigDecimal) {
return((BigDecimal)value).toPlainString();
}
return value;
}
}));
}
结果:
{"amount":"0.00000005"}
这种方法比较简单 但有一个缺点 结果变为字符串.方法二可以解决这个问题
方法二:添加两个SerializeFilter
@Test
public void testLog(){
TradeAccount tradeAccount = new TradeAccount();
tradeAccount.setAmount(new BigDecimal("0.00000005"));
AfterFilter afterFilter = new AfterFilter() {
@Override
public void writeAfter(Object object) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.getType() == BigDecimal.class) {
field.setAccessible(true);
Object value= null;
try {
value = field.get(object);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
writeKeyValue(field.getName(), value );
}
}
}
};
PropertyFilter filter = new PropertyFilter() {
@Override
public boolean apply(Object source, String name, Object value) {
if (value instanceof BigDecimal) {
return false;
}
return true;
}
};
System.out.println(JSON.toJSONString(tradeAccount, new SerializeFilter[]{afterFilter, filter},
SerializerFeature.WriteBigDecimalAsPlain));
}
结果:
{"amount":0.00000005}
方法二原理就是不使用fastjson 默认序列化BigDecimal类型的字段的方法,而自己调用
com.alibaba.fastjson.serializer.BigDecimalCodec(SerializerFeature.WriteBigDecimalAsPlain配置对此方法有效)
方法三:自定义序列化方法
public static class BigDecimalSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features){
SerializeWriter out = serializer.out;
BigDecimal value = (BigDecimal)object;
out.writeString(value.toPlainString());
}
}
@Getter
@Setter
public static class TradeAccount{
@JSONField(serializeUsing = BigDecimalSerializer.class)
private BigDecimal amount;
}
@Test
public void testLog(){
TradeAccount tradeAccount = new TradeAccount();
tradeAccount.setAmount(new BigDecimal("0.00000005"));
System.out.println(JSON.toJSONString(tradeAccount));
}
此方法类似方法一 但是需要添加注解 所以不能作为序列化的默认方法 如spring boot 将fastjson作为序列化工具类:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
FastJsonHttpMessageConverter4 fastConverter=new FastJsonHttpMessageConverter4();
FastJsonConfig fastJsonConfig=new FastJsonConfig();
fastJsonConfig.setSerializeFilters(new ValueFilter() {
@Override
public Object process(Object object, String name, Object value) {
if(value instanceof BigDecimal) {
return ((BigDecimal)value).toPlainString();
}
return value;
}
});
fastConverter.setFastJsonConfig(fastJsonConfig);
fastConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON_UTF8));
converters.add(fastConverter);
}