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

本文记录了在SpringBoot项目中使用fastjson处理枚举类型时遇到的问题,包括默认策略的局限性以及如何通过自定义Converter、ConverterFactory或ObjectSerializer、ObjectDeserializer来实现特殊需求。在尝试过程中,发现 JSONObject的toJavaObject()方法不支持注解方式的自定义反序列化,而parseObject()方法则能支持。文章强调了fastjson对于String枚举支持较好,而Integer枚举支持不足,同时提出了对最新版本增加BigDecimal支持的疑问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通常,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> T castToEnum(Object obj, Class<T> 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<? extends Enum>) 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使用过程中的一些问题,仅供参考~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值