问题描述
先看实体类:
import com.fasterxml.jackson.annotation.*;
import lombok.Data;
import org.jeecg.common.system.base.entity.JeecgEntity;
import org.jeecg.modules.iot.entity.jackson.WorkerConverter;
import org.jeecg.modules.iot.entity.jackson.WorkersDeserializer;
import org.jeecg.modules.iot.entity.jackson.WorkersSerializer;
import java.io.Serializable;
import java.util.List;
@Data
public class Mechanical extends JeecgEntity {//父类也实现了Serializable
private String deviceId; //设备编号
//...其他字段略
//我是问题字段
//@JsonSerialize(using = WorkersSerializer.class)
//@JsonDeserialize(contentConverter = WorkerConverter.class)
private List<Worker> workers;
//我是内部类
@Data
public static class Worker implements Serializable {
private static final long serialVersionUID = 1L;
private String deviceId;
//...其他字段略
}
}
以上实体类中,定义了静态内部类:Worker,作为Mechanical的列表泛型参数,通过Jackson序列化后的标识如下:
可以看到,List<Worker>
这个字段,List的标识为"ArrayList",是正确的,但传入的泛型参数(自定义内部类Worker)被序列化成了"LinkedHashMap",因此在通过Jackson进行反序列化时,将会抛出异常:
Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'java.util.LinkedHashMap' as a subtype of [simple type, class org.jeecg.modules.iot.entity.Mechanical$Worker]: Not a subtype ...
问题解决
第一时间我想到的是通过自定义序列/反序列化去解决:
- @JsonSerialize(using = WorkersSerializer.class) //使用自定义的序列化器,无效
- @JsonDeserialize(using = WorkersUnserializer.class) //使用自定义的反序列化器,无效
- @JsonDeserialize(contentConverter = WorkerConverter.class) //使用自定义的反序列化转化器,导致了堆栈内存溢出,原因未知。。
PS:以上注解可以去这里学习:Jackson JSON - Using @JsonSerialize and @JsonDeserialize with Converter for custom conversion
各种方式都尝试了,但是问题仍未解决。。脑壳疼,喝口水冷静一下,重新去思考问题的出现原因:序列化的识别码不同,嗯~ o( ̄▽ ̄)o?
好家伙,继续Google,在参考大量文章后,两个注解吸引了我的注意力:
- @JsonTypeInfo,第一感觉,貌似能描述序列化类型?
- @JsonSubTypes,这个和上面老哥配套的,貌似用于处理多态环境下的序列化
紧接着,光速去啃一下这俩注解原理和使用,这里非常感谢 @MicoCube 的文章:Java Jackson @JsonTypeInfo 多态类型处理 ,快速扫完后,大概有了思路:通过上面的注解去自定义Jackson序列化的类标识符,Now Do it!
修改前面实体类中出现问题的字段,添加以下注解:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,property = "mytype", include=JsonTypeInfo.As.PROPERTY)
@JsonSubTypes({ //设置对应子类的识别码值
@JsonSubTypes.Type(value = LinkedHashMap.class, name = "worker"),
@JsonSubTypes.Type(value = Worker.class, name = "worker")
})
private List<Worker> workers;
通过上面魔法般的操作,让我们现在来看看Jackson序列化的标识符:
怎么样,淘气鬼完全被我们控制住了,标识符类型为我们的"mytype",标识值也成了固定值"worker",这下大功告成~尽情的序列/反序列化吧!
总结
还是尽量避免使用内部类!当然这个坑硬爬完了就算了。。肚子好饿,该吃饭了QAQ