2012-11-21 7 views
6

In einem RestFul-Webservice (Jersey) -Kontext muss ich ein Objektdiagramm zu XML und JSON marshalieren/serialisieren. Der Einfachheit halber versuche ich das Problem mit 2-3 Klassen zu erklären:JAXB-serialisiertes XML mit ID-Referenzen statt Containment

Person.java

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Person { 

    private String name; 

    // @XmlIDREF 
    @XmlElement(name = "house") 
    @XmlElementWrapper(name = "houses") 
    private Collection<House> houses; 

    public Person() {} 

    public Person(String name, Collection<House> houses) { 
     this.name = name; 
     this.houses = houses; 
    } 
} 

House.java

@XmlAccessorType(XmlAccessType.FIELD) 
public class House { 

    // @XmlID 
    public String name; 

    public String location; 

    public House() {} 

    public House(String name, String location) { 
     this.name = name; 
     this.location = location; 
    } 
} 

Wenn nun serialisiert ich eine Person, die XML wird so aussehen:

<people> 
    <person> 
     <name>Edward</name> 
     <houses> 
      <house> 
       <name>MyAppartment</name> 
       <location>London</location> 
      </house> 
      <house> 
       <name>MySecondAppartment</name> 
       <location>London</location> 
      </house> 
     </houses> 
    </person> 

    <person> 
     <name>Thomas</name> 
     <houses> 
      <house> 
       <name>MyAppartment</name> 
       <location>London</location> 
      </house> 
      <house> 
       <name>MySecondAppartment</name> 
       <location>London</location> 
      </house> 
     </houses> 
    </person> 
</people> 

Das Problem hier ist, dass die gleichen Häuser mehrfach aufgeführt sind. Nun füge ich die uncommented XmlIDREF und XmlID Annotationen, die in XML ähnlich wie dies zur Folge hätte:

<people> 
    <person> 
     <name>Edward</name> 
     <houses> 
      <house>MyAppartment</house> 
      <house>MySecondAppartment</house> 
     </houses> 
    </person> 

    <person> 
     <name>Thomas</name> 
     <houses> 
      <house>MyAppartment</house> 
      <house>MySecondAppartment</house> 
     </houses> 
    </person> 
</people> 

Während die erste XML zu ausführlich war, das eine Information fehlt.

<people> 
    <person> 
     <name>Edward</name> 
     <houses> 
      <house>MyAppartment</house> 
      <house>MySecondAppartment</house> 
     </houses> 
    </person> 

    <person> 
     <name>Thomas</name> 
     <houses> 
      <house>MyAppartment</house> 
      <house>MySecondAppartment</house> 
     </houses> 
    </person> 

    <houses> 
     <house> 
      <name>MyAppartment</name> 
      <location>London</location> 
     </house> 
     <house> 
      <name>MySecondAppartment</name> 
      <location>London</location> 
     </house> 
    </houses> 
</people> 

Die Lösung sollte generisch sein, weil ich nicht will zusätzliche Klassen für jedes neues Element im Objektgraphen schreiben: Wie kann ich (und Abstellungs) etwas ähnliches erstellen.

Für Vollständigkeit, hier ist der ruhige webservice:

@Path("rest/persons") 
public class TestService { 
    @GET 
    @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_JSON }) 
    public Collection<Person> test() throws Exception { 
     Collection<Person> persons = new ArrayList<Person>(); 
     Collection<House> houses = new HashSet<House>(); 
     houses.add(new House("MyAppartment", "London")); 
     houses.add(new House("MySecondAppartment", "London")); 
     persons.add(new Person("Thomas", houses)); 
     persons.add(new Person("Edward", houses)); 
     return persons; 
    } 
} 

Vielen Dank im Voraus.

+1

mögliche Duplikate von [Kann JAXB marshalen durch Eindämmung zunächst dann Marshal von @XmlIDREF für nachfolgende Referenzen?] (Http://stackoverflow.com/questions/7587095/can-jaxb-marshal-by-containment-at-first -then-marshal-by-xmlidref-for-subsequences) –

+0

Ich könnte ein '' 'XmlAdapter''' schreiben, das eine oberflächliche Instanz eines untergeordneten' '' House''' zurückgibt, die alle Werte enthält oder nur auf das Original verweist Beispiel, ja.Aber es gibt viele Nachteile: (1) Ich müsste für jede Klasse im Objektgraphen Unterklassen schreiben, (2) Ich müsste alle '' @ XmlAttribute'''s im '' Marshal () '' '' und '' 'unmarshal()' '' Methoden und schließlich (3) wird kein XML erzeugt, das die Häuser als Kinder des Wurzelknotens enthält. Es gibt viele Dinge, die ich übernehmen müsste, wenn ich das Modell ändere. Und das alles kann automatisch erledigt werden, da alle Informationen vorhanden sind. – steffen

Antwort

2

Wenn Sie versuchen, in ein Format zu serialisieren, das dem letzten XML-Beispiel entspricht, das Sie angegeben haben, glaube ich, dass Ihr Objektdiagramm falsch strukturiert ist, um das zu erreichen.

Wenn Sie eine Sammlung von Person Objekte mit ihren zugehörigen Häusern und bieten auch eine Sammlung der House Objekte zur Verfügung stellen möchten, dann müssen Sie eine serialisierte XML-Nachricht zurück, die beide Sammlungen enthält. Es scheint, als ob Sie Ihre @XmlIDREF und @XmlID Annotationen an der richtigen Stelle für die Person-House-Assoziation haben, wie Sie beabsichtigen (basierend auf Ihrer Beschreibung), aber Sie nur eine Sammlung der Person Objekte zurückgeben im Gegensatz zu beiden Sammlungen zurückgeben.

Ihre webservice wie folgt aussehen sollte mehr (die Serialisierung Weglassen wie es du bist klar, wie es scheint, zu serialisiert):

@Path("rest/persons") 
public class TestService { 
    @GET 
    @Produces({ MediaType.TEXT_XML, MediaType.APPLICATION_JSON }) 
    public Map<String, Object> test() throws Exception { 
     Map<String, Object> peopleAndHouses = new HashMap<String, Object>(); 
     Collection<Person> persons = new ArrayList<Person>(); 
     Collection<House> houses = new HashSet<House>(); 

     houses.add(new House("MyAppartment", "London")); 
     houses.add(new House("MySecondAppartment", "London")); 
     persons.add(new Person("Thomas", houses)); 
     persons.add(new Person("Edward", houses)); 

     peopleAndHouses.put("houses", houses); 
     peopleAndHouses.put("people", persons); 
     return peopleAndHouses; 
    } 
} 

Es gibt andere Wege, dies zu erreichen (zB ein Wrapper-Objekt erstellen das hat Sammlungsattribute für Leute und Häuser, etc.) aber hoffentlich bekommst du die Idee.

Verwandte Themen