【未解决】自定义Double序列化无法处理null

一、问题出现背景

  • 返回json结果中如果有通过计算获取的double值,小数点后面有很多位小数
{
    "payable": 25.00000000021
}

二、可能原因及尝试过程:

1、原因是double类型计算是不准确的,所以需要处理结果

2、百度找到序列化double的文章使用自定义序列化方法添加json注解解决返回数据double限定小数点后几位长度,多余的舍弃以及double数据控制保留小数的几种方法,关于Java中DecimalFormat()方法的调用

  • 添加注解@JsonSerialize
@JsonSerialize(using = Double2Serializer.class)
private Double payable;
  • 自定义序列化对象方法(注意此处JsonSerializer中的Object是对象类型的泛型,而不能用基本数据类型,编辑器会提示报错的,如double)
    public class Double2Serializer extends JsonSerializer {
        private DecimalFormat df = new DecimalFormat("0.00");
    
        {
            //显示几位修改几
            df.setMaximumFractionDigits(2);
            df.setGroupingSize(0);
            //默认向上取整,这里直接舍去后面几位
            df.setRoundingMode(RoundingMode.FLOOR);
        }
    
        @Override
        public void serialize(Double doubleValue, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            if (Objects.nonNull(doubleValue)) {
                // 返回出去是字符串
                jsonGenerator.writeString(df.format(doubleValue));
                // 返回出去是数字形式
                //jsonGenerator.writeNumber(df.format(doubleValue));
            } else {
                System.err.println("====== null居然处理了 =====");
                jsonGenerator.writeString(df.format(0.0));
                //jsonGenerator.writeNumber(df.format(0.0));
            }
        }
    }
    • 结果是对小数只保留了两位小数,但对null仍然不做处理 
    package com.fasterxml.jackson.databind.ser;
    
    @JacksonStdImpl
    public class BeanPropertyWriter extends PropertyWriter implements Serializable {
        private static final long serialVersionUID = 1L;
        public static final Object MARKER_FOR_EMPTY;
        protected final SerializedString _name;
        protected final PropertyName _wrapperName;
        protected final JavaType _declaredType;
        protected final JavaType _cfgSerializationType;
        protected JavaType _nonTrivialBaseType;
        protected final transient Annotations _contextAnnotations;
        protected final AnnotatedMember _member;
        protected transient Method _accessorMethod;
        protected transient Field _field;
        protected JsonSerializer _serializer;
        protected JsonSerializer _nullSerializer;
        protected TypeSerializer _typeSerializer;
        protected transient PropertySerializerMap _dynamicSerializers;
        protected final boolean _suppressNulls;
        protected final Object _suppressableValue;
        protected final Class[] _includeInViews;
        protected transient HashMap _internalSettings;
    
        public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
            Object value = this._accessorMethod == null ? this._field.get(bean) : this._accessorMethod.invoke(bean, (Object[])null);
            // 对null用全局处理,无法继承重写方法
            if (value == null) {
                if (this._nullSerializer != null) {
                    gen.writeFieldName(this._name);
                    this._nullSerializer.serialize((Object)null, gen, prov);
                }
            } else {
                JsonSerializer ser = this._serializer;
                if (ser == null) {
                    Class cls = value.getClass();
                    PropertySerializerMap m = this._dynamicSerializers;
                    ser = m.serializerFor(cls);
                    if (ser == null) {
                        ser = this._findAndAddDynamic(m, cls, prov);
                    }
                }
    
                if (this._suppressableValue != null) {
                    if (MARKER_FOR_EMPTY == this._suppressableValue) {
                        if (ser.isEmpty(prov, value)) {
                            return;
                        }
                    } else if (this._suppressableValue.equals(value)) {
                        return;
                    }
                }
                // 自定义序列化
                if (value != bean || !this._handleSelfReference(bean, gen, prov, ser)) {
                    gen.writeFieldName(this._name);
                    if (this._typeSerializer == null) {
                        ser.serialize(value, gen, prov);
                    } else {
                        ser.serializeWithType(value, gen, prov, this._typeSerializer);
                    }
                }
            }
        }
    }
    
    • 附上DecimalFormat的使用
    符号 位置 本地化? 含义
    0 数字 阿拉伯数字
    # 数字

    阿拉伯数字

    如果不存在就显示为空

    . 数字 小数分隔符或货币小数分隔符
    - 数字 减号
    , 数字 分组分隔符
    E 数字 分割科学技术法中的尾数和指数。在前缀和后缀中无需添加引号
    ; 子模式边界 分隔正数和负数子模式
    % 前缀或后缀 乘以100并显示为百分数/u2030前缀或后缀是乘以1000并显示为千分数
    ¤ (\u00A4) 前缀或后缀 货币记号,由货币符号替换。如果两个同时出现,则用国际货币符号替换。如果出现在某个模式中,则使用货币小数分隔符,而不使用小数分隔符
    ' 前缀或后缀 用于在前缀或或后缀中为特殊字符加引号,例如 "'#'#" 将 123 格式化为 "#123"。要创建单引号本身,请连续使用两个单引号:"# o''clock"
    double pi = 3.1415927;//圆周率
    //取一位整数
    System.out.println(new DecimalFormat("0").format(pi));//3
    //取一位整数和两位小数
    System.out.println(new DecimalFormat("0.00").format(pi));//3.14
    //取两位整数和三位小数,整数不足部分以0填补。
    System.out.println(new DecimalFormat("00.000").format(pi));// 03.142
    //取所有整数部分
    System.out.println(new DecimalFormat("#").format(pi));//3
    //以百分比方式计数,并取两位小数
    System.out.println(new DecimalFormat("#.##%").format(pi));//314.16%
    
     /**
      * 上面的代码就是网上很经典的案例,下面我们来分析另外的一个值
      */      
    pi=12.34567;
    //取一位整数
    System.out.println(new DecimalFormat("0").format(pi));//12
    //取一位整数和两位小数
    System.out.println(new DecimalFormat("0.00").format(pi));//12.35
    //取两位整数和三位小数,整数不足部分以0填补。
    System.out.println(new DecimalFormat("00.000").format(pi));// 12.346
    //取所有整数部分
    System.out.println(new DecimalFormat("#").format(pi));//12
    //以百分比方式计数,并取两位小数
    System.out.println(new DecimalFormat("#.##%").format(pi));//1234.57%
    
    /**
     * 扩展,如果是其他的数字会是下面的效果
     */
    pi=12.34;
    //整数
    System.out.println(new DecimalFormat("6").format(pi));//612
    System.out.println(new DecimalFormat("60").format(pi));//612
    System.out.println(new DecimalFormat("06").format(pi));//126
    System.out.println(new DecimalFormat("00600").format(pi));//00126
    System.out.println(new DecimalFormat("#####60000").format(pi));//00126
    //小数
    System.out.println(new DecimalFormat(".6").format(pi));//12.6
    System.out.println(new DecimalFormat(".06").format(pi));//12.36
    System.out.println(new DecimalFormat(".60").format(pi));//12.36
    System.out.println(new DecimalFormat(".0600").format(pi));//12.3406
    System.out.println(new DecimalFormat(".6000").format(pi));//12.3406
    System.out.println(new DecimalFormat(".600000##").format(pi));//12.340006

    三、最终解决:

    • 使用自定义对象 Double2Serializer 处理 Double 的值,但是对 null 是不做处理的。
    • 对计算结果进行处理,如果为 null 转为0(然后非null会序列化为0.00),或者根据需要不做处理(还是显示null)

    备注:

    本文主要是借助博客环境,同大家讨论异常问题解决的办法,欢迎大家评论,谢谢!

     

    你可能感兴趣的:(业务问题解决)