我使用Jackson将应用程序的模型序列化/反序列化为JSON和XML(需要两者都有)。
模型类:
@JacksonXmlRootElement
public class Data {
@JsonProperty("attributes")
@JsonDeserialize(using = AttributesDeserializer.class)
@JsonSerialize(using = AttributesSerializer.class)
@JacksonXmlElementWrapper
private Map<Key, Map<String, Attribute>> attributes;
....
public class Key {
private Integer id;
private String name;
....
public class Attribute {
private Integer id;
private Integer value;
private String name;
我需要我的JSON看起来像这样:
{
"attributes": [
{
"key": {
"id": 10,
"name": "key1"
},
"value": {
"numeric": {
"id": 1,
"value": 100,
"name": "numericAttribute"
},
"text": {
"id": 2,
"value": 200,
"name": "textAttribute"
}
}
},
{
"key": {
"id": 20,
"name": "key2"
},
"value": {
"numeric": {
"id": 1,
"value": 100,
"name": "numericAttribute"
},
"text": {
"id": 2,
"value": 200,
"name": "textAttribute"
}
}
}
]
}
我的XML文件看起来像这样:
<Data>
<attributes>
<key>
<id>10</id>
<name>key1</name>
</key>
<value>
<numeric>
<id>1</id>
<value>100</value>
<name>numericAttribute</name>
</numeric>
<text>
<id>2</id>
<value>200</value>
<name>textAttribute</name>
</text>
</value>
<key>
<id>20</id>
<name>key2</name>
</key>
<value>
<numeric>
<id>1</id>
<value>100</value>
<name>numericAttribute</name>
</numeric>
<text>
<id>2</id>
<value>200</value>
<name>textAttribute</name>
</text>
</value>
</attributes>
</Data>
我使用自定义序列化程序获取所需的JSON和XML数据:
public class AttributesSerializer extends JsonSerializer<Map<Key, Map<String, Attribute>>> {
@Override
public void serialize(Map<Key, Map<String, Attribute>> map, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
jsonGenerator.writeStartArray();
for (Map.Entry<Key, Map<String, Attribute>> entry : map.entrySet()) {
jsonGenerator.writeStartObject();
jsonGenerator.writeObjectField("key", entry.getKey());
jsonGenerator.writeObjectFieldStart("value");
for (Map.Entry<String, Attribute> attributesEntry : entry.getValue().entrySet()) {
jsonGenerator.writeObjectField(attributesEntry.getKey(), attributesEntry.getValue());
}
jsonGenerator.writeEndObject();
jsonGenerator.writeEndObject();
}
jsonGenerator.writeEndArray();
}
}
对于使用自定义反序列化器的JSON,反序列化工作正常:
public class AttributesDeserializer extends JsonDeserializer<Map<Key, Map<String, Attribute>>> {
@Override
public Map<Key, Map<String, Attribute>> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
if (node.size() == 0) {
return null;
}
ObjectMapper om = new ObjectMapper();
Map<Key, Map<String, Attribute>> attributes = new HashMap<>();
node.forEach(jsonNode -> {
Map<String, Attribute> attributesMap = new HashMap<>();
JsonNode keyNode = jsonNode.get("key");
Key key = om.convertValue(keyNode, Key.class);
JsonNode valueNode = jsonNode.get("value");
Iterator<Map.Entry<String, JsonNode>> attributesIterator = valueNode.fields();
while(attributesIterator.hasNext()) {
Map.Entry<String, JsonNode> field = attributesIterator.next();
Attribute attribute = om.convertValue(field.getValue(), Attribute.class);
attributesMap.put(field.getKey(), attribute);
}
attributes.put(key, attributesMap);
});
return attributes;
}
}
虽然 JSON 没有问题,但是在反序列化 XML 时应用程序崩溃:
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: ro.alexsvecencu.jackson.Data["attributes"])
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388)
at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1599)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:278)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2740)
at ro.alexsvecencu.jackson.Main.main(Main.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.NullPointerException
at ro.alexsvecencu.jackson.AttributesDeserializer.lambda$deserialize$0(AttributesDeserializer.java:29)
at ro.alexsvecencu.jackson.AttributesDeserializer$$Lambda$1/1709366259.accept(Unknown Source)
at java.lang.Iterable.forEach(Iterable.java:75)
at ro.alexsvecencu.jackson.AttributesDeserializer.deserialize(AttributesDeserializer.java:24)
at ro.alexsvecencu.jackson.AttributesDeserializer.deserialize(AttributesDeserializer.java:15)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
... 9 more
发生的情况是,我的自定义反序列化器在处理XML时崩溃了,因为很明显它没有将所有属性解释为“数组”,当我遍历jsonNode的子项时,它将迭代键/值。此外,通过调试,我注意到反序列化器仅针对XML中最后一个标记的属性进行调用。
有没有办法告诉Jackson使用特定的自定义反序列化器/序列化器,以使其在XML和JSON之间有所不同?这是我认为可以解决问题的一种方式。
我的XML可能格式有点不同(我在形式上并不受限制,但JSON必须保持该格式)。在这种灵活性下,您是否看到任何解决我的问题的替代方法?我可以使用JAXB等其他工具来处理XML,但我基本上只能使用Jackson来处理两者。