Jackson Fastxml映射器 - 接口/抽象对象类型列表列表的序列化/挑选图



我已经搜索和搜索过,但没有找到答案/解决方案,因此诉诸于自己问这个。

使用fastxml杰克逊2.8.7

我有一个复杂的地图,我将其传递给Angular并通过弹簧映射作为JSON字符串返回。

地图:

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

它是tablemodel列表的地图。表模型是接口,它扩展到几个具体类。因此,使用tablemodel作为对象类型使我可以将从tablememodel扩展到列表的任何具体类。

我可以使用:

将其传递给角罚
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
tableEntryJSON = mapper.writeValueAsString( tableEntryData );

但是,当我试图对json进行估算时:

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

我面临这个例外:

com.fasterxml.jackson.databind.jsonmappingexception :( java.lang.nullpointerexception)(通过参考链: java.util.linkedhashmap [" table_a_list"] -> java.util.linkedlist [8])

现在我的数据映射(TableenTryData)包含这样的数据:

map = { [table_a_list] = {linkedlist of tablea}的13个对象, [table_b_list] = {tableb的两个对象的linkedlist} }

table_a_list和table_b_list是地图键。Tablea和Tabelb是实现接口tablemodel的类。

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,   },  ] }

看起来正确。

为了正确地从接口中挑选混凝土类,我已经定义了如下的内容

tablemodel:

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

tablea:

@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:

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

然后,我还创建了一个Deserializer类ModelInstanceNcencedEserializer:

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

现在,当这个婴儿有些工作时,有一个问题。Deserializer读取第二映射条目是第一个地图条目的一部分列表。发生的事情是,求职者似乎一次从table_a_list json读取两个记录,结果最终包括第7个条目的table_b_list:

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

table_a_list中有13个条目。

,任何人都可以指出我如何正确执行此操作。我认为我需要更好地配置求职者或其他问题。

是的,我总是可以回去摆脱Tablemodel方法,使用更好的东西,但这不是重点。此时,这将需要太多的代码更改。我需要正确地做这项工作。

几分钟后发现了解决方案,尽管我的大脑失去了2天。

使用:

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

而不是:

return mapper.readValue(jp, instanceClass);

JsonParser上的readValue最终会增加根节点。这是一个合乎逻辑的错误 缺乏血腥指南。

感谢大家的回答!:*

相关内容

  • 没有找到相关文章

最新更新