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;
    }

舒服了.....

如果大家頭更好的方法歡迎評論區討論交流~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM