jackson xml反序列化内联数组
Posted
技术标签:
【中文标题】jackson xml反序列化内联数组【英文标题】:jackson xml deserialize inline array 【发布时间】:2012-10-22 05:00:00 【问题描述】:如何反序列化这种奇怪的 XML。在我看来,道具实体缺失(围绕道具),但我无法更改此 XML 的来源(网络服务)。
<parents>
<parent name="first">
<description><![CDATA[Description for the first-Entity]]></description>
<prop name="level">
<value><![CDATA[1]]></value>
</prop>
<prop name="enabled">
<value><![CDATA[true]]></value>
</prop>
<prop name="version">
<value><![CDATA[1.0-beta3]]></value>
</prop>
</parent>
<parent name="second">...</parent>
...
</parents>
我的实体是
public class Test
@Test
public void deserializerTest() throws JsonParseException, JsonMappingException, IOException
ObjectMapper om = new XmlMapper();
List<Parent> xml = om.readValue(new File("./test.xml"),
new TypeReference<List<Parent>>() );
public class Prop
@JacksonXmlProperty(isAttribute = true)
public String name;
@JacksonXmlText
public String value;
@JacksonXmlRootElement
public class Parent
@JacksonXmlProperty(isAttribute = true)
public String name;
public String description;
// 1. alternative with List
public List<Prop> prop;
// 2. alternative with Map
@JsonDeserialize(using = PropDeser.class)
public Map<String, String> prop;
public static class PropDeser extends JsonDeserializer<Map<String, String>>
@Override
public Map<String, String> deserialize(JsonParser jp,
DeserializationContext ctxt) throws IOException,
JsonProcessingException
Map<String, String> ret = new HashMap<String, String>();
boolean eof = false;
while (jp.hasCurrentToken())
JsonToken t = jp.getCurrentToken();
switch (t)
case END_OBJECT:
if (eof)
return ret;
eof = true;
break;
case VALUE_STRING:
ret.put(jp.getCurrentName(), jp.getText());
break;
default:
eof = false;
break;
jp.nextValue();
return null;
1。替代
创建一个异常'Cannot instance value of type [simple type, class my.test.Prop] from JSON String;没有单字符串构造函数/工厂方法(通过引用链:my.test.Parent["prop"])'
我不想要一个简单的字符串列表。我需要两者:名称和价值。所以我想到了通过创建自己的反序列化器来使用Map<String, String>
...
2。替代
错误似乎是方法 PropDeser.deserialize() 消耗了父级的结束标记。
java.lang.NullPointerException
at com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.find(BeanPropertyMap.java:160)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:112)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:226)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:203)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2575)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1766)
at my.test.Test.deserializerTest(Test.java:57)
是否有可能在 XML 流 中向后迭代?该方法如何知道何时停止?我不知道。
【问题讨论】:
【参考方案1】:应该可以使用 Jackson XML 模块 2.1 处理“未包装”样式的列表元素,@JacksonXmlElementWrapper(useWrapping=false)
。
结构应该是这样的:
@JacksonXmlRootElement(localName="parents")
public class Parents
@JacksonXmlElementWrapper(useWrapping=false)
public List<Parent> parent;
public class Parent
@JacksonXmlProperty(isAttribute=true)
public String name;
public String description;
@JacksonXmlElementWrapper(useWrapping=false)
public List<Prop> prop;
public class Prop
@JacksonXmlProperty(isAttribute=true)
public String name;
public String value;
所以你的解决方案非常接近。
请注意,如果使用内部类,它们需要在声明中包含“静态”。 我用 2.1.4 对此进行了测试,它对我有用。
【讨论】:
是否可以在映射器上将 useWrapping=false 设置为默认值,这样我们就不需要使用设置注释每个(第 3 方)对象? 是的,有这样的设置;在JacksonXmlModule
中有方法setDefaultUseWrapper
。
例如:val xmlModule = JacksonXmlModule() xmlModule.setDefaultUseWrapper(false) val xmlMapper = XmlMapper(xmlModule)以上是关于jackson xml反序列化内联数组的主要内容,如果未能解决你的问题,请参考以下文章
Jackson XML - 使用命名空间前缀反序列化 XML
Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素