fastjson枚举转换(序列化、反序列化)最新版本爬坑记录

通常,fastjson在序列化及反序列化枚举时,一般以下几种策略:

1).根据枚举的name值序列化及反序列化(默认)

2).根据枚举的ordinal序列化及反序列化

3).根据枚举的toString方法序列化,但是反序列仍采取默认的策略

 

但有时候我们的需求可能不是这样的,比如定义的枚举如下:

public enum DataStatus {

    CREATE(1, "新建"),

    READ(2, "读取"),

    UPDATE(3, "更新"),

    DELETE(4, "删除");

    private Integer value;

    private String text;

    DataStatus(Integer value, String text) {
        this.value = value;
        this.text = text;
    }

    /*这里省略很多代码*/

    public Integer getValue() {
        return this.value;
    }

    public String getText() {
        return this.text;
    }

    @Override
    public String toString() {
        return "{\"value\":" + this.value + ",text:\"" + this.text + "\"}";
    }

}

使用需求是,序列化、反序列化的值是数字,并且在需要的时候,可以显示汉字,因此需要返回一个稍微复杂的json字符串,并提供值和显示文本的内容,由调用者(web端、api调用)决定具体如何使用

 

通过分析得知,fastjson直接提供的几种策略,都不符合要求,因此我们需要自定义fastjson的序列化、反序列化

 

fastjson自定义(枚举)序列化、反序列化

 

实现方式一:Converter、ConverterFactory

参考资料:https://notes.0xl2oot.cn/springboot/2018/11/16/springboot-request-param-enums.html

备        注:最新版本springboot、fastjson未调通,具体原因时间关系,未深入研究~

 

实现方式二:ObjectSerializer、ObjectDeserializer 

参考资料:https://blog.csdn.net/qq_26680031/article/details/83473643

参考资料:https://www.cnblogs.com/insaneXs/p/9515803.html

备        注:调通了,但结合使用需求的过程有些曲折,详见后续内容~

 

爬坑记录

1、JSONObject的toJavaObjec()反序列化方法不支持注解方式自定义反序列化

枚举类上使用@JSONType(deserializer = xxx.class)

枚举属性类上使用@JSONField(deserializeUsing=xxx.class)

以上两种方式测试都无效,还是调用fastjson默认实现,具体原因是什么,看fastjson实现就知道了

核心实现代码:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/util/TypeUtils.java

public static  T castToEnum(Object obj, Class clazz, ParserConfig mapping){
        try{
            if(obj instanceof String){
                String name = (String) obj;
                if(name.length() == 0){
                    return null;
                }

                if (mapping == null) {
                    mapping = ParserConfig.getGlobalInstance();
                }

                ObjectDeserializer derializer = mapping.getDeserializer(clazz);
                if (derializer instanceof EnumDeserializer) {
                    EnumDeserializer enumDeserializer = (EnumDeserializer) derializer;
                    return (T) enumDeserializer.getEnumByHashCode(TypeUtils.fnv1a_64(name));
                }

                return (T) Enum.valueOf((Class) clazz, name);
            }

            if(obj instanceof BigDecimal){
                int ordinal = intValue((BigDecimal) obj);
                Object[] values = clazz.getEnumConstants();
                if(ordinal < values.length){
                    return (T) values[ordinal];
                }
            }

            if(obj instanceof Number){
                int ordinal = ((Number) obj).intValue();
                Object[] values = clazz.getEnumConstants();
                if(ordinal < values.length){
                    return (T) values[ordinal];
                }
            }
        } catch(Exception ex){
            throw new JSONException("can not cast to : " + clazz.getName(), ex);
        }
        throw new JSONException("can not cast to : " + clazz.getName());
    }

以上代码中,BigDecimal和Number都还是使用的ordinal方式

 

2、JSONObject.parseObject(jsonObject.toJSONString(), xxxClass)支持1中的自定义反序列化调用,最终功能实现

 

通过爬坑过程可以得知,fastjson对String类型的枚举支持是友好的,而对Integer支持是不友好的

甚至在解决String枚举bug的过程中,并没有解决Integer枚举同样的问题

另外,最新版本增加了BigDecimal的支持,但这么“大”的枚举值场景,真的有使用需求吗?

 

简单记录一下fastjson使用过程中的一些问题,仅供参考~

你可能感兴趣的:(fastjson枚举转换(序列化、反序列化)最新版本爬坑记录)