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;
}
}
實體類BaseMessage
的type
屬性添加注解指定反序列轉換器
/**
* @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
我還定義啥枚舉啊
修改枚舉類MessageType
的valueOf
方法
public static MessageType valueOf(int value) {
for (MessageType type : MessageType.values()){
if (type.getValue() == value){
return type;
}
}
return null;
}
舒服了.....
如果大家頭更好的方法歡迎評論區討論交流~