JAXB Postprocessing

1 Kommentar

Im Rahmen eines aktuellen Projekts verwenden wir JAXB zum Unmarshalling strukturierter Inhalte, die aus einem CMS gelesen werden. Es ergab sich die Notwendigkeit, nach dem reinen Unmarshalling noch weitere Dinge zu tun, um dem neu erzeugten Objekt(baum) einen konsistenten Zustand zu geben. Im konkreten Fall wurde eine Map benötigt, die redaktionell gepflegte textuelle IDs zu numerischen IDs zuordnet. Da diese Zuordnung nicht aus dem XML ablesbar ist, muss sie nach dem Erzeugen des Objekts hergestellt werden.

Auf der Suche nach einer möglichst eleganten Möglichkeit, den generischen XML-Reader um ein Postprocessing zu erweitern, hatten wir zunächst die Idee ein Interface zu definieren das von jeder gemappten Top-Level-Modellklasse implementiert werden muss, die Postprocessing benötigt. Dies stellte sich jedoch als überflüssige Idee heraus, da JAXB bereits Mechanismen für Pre- und Postprocessing anbietet. Die zugehörige Dokumentation befindet sich in der Javadoc zu javax.xml.bind.Unmarshaller.

Indem man der gemappten Modellklasse eine Methode

void afterUnmarshal(Unmarshaller, Object parent);

hinzufügt, hat man einen Callback-Hook der jeweils nach dem Unmarshalling aufgerufen wird. Innerhalb der Methode hat man vollen Zugriff auf den Unmarshaller und auf das in der Hierarchie höherstehende parent-Objekt. Befindet man sich im Top-Level-Objekt (XmlRootElement), so ist parent null.

Implementiert man diese Methode in der obersten Modellklasse, so kann man von dort aus bequem den Objektbaum durchwandern und die nötigen Aktionen vornehmen. In unserem konkreten Fall sieht das unspektakulär aus:

void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
    createIDs();
}

Die Methode „createIDs();“ hat default visibility, ist also vom zugehörigen Unit-Test im gleichen Package aufrufbar, ohne dort in Abwesenheit von JAXB afterUnmarshal(…) nutzen zu müssen. Dies dient einerseits der „separation of concerns“, andererseits ist so die afterUnmarshal(…) Methode je nach Anforderung beliebig erweiterbar ohne dass dort ein Dickicht an Code entsteht.

Tags

Kommentare

  • Oliver Gierke

    Hallo,

    ich hatte in einem vergangenen Projekt das gleiche Problem. IMHO ist das von JAXB propagierte Vorgehen allerdings ein ziemlicher Hack, weil die Methode in keinem Interface auftaucht und sich jemand, der sich den Code zum ersten Mal anschaut einfach nur „WTF?“ denkt.

    Unser workaround damals war um den Unmarshaller herum ein Subsystem zu schneiden, auf dem sich Enricher für einen bestimmten Typ registrieren konnten, diese wurden dann mit dem jeweils passenden Objekt gerufen. Erst, wenn das Domänenobjekt dieses Subsystem verklässt gilt es dann als vollständig initialisiert.

    Dieses Vorgehen hat zwar den Nachteil, dass das Domänenobjekt seine internen Constraints nicht mehr wirklich selbst unter Kontrolle hat, erlaubt aber beim Enrichment auch auf andere Infrastrukturkomponenten zuzugreifen (in unserem Fall waren das Springbeans), was per einfachem JAXB Callback leider nicht geht.

    Gruß
    Ollie

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.