解决:Jackson反序列化Java内部类失败(序列化后的识别码为LinkedHashMap,而非内部类本身)

问题描述

先看实体类:

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序列化后的标识如下:

解决:Jackson反序列化Java内部类失败(序列化后的识别码为LinkedHashMap,而非内部类本身)_第1张图片

可以看到,List 这个字段,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序列化的标识符:

解决:Jackson反序列化Java内部类失败(序列化后的识别码为LinkedHashMap,而非内部类本身)_第2张图片

怎么样,淘气鬼完全被我们控制住了,标识符类型为我们的"mytype",标识值也成了固定值"worker",这下大功告成~尽情的序列/反序列化吧!

总结

还是尽量避免使用内部类!当然这个坑硬爬完了就算了。。肚子好饿,该吃饭了QAQ

你可能感兴趣的:(Java,Jackson,jackson,内部类反序列化,Java,JsonTypeInfo,JsonSubTypes)