java fastjson如何自定义转换含枚举类型对象(编程技巧)

在使用fastjson对java对象进行序列化和反序列化时,如果含有枚举类型,默认会根据枚举变量的ordinal值进行反序列且序列化时显示枚举字面代表的字符串。经常这种行为不是我们想要的,那么如何进行定制化枚举类型的序列化和反序列? 举例如下

问题引出

假设待序列化和反序列化java对象结构如下

public class Msg {

    private int id;

    private StatusCodeEnum status;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public StatusCodeEnum getStatus() {
        return status;
    }

    public void setStatus(StatusCodeEnum status) {
        this.status = status;
    }


    public static enum StatusCodeEnum {
        OK(200, "正常"), SERVER_ERROR(500, "服务器错误");

        private static final Map<Integer, StatusCodeEnum> CODE_MAP = new HashMap<Integer, StatusCodeEnum>();

        static {
            for (StatusCodeEnum typeEnum : StatusCodeEnum.values()) {
                CODE_MAP.put(typeEnum.getCode(), typeEnum);
            }
        }

        StatusCodeEnum(int code, String meaning) {
            this.code = code;
            this.meaning = meaning;
        }

        public int getCode() {
            return code;
        }

        public String getMeaning() {
            return meaning;
        }

        public static StatusCodeEnum getEnum(Integer code) {
            return CODE_MAP.get(code);
        }

        private final int code;
        private final String meaning;
    }

}

对象内部定义了状态码枚举类StatusCodeEnum,包含两个实例OK、SERVER_ERROR。

反序列化问题

如何使用fastjson成功反序列如下json串?

{“id”:1,”status”:200}

显然,如果直接用Json.parseObject()方法进行反序列化,会报如下错误信息:

Exception in thread “main” com.alibaba.fastjson.JSONException: parse
enum com.netwaymedia.exhibition.nio.common.dto.Msg$StatusCodeEnum
error, value : 200 at
com.alibaba.fastjson.parser.deserializer.EnumDeserializer.deserialze(EnumDeserializer.java:48)
at
com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:33)

原因分析:前面已经提过,fastjson默认使用ordinal值去查找对应的枚举实例,显示是获取不到的,所以抛出异常,需要修改status值为0才运行OK。

序列化问题

如果使用JSON.toJSONString()方法对上述Msg对象进行序列化,会得到如下json串

{“id”:1,”status”:”OK”}

显示不是我们所期待的原始字符串

{“id”:1,”status”:200}

如何解决上述两大问题?

优雅的解决方案

答案就在于fastjson提供注解JSONField。通过JSONField可灵活控制字段的序列化和反序列,重新修改Msg结构如下:

public class Msg {

    private int id;

    private StatusCodeEnum statusCode;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @JSONField(name = "status")
    public int getStatus() {
        return statusCode.getCode();
    }

    @JSONField(name = "status")
    public void setStatus(int code) {
        this.statusCode = StatusCodeEnum.getEnum(code);
    }

    @JSONField(serialize = false)
    public StatusCodeEnum getStatusCode() {
        return statusCode;
    }

    @JSONField(deserialize = false)
    public void setStatusCode(StatusCodeEnum statusCode) {
        this.statusCode = statusCode;
    }

    public static enum StatusCodeEnum {
        OK(200, "正常"), BAD_REQUEST(400, "服务器出错");

        private static final Map<Integer, StatusCodeEnum> CODE_MAP = new HashMap<Integer, StatusCodeEnum>();

        static {
            for (StatusCodeEnum typeEnum : StatusCodeEnum.values()) {
                CODE_MAP.put(typeEnum.getCode(), typeEnum);
            }
        }

        StatusCodeEnum(int code, String meaning) {
            this.code = code;
            this.meaning = meaning;
        }

        public int getCode() {
            return code;
        }

        public String getMeaning() {
            return meaning;
        }

        public static StatusCodeEnum getEnum(Integer code) {
            return CODE_MAP.get(code);
        }

        private final int code;
        private final String meaning;
    }
}

思路是通过修改字段名为statusCode,并用JSONField注解该字段不进行序列和反序列化,但是提供getStatus/setStatus方法来定制化枚举变量statusCode的序列和反序列,完美的解决前面提到的两大问题。

这个方法我在网上还没看到过,是我自己尝试出来的,特别拿出来跟大家分享,不用谢,请叫我雷锋。

Fastjson支持自定义转换规则,可以通过实现自定义的序列化器(Serializer)和反序列化器(Deserializer)来实现。下面是一个简单的示例,演示如何自定义一个日期格式的序列化和反序列化规则: 首先,定义一个日期格式化的序列化器: ```java public class DateSerializer implements Serializer<Date> { @Override public void write(JSONSerializer serializer, Date date, Object fieldName, Type fieldType, int features) throws IOException { if (date == null) { serializer.writeNull(); return; } SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); serializer.write(format.format(date)); } } ``` 然后,定义一个日期格式化的反序列化器: ```java public class DateDeserializer implements ObjectDeserializer { @Override public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { String dateStr = parser.parseObject(String.class); if (StringUtils.isEmpty(dateStr)) { return null; } try { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return (T) format.parse(dateStr); } catch (ParseException e) { throw new JSONException("parse date error", e); } } @Override public int getFastMatchToken() { return JSONToken.LITERAL_STRING; } } ``` 最后,使用自定义的序列化器和反序列化器: ```java SerializeConfig.getGlobalInstance().put(Date.class, new DateSerializer()); ParserConfig.getGlobalInstance().putDeserializer(Date.class, new DateDeserializer()); ``` 这样,当Fastjson序列化或反序列化日期类型的对象时,就会使用我们自定义的日期格式化规则。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值