2016-03-22 10 views
4

Ich versuche, ein Paar unveränderlich POJOs erstellen Serialisierung und Deserialisierung von XML zu behandeln, die wie folgt aussieht:kann nicht gewickelte Liste mit Jackson XmlMapper deserialisieren

<?xml version="1.0" encoding="UTF-8"?> 
<Outer xmlns="http://example.com"> 
    <Foo>outer foo</Foo> 
    <Inners> 
    <Inner> 
     <Bar>inner 1 bar</Bar> 
     <Baz>inner 2 baz</Baz> 
    </Inner> 
    <Inner> 
     <Bar>inner 2 bar</Bar> 
     <Baz>inner 2 baz</Baz> 
    </Inner> 
    </Inners> 
</Outer> 

Ich muß serialisiert werden können, und deserialisieren sowohl eine Outer, die eine Liste von Inner s enthält, als auch eine Inner für sich.

Ich kann einen Serializer dafür schaffen ohne Probleme, aber meine Deserializer schlägt mit der Ausnahme com.fasterxml.jackson.databind.JsonMappingException: Duplicate property 'Inners' for [simple type, class BrokenTest$Outer]

Hier werden die Unit-Tests für die Weitergabe der Serialisierung und andernfalls Deserialisierung:

import com.fasterxml.jackson.annotation.JsonCreator; 
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 org.testng.annotations.Test; 

import java.util.Arrays; 
import java.util.List; 

import static org.testng.Assert.assertEquals; 
import static org.testng.Assert.assertNotNull; 

public class BrokenTest 
{ 
    private static final String NAMESPACE = "http://example.com"; 

    @JacksonXmlRootElement(localName="Outer", namespace = NAMESPACE) 
    public static class Outer 
    { 
     @JacksonXmlProperty(localName="Foo", namespace = NAMESPACE) 
     public final String foo; 

     @JacksonXmlProperty(localName="Inner", namespace = NAMESPACE) 
     @JacksonXmlElementWrapper(localName = "Inners", namespace = NAMESPACE) 
     public final List<Inner> inners; 

     @JsonCreator 
     public Outer(
       @JacksonXmlProperty(localName="Foo", namespace = NAMESPACE) final String foo, 
       @JacksonXmlProperty(localName="Inners", namespace = NAMESPACE) final List<Inner> inners) 
     { 
      this.foo = foo; 
      this.inners = inners; 
     } 
    } 

    @JacksonXmlRootElement(localName="Inner", namespace = NAMESPACE) 
    public static class Inner 
    { 
     @JacksonXmlProperty(localName="Bar", namespace = NAMESPACE) 
     public final String bar; 

     @JacksonXmlProperty(localName="Baz", namespace = NAMESPACE) 
     public final String baz; 

     @JsonCreator 
     public Inner(
       @JacksonXmlProperty(localName="Bar", namespace = NAMESPACE) final String bar, 
       @JacksonXmlProperty(localName="Baz", namespace = NAMESPACE) final String baz) 
     { 
      this.bar = bar; 
      this.baz = baz; 
     } 
    } 

    @Test 
    public void serializeInner() throws Exception 
    { 
     Inner inner = new Inner("inner bar", "inner baz"); 
     ObjectMapper mapper = new XmlMapper(); 
     String serialized = mapper.writeValueAsString(inner); 
     assertEquals(serialized, "<Inner xmlns=\"http://example.com\"><Bar>inner bar</Bar><Baz>inner baz</Baz></Inner>"); 
    } 

    @Test 
    public void deserializeInner() throws Exception 
    { 
     String serialized = "<Inner xmlns=\"http://example.com\"><Bar>inner bar</Bar><Baz>inner baz</Baz></Inner>"; 
     ObjectMapper mapper = new XmlMapper(); 
     Inner inner = mapper.readValue(serialized, Inner.class); 
     assertNotNull(inner); 
     assertEquals("inner bar", inner.bar); 
     assertEquals("inner baz", inner.baz); 
    } 

