zoukankan      html  css  js  c++  java
  • 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;
        }
    

    舒服了.....

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

  • 相关阅读:
    list拖动
    android sdk
    AwwwB推荐网站全盘克隆
    WPF中的容器控件——WrapPanel
    WPF中的容器控件——StackPanel
    MFC应用程序中指针的使用
    排序算法之插入排序
    转:MFC 常用语句集锦
    【转】MFC学习总结
    排序算法之冒泡排序
  • 原文地址:https://www.cnblogs.com/liangshu/p/12405754.html
Copyright © 2011-2022 走看看