2013-12-19 62 views
2

好啦......我很難把這個包裹起來。我有一個代表XmlTest類型的XML文檔。 XmlTest有一個children類型List<XmlTest>children是一個未包裝的XML集合。當@ JacksonXmlProperty.localName匹配@ JacksonXmlRootElement.localName時,無法反序列化解包列表

的問題是,當我反序列化我的XML源作爲XmlTest例如,它失敗:gist

java.lang.IllegalStateException: Current state not XML_START_ELEMENT (1) but 6 
    at com.fasterxml.jackson.dataformat.xml.deser.XmlTokenStream.repeatStartElement(XmlTokenStream.java:228) 
    at com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser.addVirtualWrapping(FromXmlParser.java:280) 
    at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer._configureParser(WrapperHandlingDeserializer.java:140) 
    at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:108) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:230) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:207) 
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:23) 
    at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:464) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:376) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:977) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:276) 
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121) 
    at com.fasterxml.jackson.dataformat.xml.deser.WrapperHandlingDeserializer.deserialize(WrapperHandlingDeserializer.java:109) 
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888) 
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034) 
    at a.test.utilities.XmlHelpers.fromXml(XmlHelpers.java:19) 
    at a.UnitTest.test(UnitTest.java:22) 

這裏是我使用的XML文檔:gist

<test id="0"> 
    <test id="0.1"> 
     <test id="0.1.1" /> 
    </test> 
    <test id="0.2" /> 
    <test id="0.3"> 
     <test id="0.3.1" /> 
    </test> 
</test> 

這裏是我正在使用的單元測試引起異常:gist

package api.core.jasper; 

import static org.junit.Assert.fail; 

import java.util.List; 

import org.junit.Test; 

import com.fasterxml.jackson.annotation.JsonCreator; 
import com.fasterxml.jackson.annotation.JsonProperty; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.dataformat.xml.XmlMapper; 
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; 
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; 
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; 
import com.google.common.collect.Lists; 

public class UnitTest { 

    @Test 
    public void test() throws Exception { 
    final ObjectMapper mapper = new XmlMapper(); 

    final XmlTest before = 
     new XmlTest("0", Lists.newArrayList(new XmlTest("0.1", null), 
      new XmlTest("0.2", Lists.newArrayList(new XmlTest("0.2.1", null))))); 
    final String xml = mapper.writeValueAsString(before); 
    final XmlTest after = mapper.readValue(xml, XmlTest.class); 

    fail(); 
    } 

    @JacksonXmlRootElement(localName = "test") 
    public static class XmlTest { 
    private final String id; 
    private final List<XmlTest> children; 

    @JsonCreator 
    public XmlTest(@JsonProperty("id") final String id, @JsonProperty("tests") final List<XmlTest> children) { 
     this.id = id; 
     this.children = children; 
    } 

    @JsonProperty("id") 
    @JacksonXmlProperty(localName = "id", isAttribute = true) 
    public String id() { 
     return id; 
    } 

    @JsonProperty("children") 
    @JacksonXmlElementWrapper(useWrapping = false) 
    @JacksonXmlProperty(localName = "test") 
    public List<XmlTest> children() { 
     return children; 
    } 
    } 

} 

如何將此XML文檔反序列化爲XmlTest實例?

編輯1

我發現,在XML文檔中更改根元素的名稱將導致成功的反序列化。這是一個有趣的行爲,但對我來說不是一種選擇,我不控制應用程序中文檔的構建。

這將反序列化預期:gist如果你寫一個自定義解串器

<root id="0"> 
    <test id="0.1"> 
     <test id="0.1.1" /> 
    </test> 
    <test id="0.2" /> 
    <test id="0.3"> 
     <test id="0.3.1" /> 
    </test> 
</root> 
+1

我試着與你的示例代碼玩。它看起來像一個傑克遜數據格式xml中的錯誤。 –

+0

@EugeneEvdokimov,我同意我今天提交了這個bug https://github.com/FasterXML/jackson-dataformat-xml/issues/86 –

回答

3

作品。

package api.core.jasper; 

import java.io.IOException; 
import java.util.List; 

import org.junit.Test; 

import com.fasterxml.jackson.core.JsonParser; 
import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.core.JsonToken; 
import com.fasterxml.jackson.databind.DeserializationContext; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 
import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 
import com.fasterxml.jackson.dataformat.xml.XmlMapper; 
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; 
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; 
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; 
import com.google.common.base.Objects; 
import com.google.common.base.Optional; 
import com.google.common.collect.Lists; 

public class UnitTest { 

    @Test 
    public void test() throws Exception { 
    final ObjectMapper mapper = new XmlMapper(); 

    final XmlTest before = 
     new XmlTest("0", Lists.newArrayList(new XmlTest("0.1", null), 
      new XmlTest("0.2", Lists.newArrayList(new XmlTest("0.2.1", null))))); 
    System.out.println(before); 
    final String xml = mapper.writeValueAsString(before); 
    System.out.println(xml); 
    final XmlTest after = mapper.readValue(xml, XmlTest.class); 
    System.out.println(after); 
    } 

    @JsonDeserialize(using = XmlTestDeserializer.class) 
    @JacksonXmlRootElement(localName = "test") 
    public static class XmlTest { 
    @JacksonXmlProperty(localName = "id", isAttribute = true) 
    public String id; 

    @JacksonXmlElementWrapper(useWrapping = false) 
    @JacksonXmlProperty(localName = "test") 
    public List<XmlTest> children; 

    public XmlTest(final String id, final List<XmlTest> children) { 
     this.id = id; 
     this.children = Optional.fromNullable(children).or(Lists.<XmlTest>newArrayList()); 
    } 

    @Override 
    public String toString() { 
     return Objects.toStringHelper(this) 
      .add("id", id) 
      .add("children", children) 
      .toString(); 
    } 
    } 

    public static class XmlTestDeserializer extends StdDeserializer<XmlTest> { 

    protected XmlTestDeserializer() { 
     super(XmlTest.class); 
    } 

    @Override 
    public XmlTest deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException, 
     JsonProcessingException { 
     if (jp.getCurrentToken() != JsonToken.START_OBJECT) { 
     throw new IOException("Invalid token, expected START_OBJECT"); 
     } 

     String id = null; 
     final List<XmlTest> children = Lists.newArrayList(); 

     while (jp.nextToken() != JsonToken.END_OBJECT) { 
     final String key = jp.getCurrentName(); 
     jp.nextToken(); 

     if ("id".equals(key)) { 
      id = jp.readValueAs(String.class); 
     } else if ("test".equals(key)) { 
      final XmlTest child = jp.readValueAs(XmlTest.class); 
      if (child != null) { 
      children.add(child); 
      } 
     } 
     } 

     jp.close(); 

     return new XmlTest(id, children); 
    } 
    } 
} 

測試控制檯輸出:

XmlTest{id=0, children=[XmlTest{id=0.1, children=[]}, XmlTest{id=0.2, children=[XmlTest{id=0.2.1, children=[]}]}]} 
<test id="0"><test id="0.1"/><test id="0.2"><test id="0.2.1"/></test></test> 
XmlTest{id=0, children=[XmlTest{id=0.1, children=[]}, XmlTest{id=0.2, children=[XmlTest{id=0.2.1, children=[]}]}]} 
+1

你已經做得很好了 –