我搜索过并搜索过,但没有找到答案/解决方案,所以我自己就这样问了。
使用fasterxml jackson 2.8.7
我有一个复杂的地图,我传递给angular并通过Spring映射作为JSON字符串返回。
地图:
Map<String, List<TableModel>> tableEntryData = new LinkedHashMap<>();
它是TableModel列表的Map。表模型是一个接口,它扩展到几个具体的类中。因此,使用TableModel作为对象类型允许我将从TableModel扩展的任何具体类放入List中。
我可以使用:
将其传递给棱角分明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中[&#34; Table_A_List&#34;] - &GT; java.util.LinkedList中[8])
现在我的数据Map(tableEntryData)包含如下数据:
Map = { [Table_A_List] = {TableA的13个对象的LinkedList}, [Table_B_List] = {TableB的2个对象的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
{
....
}
表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
}
表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
}
然后我也创建了一个反序列化器类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);
}
}
现在虽然这个婴儿有点工作,但是有一个问题。反序列化器将第二个映射条目读取为作为第一个映射条目一部分的List。发生的事情是,反序列化器似乎一次从TABLE_A_List JSON读取两条记录,结果在第7条目中包含TABLE_B_List:
{
"TABLE_B_List" : [ {
"deserializeType" : "TableB",
"code" : 9,
}, {
"deserializeType" : "TableB",
"code" : 1,
}, ]
}
TABLE_A_List中共有13个条目。
所以有人可以指出我如何正确地做到这一点。我想我需要更好地配置解串器或其他问题。
是的我总是可以回去摆脱TableModel方法并使用更好的东西,但这不是重点。此时需要进行太多的代码更改。我需要正确地完成这项工作。
答案 0 :(得分:0)
几分钟后找到了解决方案,尽管我的大脑已经失去了2天。
使用:
return mapper.readValue(root.toString(), instanceClass);
而不是:
return mapper.readValue(jp, instanceClass);
readValue
上的 JsonParser
最终会增加根节点。这是一个逻辑错误+缺乏血腥指南。
感谢大家的回答! :*