简体   繁体   English

Jackson fastxml映射器-接口/抽象对象类型列表的序列化/反序列化映射

[英]Jackson fasterxml mapper - serialize/deserialize map of list of interface/abstract object type

I have searched and searched but found no answer/solution so am resorting to asking this myself. 我进行了搜索,但没有找到答案/解决方案,所以我自己问这个问题。

Using fasterxml jackson 2.8.7 使用fasterxml jackson 2.8.7

I have a complex map that I pass to angular and get back via a Spring mapping as a JSON string. 我有一个复杂的地图,该地图传递给angular并通过Spring映射作为JSON字符串返回。

Map: 地图:

Map<String, List<TableModel>> tableEntryData = new LinkedHashMap<>();

It is a Map of List of TableModel. 它是TableModel列表的映射。 Table model is an interface that extends into several concrete classes. 表模型是一个扩展为几个具体类的接口 So using TableModel as the object type allows me to put whatever concrete class extended from TableModel into the List. 因此,使用TableModel作为对象类型可以使我将从TableModel扩展的任何具体类都放入List中。

I can pass this to angular fine using: 我可以使用以下方法将其传递给角度罚款:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
tableEntryJSON = mapper.writeValueAsString( tableEntryData );

But when I try to deserialize the JSON: 但是当我尝试反序列化JSON时:

tableEntryData = mapper.readValue(tableEntryJSON, new TypeReference<LinkedHashMap<String, LinkedList<TableModel>>>() {} );

I am facing this exception: 我面临这个例外:

com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.LinkedHashMap["Table_A_List"]->java.util.LinkedList[8]) com.fasterxml.jackson.databind.JsonMappingException :(是java.lang.NullPointerException)(通过参考链:java.util.LinkedHashMap [“ Table_A_List”]-> java.util.LinkedList [8])

Now my data Map (tableEntryData) contains data like this: 现在我的数据映射(tableEntryData)包含如下数据:

Map = { [Table_A_List] = {LinkedList of 13 objects of TableA}, [Table_B_List] = {LinkedList of 2 objects of TableB} } 映射= {[Table_A_List] = {TableA的13个对象的LinkedList},[Table_B_List] = {TableB的2个对象的LinkedList}}

Where Table_A_List and Table_B_List are map keys. 其中Table_A_List和Table_B_List是映射键。 TableA and TabelB are classes that implement interface TableModel. TableA和TabelB是实现接口TableModel的类。

The JSON created is like this: 创建的JSON如下所示:

{   "TABLE_A_List" : [ {
    "deserializeType" : "TableA",
    "amount" : 0.0,   }, {
    "deserializeType" : "TableA",
    "amount" : 8.3,   }, {
    "deserializeType" : "TableA",
    "amount" : 20.0,   }, {
    "deserializeType" : "TableA",
    "amount" : 19.4,   }, {
    "deserializeType" : "TableA",
    "amount" : 33.9,   }, {
    "deserializeType" : "TableA",
    "amount" : 11.3,   }, {
    "deserializeType" : "TableA",
    "amount" : 23.6,   },{
    "deserializeType" : "TableA",
    "amount" : 2.6,   },{
    "deserializeType" : "TableA",
    "amount" : 3.6,   },{
    "deserializeType" : "TableA",
    "amount" : 23.0,   },{
    "deserializeType" : "TableA",
    "amount" : 230.6,   },{
    "deserializeType" : "TableA",
    "amount" : 23.8,   },{
    "deserializeType" : "TableA",
    "amount" : 11.1,   }, ],
"TABLE_B_List" : [ {
    "deserializeType" : "TableB",
    "code" : 9,   }, {
    "deserializeType" : "TableB",
    "code" : 1,   },  ] }

which seems correct. 这似乎是正确的。

In order to correctly deserialize concrete classes from the interface, I have defined things as follows 为了从接口正确反序列化具体类,我定义了以下内容

TableModel: TableModel的:

@JsonDeserialize(using = ModelInstanceDeserializer.class) @JsonIgnoreProperties(ignoreUnknown = true) public interface TableModel { .... }

TableA: 表A:

@JsonDeserialize(as = TableA.class)
@JsonIgnoreProperties(ignoreUnknown = true)
public class TableA implements Serializable 
{
    String deserializeType = "TableA"; //This is for providing type info that helps with the deserialization since JSON mapper erases type info inside Maps/Lists

//public getters for fields
}

TableB: 表B:

@JsonDeserialize(as = TableB.class)
@JsonIgnoreProperties(ignoreUnknown = true)
public class TableB implements Serializable 
{
    String deserializeType = "TableB"; //This is for providing type info that helps with the deserialization since JSON mapper erases type info inside Maps/Lists

//public getters for fields
}

Then I created a deserializer class ModelInstanceDeserializer as well: 然后,我还创建了一个反序列化器类ModelInstanceDeserializer:

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class ModelInstanceDeserializer extends JsonDeserializer<TableModel> {
    @Override
    public TableModel deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        ObjectNode root = (ObjectNode) mapper.readTree(jp);
        Class<? extends TableModel> instanceClass = null;

        String type = "";
        if (root.has("deserializeType")) {
            type = root.get("deserializeType").asText();
        }

        if (type.equals("TableA")) {
            instanceClass = TableA.class;
        } else if (type.equals("TableA")) {
            instanceClass = TableB.class;
        }
        if (instanceClass == null) {
            return null;
        }
        return mapper.readValue(jp, instanceClass);
    }
}

Now while this baby works somewhat, there is a problem. 现在,虽然这个婴儿有些起作用,但是有一个问题。 The deserializer reads the second map entry as a List that is part of the first map entry. 解串器将第二个映射条目读取为一个列表,该列表是第一个映射条目的一部分。 What is happening is that the deserializer seems to read two records at a time from the TABLE_A_List JSON and as a result ends up including TABLE_B_List on the 7th entry: 发生的情况是,解串器似乎一次从TABLE_A_List JSON读取了两个记录,结果最终在第7个条目上包括TABLE_B_List:

{
  "TABLE_B_List" : [ {
    "deserializeType" : "TableB",
    "code" : 9,
  }, {
    "deserializeType" : "TableB",
    "code" : 1,
  },  ]
}

There are 13 total entries in TABLE_A_List. TABLE_A_List中共有13个条目。

So can anybody point me on how to do this correctly. 因此,任何人都可以指出我如何正确执行此操作。 I think I need to configure the deserializer better or something else is the issue. 我想我需要更好地配置解串器,否则问题就出在其他地方。

Yes I can always go back and get rid of the TableModel approach and use something better but that is not the point. 是的,我总是可以回过头来摆脱TableModel方法,并使用更好的方法,但这不是重点。 It would require too much code change at this point. 此时将需要太多代码更改。 I need to make this work correctly. 我需要使这项工作正确。

Found the solution a few minutes later despite having lost my brains over this for 2 days. 几分钟后找到解决方案,尽管在这两天内我全神贯注。

Use: 采用:

return mapper.readValue(root.toString(), instanceClass);

Instead of: 代替:

return mapper.readValue(jp, instanceClass);

readValue on JsonParser ends up incrementing the root node. JsonParser上的readValue最终使根节点增加。 It was a logical error + lack of bloody guides. 这是一个逻辑错误+缺乏流血的指导。

Thanks everyone for your answers! 谢谢大家的回答! :* :*

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM