【问题标题】:jackson xml deserialize inline arrayjackson xml反序列化内联数组
【发布时间】: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&lt;String, String&gt;...

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 流 中向后迭代?该方法如何知道何时停止?我不知道。

【问题讨论】:

    标签: java xml arrays jackson deserialization


    【解决方案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)
    猜你喜欢
    • 2022-01-22
    • 2013-08-22
    • 2018-10-26
    • 1970-01-01
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    相关资源
    最近更新 更多