Jackson反序列化枚举类型解决方案

BUG描述

在使用SpringBoot自带的jackson处理客户端提交的消息体反序列化时,遇到一个非常棘手的情况

客户端发送如下json

{"content":"6545566","type":"1","to":"xxx"}

Java对应实体类

abstract class BaseMessage implements Message{

    @JsonIgnore
    protected String from;
    @JsonIgnore
    protected String address;
    @JsonIgnore
    protected Date sendTime;
    
    protected MessageType type;

    /**
     * 客户端信息的处理方法
     * @return netty socket回复对象
     */
    @Override
    public abstract BaseResult handle();
}

MessageType枚举类

/**
 * @author Evan
 */
public enum MessageType {
    /**
     *
     */
    TEXT(1),
    /**
     *
     */
    IMAGE(2);

    private int index;


    MessageType(int index) {
        this.index = index;
    }

    public int getValue() {
        return index;
    }
}

在反序列化的时候出现以下错误
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "type"

报错信息说明的很清楚,枚举属性type在反序列化的时候无法识别.其实也可以理解,枚举本身就是一个很特殊的数据类型Jackson无法正常的序列化也正常

解决思路

其实这个问题一开始真是难到我了,按之前的项目经验来说,在处理前端数据对应的实体类的属性一般是不会使用枚举类型的一般这种类似的属性我们都要求客户端以整数值提交后台,后台实体类也按integer类型保存.此类问题真的少见

面向Google编程,得到最靠谱最简单的方案是在枚举类使用@JsonCreator注解标识一个工厂方法创建正确的枚举值,但是不知道为什么在我这里毫无效果

查阅资料后了解到Jackson是允许为单独属性定义转换器的

实现如下代码

/**
 * @author Evan
 */
public class MessageTypeConverter implements Converter<String, MessageType> {

    @Override
    public MessageType convert(String value) {
        return MessageType.valueOf(Integer.parseInt(value));
    }

    /**
     * 输入值类型
     * @param typeFactory
     * @return
     */
    @Override
    public JavaType getInputType(TypeFactory typeFactory) {
        return typeFactory.constructType(String.class);
    }

    /**
     * 转换器输出值类型
     * @param typeFactory
     * @return
     */
    @Override
    public JavaType getOutputType(TypeFactory typeFactory) {
        return typeFactory.constructType(MessageType.class);
    }
}

其中关键就在于convert方法,我们要求前台提交一个String类型的数值给我们,我们在根据这个数值给转换器该属性准确的值

枚举类MessageTpe添加valueOf方法

 public static MessageType valueOf(int value) {
        switch (value) {
            case 1:
                return TEXT;

            case 2:
                return IMAGE;
            default:
                return null;
        }
    }

实体类BaseMessagetype属性添加注解指定反序列转换器

/**
 * @author Evan
 */
abstract class BaseMessage implements Message{

    @JsonIgnore
    protected String from;
    @JsonIgnore
    protected String address;
    @JsonIgnore
    protected Date sendTime;
    @JsonDeserialize(converter = MessageTypeConverter.class)
    protected MessageType type;

    /**
     * 客户端信息的处理方法
     * @return netty socket回复对象
     */
    @Override
    public abstract BaseResult handle();
}

那么就可以从一个数值得到正确的对应的枚举类型了

emmmmmmmmmmm.........问题是解决了.....

好像哪里不对劲

他喵的要switch我还定义啥枚举啊

修改枚举类MessageTypevalueOf方法

    public static MessageType valueOf(int value) {
        for (MessageType type : MessageType.values()){
            if (type.getValue() == value){
                return type;
            }
        }
        return null;
    }

舒服了.....

如果大家头更好的方法欢迎评论区讨论交流~

原文地址:https://www.cnblogs.com/liangshu/p/12405754.html