2011-01-14 2 views
3

ich XStream bin mit einer Datei wie folgt strukturiert laden:Kann XStream so konfiguriert werden, dass es bidirektionale Referenzen (Eltern/Kind) hat?

<parent> 
    <child/> 
    <child/> 
</parent> 

wie diese in einer Klasse:

public class Parent(){ 
private List<Child> children; 
} 

public class Child { 
private Parent parent; 
} 

Ich mag würde dies in der Lage sein zu tun: parent.getChildren().get(0).getParent()

Ich möchte in der Lage sein, das XML so zu verwenden, wie es sitzt. Ich weiß, dass ich Verweise auf den Elternteil unter Kindern hinzufügen kann, aber das scheint sehr überflüssig. Ich kenne den Elternteil des Kindes wegen seiner XML-Struktur.

Unterstützt XStream dies?

Antwort

3

Ja Xstream unterstützt Backlinks, um zirkuläre Referenzen zu vermeiden. Es tut dies standardmäßig, aber es ist fraglich, ob eine Nachricht, die dies erfordert, wirklich geeignet ist. Es ist in Ordnung, nur einige Daten über das Netzwerk zu schmeißen, ist aber nicht wirklich eine "Nachricht", eher ein serialisiertes Objekt.

Ihre untergeordneten Objekte müssen einen "Zeiger" zum übergeordneten Objekt haben.

+0

Ich stimme Ihrer Einschätzung zu, dass dies keine gute Idee ist, ich arbeite jedoch unter einigen äußeren Bedingungen. Also 'öffentliche Klasse Child {private Elternteil; } '. Will XStream das automatisch auffüllen? Welche XStream Annotation oder Config muss ich einrichten, um damit umgehen zu können? – Freiheit

+0

gut - wenn die Referenz gesetzt ist, wenn Sie das Objekt marshallen, wird es gesetzt, wenn Sie es entmarshalen.IIRC es passiert einfach. Hast Du es versucht? So sehe ich normalerweise, wenn sie arbeiten! – time4tea

+0

dauert es nicht lange: System.out.println (new XStream(). ToXML (übergeordnet)); – time4tea

0

Wenn Sie bereit sind, etwas anderes als XStream zu verwenden, dann kann EclipseLink JAXB (MOXy) problemlos bidirektionale Eigenschaften mit @XmlInverseReference (ich bin der MOXy Tech Lead).

Ihr Objektmodell als würde abgebildet:

import java.util.List; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class Parent { 

    private List<Child> children; 

    @XmlElement(name="child") 
    public List<Child> getChildren() { 
     return children; 
    } 

    public void setChildren(List<Child> children) { 
     this.children = children; 
    } 

} 

und (beachten Sie die Verwendung von @XmlInverseReference auf der übergeordneten Eigenschaft):

import org.eclipse.persistence.oxm.annotations.XmlInverseReference; 

public class Child { 

    private Parent parent; 

    @XmlInverseReference(mappedBy="children") 
    public Parent getParent() { 
     return parent; 
    } 

    public void setParent(Parent parent) { 
     this.parent = parent; 
    } 

} 

Der Demo-Code wie (input.xml aussehen würde, bezieht sich auf die XML aus Ihrer Frage):

Um MOXy als die JAXB-Implementierung anzugeben, die Sie benötigen umfasst eine Datei jaxb.properties im selben Paket wie Ihre Modellklassen mit folgendem Eintrag genannt:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

Unten ist ein Link zu meinem Vergleich von JAXB und XStream:

+1

Ihre Antwort ist wahrscheinlich ein besserer Pfad, aber dieses Projekt ist in XStream gesperrt. – Freiheit

2

Eine Option besteht darin, readResolve im übergeordneten Element zu verwenden, um die Rückverweise festzulegen. Dies wird in der gleichen Weise wie Standardbibliothek Serialisierung nach dem Xstream FAQ hier aufgerufen werden: http://x-stream.github.io/faq.html#Serialization_initialize_transient

Wenn readResolve genannt wird, die Parent und alle seine Kinder bereits deserialisiert worden ist, so dass Sie die Rückreferenzierung zu dieser Zeit einstellen .

public class Parent { 
    private List<Child> children = new ArrayList<Child>(); 
    private Object readResolve() { 
    for(Child child: children) { 
     child.setParent(this); 
    } 
    return this; 
    } 
}