8 Stimmen

Vermeidung von doppeltem Code bei der Verwendung von JAXB mit containerähnlichen Elementen mit ähnlicher Struktur

Die Situation

Ich verwende die JAXB-Implementierung von MOXy, um mit einem großen XML-Dokument zu arbeiten, dessen Schema viele ähnliche komplexe Typen enthält. Genauer gesagt gibt es etwa zwei Dutzend Typen, die als Listen-Wrapper-Elemente mit der folgenden Struktur fungieren:

<ITEMS attr1="X" attr2="Y">
  <ITEM>...</ITEM>
  ...
  <EXTENSION/>
<ITEMS>

Für jedes dieser list-wrapper-ähnlichen Elemente ändert sich der Name und das darin enthaltene Listenelement. Die Attribute (die alle optional sind) und das einzelne EXTENSION-Element (ebenfalls optional) sind jedoch immer vorhanden. Hier ein Beispiel für die Verwendung von zwei der Typen:

<ROLES visible="false">
  <ROLE type="X"/>
  <ROLE type="Y"/>
</ROLES>

<PAYMENTS visible="true">
  <PAYMENT>
    <PAYEENAME>Joe</PAYEENAME>
  </PAYMENT>
  <EXTENSION>
    <SOMETHING>Here</SOMETHING>
  </EXTENSION>
</PAYMENTS>

Die Frage

Ich möchte eine Verdoppelung des Codes vermeiden, da das Einzige, was sich zwischen diesen Elementen ändert, der Name und das eine oder andere Element ist, das es enthält. Wie lässt sich dies am besten bewerkstelligen?

Ich sehe nur zwei mögliche Lösungen.

1

Erstellen einer konkreten Klasse unter Verwendung von Generika, um den Objekttyp anzugeben, der in der sich ändernden Sammlung verwendet werden soll. Dann Verwendung der externen OX-Mappings von MOXy, um anzugeben, wie jede einzelne Verwendung der Klasse serialisiert werden soll. Etwa so:

public class GenericContainer<T> {
    @XmlAttribute
    protected Boolean visibile;
    @XmlElement(name = "Extension")
    protected Extension extension;

    // OX Mappings done in external meta file
    protected List<T> items;
    ...
}

Ich finde diese Option zwar gut, aber es scheint nicht möglich zu sein, die OX-Zuordnungen einer Klasse für jede einzelne Verwendung neu zu definieren.

2

Erstellen einer Basisklasse ohne die Eigenschaft List und anschließendes Erstellen einer konkreten Klasse für jedes benutzerdefinierte Wrapper-Element. Diese Lösung funktioniert definitiv, aber ich werde am Ende mit etwa zwei Dutzend fast identische Klassen.

Ist beides #1 möglich oder gibt es eine bessere Lösung, an die ich noch nicht gedacht habe?

Vielen Dank im Voraus!

0voto

Chase Punkte 3023
public class GenericContainer {

private Boolean visible;
private Object extension;
private List<Object> nodes;

@XmlAttribute
public Boolean isVisible() {
    return visible;
}

public void setVisible(Boolean visible) {
    this.visible = visible;
}

@XmlElement(name="EXTENSION")
public Object getExtension() {
    return extension;
}

public void setExtension(Object extension) {
    this.extension = extension;
}

@XmlAnyElement
public List<Object> getNodes() {
    return nodes;
}

public void setNodes(List<Object> nodes) {
    this.nodes = nodes;
}

}

Und zum Lesen der XML-Instanz

    JAXBContext jaxbContext = JAXBContext.newInstance("jaxbtest1");
    Unmarshaller um = jaxbContext.createUnmarshaller();

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new File("src/test1.xml"));
    Node node = doc.getFirstChild();

    JAXBElement<GenericContainer> jaxbE = um.unmarshal(node, GenericContainer.class);

    GenericContainer gc = jaxbE.getValue();
    Boolean vis = gc.isVisible();
    Element ext = (Element)gc.getExtension();
    for(Object o : gc.getNodes()) {
        Element listItem = (Element)o;
    }

Aber ist Code-Duplizierung wirklich wichtig? Wenn Ihr Schema eine gemeinsame Erweiterungsbasis für die Typen von Listencontainern hat und Sie xjc verwenden, warum sollten Sie unterschiedliche Klassen vermeiden? Schließlich besteht die Idee hinter JAXB darin, eine Wertklasse für jeden einzelnen komplexen Typ zu haben.

Wenn Sie eine Allzwecklogik erstellen können, die ähnliche, aber unterschiedliche XML-Typen verarbeitet, und keine große Anzahl von Java-Klassen benötigen, können Sie zu StAX wechseln.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X