    @Test 
    public void serializeOuter() throws Exception 
    { 
     Outer outer = new Outer("outer foo", Arrays.asList(new Inner("inner 1 bar", "inner 1 baz"), new Inner("inner 2 bar", "inner 2 baz"))); 
     ObjectMapper mapper = new XmlMapper(); 
     String serialized = mapper.writeValueAsString(outer); 
     assertEquals(serialized, "<Outer xmlns=\"http://example.com\"><Foo>outer foo</Foo><Inners><Inner><Bar>inner 1 bar</Bar><Baz>inner 1 baz</Baz></Inner><Inner><Bar>inner 2 bar</Bar><Baz>inner 2 baz</Baz></Inner></Inners></Outer>"); 
    } 

    @Test 
    public void deserializeOuter() throws Exception 
    { 
     String serialized = "<Outer xmlns=\"http://example.com\"><Foo>outer foo</Foo><Inners><Inner><Bar>inner 1 bar</Bar><Baz>inner 1 baz</Baz></Inner><Inner><Bar>inner 2 bar</Bar><Baz>inner 2 baz</Baz></Inner></Inners></Outer>"; 
     ObjectMapper mapper = new XmlMapper(); 
     Outer outer = mapper.readValue(serialized, Outer.class); // fails 
     assertNotNull(outer); 
     assertEquals("outer foo", outer.foo); 
     assertEquals(2, outer.inners.size()); 
     assertEquals("inner 1 bar", outer.inners.get(0).bar); 
     assertEquals("inner 1 baz", outer.inners.get(0).baz); 
     assertEquals("inner 2 bar", outer.inners.get(1).bar); 
     assertEquals("inner 2 baz", outer.inners.get(1).baz); 
    } 
} 

Ich kann erhalten eine andere Ausnahme (com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "Inners" (class BrokenTest$Outer), not marked as ignorable (2 known properties: "Foo", "Inner"])), wenn ich die @JacksonXmlProperty Annotation auf Outer Konstruktor ändern, um die localName "Inner" anstelle von "Inneres" zu verwenden.

Gibt es eine Möglichkeit, ein Paar POJOs zu erstellen, die für diese vier Testfälle funktionieren?

bearbeitet: Dies ist mit Jackson Version 2.7.3

+0

traurig über die offensichtlich falsche Antwort, ich war zu viel Aufmerksamkeit auf JUnit „tatsächliche Ergebnis“ zu bezahlen, die in Ihren Tests ist die „erwartete Ergebnis ". Ich werde die Antwort löschen. – nyname00

+2

Eine seltsame Sache, die ich fand, war, dass, wenn Sie die Annotation auf "Inners" im "Outer" -Konstruktor in '@JacksonXmlProperty (localName =" XXX ", Namespace = NAMESPACE) final List Inners ändern, alle Tests bestanden. Aber du solltest das nochmal überprüfen;) – nyname00

+0

Du hast Recht, es funktioniert. Das ist sehr seltsam. Bitte mach das zur Antwort, damit ich es annehmen kann. –

Antwort

1

Dies ist ein known bug in Jackson XML Handling.

Eine Umgehung ist die Annotation auf inners im Outer Konstruktor ändern, so dass der lokale Name etwas nicht im XML-Dokument ist. Hier

ist eine Version der Unit-Tests, die funktioniert:

import com.fasterxml.jackson.annotation.JsonCreator; 
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 org.testng.annotations.Test; 

import java.util.Arrays; 
import java.util.List; 

import static org.testng.Assert.assertEquals; 
import static org.testng.Assert.assertNotNull; 

public class BrokenTest 
{ 
    private static final String NAMESPACE = "http://example.com"; 

    @JacksonXmlRootElement(localName="Outer", namespace = NAMESPACE) 
    public static class Outer 
    { 
     @JacksonXmlProperty(localName="Foo", namespace = NAMESPACE) 
     public final String foo; 

     @JacksonXmlProperty(localName="Inner", namespace = NAMESPACE) 
     @JacksonXmlElementWrapper(localName = "Inners", namespace = NAMESPACE) 
     public final List<Inner> inners; 

     @JsonCreator 
     public Outer(
       @JacksonXmlProperty(localName="Foo", namespace = NAMESPACE) final String foo, 
       @JacksonXmlProperty(localName="XXX", namespace = NAMESPACE) final List<Inner> inners) 
     { 
      this.foo = foo; 
      this.inners = inners; 
     } 
    } 

    @JacksonXmlRootElement(localName="Inner", namespace = NAMESPACE) 
    public static class Inner 
    { 
     @JacksonXmlProperty(localName="Bar", namespace = NAMESPACE) 
     public final String bar; 

     @JacksonXmlProperty(localName="Baz", namespace = NAMESPACE) 
     public final String baz; 

     @JsonCreator 
     public Inner(
       @JacksonXmlProperty(localName="Bar", namespace = NAMESPACE) final String bar, 
       @JacksonXmlProperty(localName="Baz", namespace = NAMESPACE) final String baz) 
     { 
      this.bar = bar; 
      this.baz = baz; 
     } 
    } 

    @Test 
    public void serializeInner() throws Exception 
    { 
     Inner inner = new Inner("inner bar", "inner baz"); 
     ObjectMapper mapper = new XmlMapper(); 
     String serialized = mapper.writeValueAsString(inner); 
     assertEquals(serialized, "<Inner xmlns=\"http://example.com\"><Bar>inner bar</Bar><Baz>inner baz</Baz></Inner>"); 
    } 

    @Test 
    public void deserializeInner() throws Exception 
    { 
     String serialized = "<Inner xmlns=\"http://example.com\"><Bar>inner bar</Bar><Baz>inner baz</Baz></Inner>"; 
     ObjectMapper mapper = new XmlMapper(); 
     Inner inner = mapper.readValue(serialized, Inner.class); 
     assertNotNull(inner); 
     assertEquals("inner bar", inner.bar); 
     assertEquals("inner baz", inner.baz); 
    } 

    @Test 
    public void serializeOuter() throws Exception 
    { 
     Outer outer = new Outer("outer foo", Arrays.asList(new Inner("inner 1 bar", "inner 1 baz"), new Inner("inner 2 bar", "inner 2 baz"))); 
     ObjectMapper mapper = new XmlMapper(); 
     String serialized = mapper.writeValueAsString(outer); 
     assertEquals(serialized, "<Outer xmlns=\"http://example.com\"><Foo>outer foo</Foo><Inners><Inner><Bar>inner 1 bar</Bar><Baz>inner 1 baz</Baz></Inner><Inner><Bar>inner 2 bar</Bar><Baz>inner 2 baz</Baz></Inner></Inners></Outer>"); 
    } 

    @Test 
    public void deserializeOuter() throws Exception 
    { 
     String serialized = "<Outer xmlns=\"http://example.com\"><Foo>outer foo</Foo><Inners><Inner><Bar>inner 1 bar</Bar><Baz>inner 1 baz</Baz></Inner><Inner><Bar>inner 2 bar</Bar><Baz>inner 2 baz</Baz></Inner></Inners></Outer>"; 
     ObjectMapper mapper = new XmlMapper(); 
     Outer outer = mapper.readValue(serialized, Outer.class); // fails 
     assertNotNull(outer); 
     assertEquals("outer foo", outer.foo); 
     assertEquals(2, outer.inners.size()); 
     assertEquals("inner 1 bar", outer.inners.get(0).bar); 
     assertEquals("inner 1 baz", outer.inners.get(0).baz); 
     assertEquals("inner 2 bar", outer.inners.get(1).bar); 
     assertEquals("inner 2 baz", outer.inners.get(1).baz); 
    } 
} 
Verwandte Themen