Ich denke, viele Java-Entwickler, die mindestens einmal auf Web-
, haben die Generierung von Java
DTO
Klassen verwendet, wie im XML Schema
( XSD
) beschrieben . Jaxb bewältigt dies mit einem Knall, egal wie man es benutzt, über einen xjc
oder wsimport
Aufruf über die Kommandozeilen-, Maven- oder Gradle-Plugins.
Es ist so schnell und einfach, Klassen aus einem XSD
Schema zu generieren. Aber hier ist ein Problem - die Beschreibungen in der Originalschaltung verschwinden fast vollständig!
In der Praxis fehlt die Beschreibung der Felder (Felder) vollständig, da nur die Klasse selbst eine Javadoc
Beschreibung in einem festen Format hat (in dem Sie beispielsweise die Beschreibung und das XML
Fragment nicht ohne die regulären Elemente trennen können). Und wenn Sie, wie ich, sie auch zur Laufzeit ( runtime
) benötigen, gibt es absolut Probleme .
So seltsam es auch scheinen mag, es war notwendig, dies zu überwinden, die Aufgabe nahm viel Zeit in Anspruch, und als Ergebnis schrieb ich ein Plug-In, das ich in der Hoffnung präsentieren möchte, dass es jemandem in Zukunft einige Stunden ersparen kann.
Jaxb Features auf einen Blick
Jaxb hat eine lange Geschichte und eine gute offizielle Beschreibung, einschließlich des Hinzufügens von Verhalten zu generierten Klassen.
Das Hauptwerkzeug zum Aufrufen der Klassengenerierung über die Befehlszeile - xjc verfügt auch nicht über die geringste Anzahl von Schlüsseln. Keiner von ihnen ist jedoch für unseren Fall.
Natürlich können Sie nicht anders, als -b
erwähnen, wo Sie Ihre eigene Bindung bereitstellen können. Und dies ist eine sehr mächtige Waffe, insbesondere in Verbindung mit mehreren Plug-Ins. Ein sehr guter Blog-Beitrag (auf Englisch) - ich empfehle ihn als kurze Einführung zu lesen. Die Bindung ist jedoch größtenteils auf die statischen Werte der zugewiesenen Anthotationen oder Vornamen beschränkt, die die Elemente angeben, auf die sie angewendet wird. Bei meinem Problem hilft das nicht.
Jaxb (XJC) Plugins
Während ich nach einer vorgefertigten Lösung suchte, fand ich viele Plugins, die die Generation erweitern. Ich nehme an, dass ihre Überprüfung den Rahmen dieses Beitrags sprengt. Was wichtig ist, ich finde nicht, was genau das tut, was ich brauche.
Beim Lesen der Antworten und Fragen unter http://stackoverflow.com/ fand ich jedoch mehrere Fragen dieser Art, zum Beispiel:
- Verwenden von JAXB zum Behandeln von Schemaanmerkungen .
- So erstellen Sie generierte Klassen mit Javadoc aus der XML-Schemadokumentation
- Wie kann ich eine Klasse generieren, aus der ich das XML eines Knotens als String abrufen kann?
und keine einzige vollständige Antwort, in einigen über viele Jahre!
Als wir jedoch zum Thema Chancen zurückkehrten, stellte sich heraus, dass es eine API
zum Schreiben von Plugins gibt! Low-Level, manchmal verwirrend, fast ohne Dokumentation ... Aber ich kann sagen, dass dies sehr weit fortgeschritten ist, das heißt, Sie können direkt viel in welche Prozesse eingreifen. Übrigens wird in vielen nicht standardmäßigen Fällen häufig auf die Antworten darauf Bezug genommen. Nun, ich habe versucht, ein Plugin zu schreiben.
Für diejenigen, die an den Details des Schreibprozesses ihrer Plugins interessiert sind, kann ich Artikel empfehlen:
Was ich wollte und warum
Für eine unserer Integrationen stellte der Kunde ein Archiv mit XSD
Dateien zur Verfügung, nach dem wir das Modell in MDM Unidata generieren mussten , mit dem wir arbeiten, um die Qualitätsregeln weiter zu konfigurieren.
Ich stelle fest, dass das MDM
System selbst proprietär ist, es ist unwahrscheinlich, dass viele damit vertraut sind, aber das spielt keine Rolle. Das Fazit ist, dass wir Verzeichnisse und Register aus XSD
Beschreibungen erstellen mussten. Gleichzeitig haben Registries Felder, die sowohl eine Kennung (Feldname) als auch einen "Anzeigenamen" verwenden - ein Name, der für eine Person auf Russisch verständlich ist. Mit einem RDBMS kann eine einfache Analogie gezogen werden (und dies ist wahrscheinlich auch ein nützliches Beispiel für die Anwendung), in Bezug auf die wir annehmen können, dass wir Datenbanktabellen erstellen wollten, aber gleichzeitig Beschreibungen ( comment
) für jede Spalte zur späteren Verwendung geben.
Mein Plan war folgender:
- Generieren von
XSD
Klassen mit XJC
- Dann nehmen wir eine schöne Bibliothek von Reflexionen und iterieren über alle Objekte, wobei wir rekursiv die Felder hinuntergehen.
Bei lateinischen Namen, die aus den field
entnommen wurden, funktionierte alles schnell. Aber die russische, von Menschen lesbare Beschreibung war nirgends zu finden!
Das manuelle Bearbeiten von Beschreibungen ist keine Option, da Zehntausende verschachtelter Felder vorhanden sind.
Der erste Versuch bestand darin, selbst einen ähnlichen Parser über Groovy
zu schreiben und die Beschreibungen von XSD
. Und im Allgemeinen wurde es implementiert. Es wurde jedoch schnell klar, dass in vielen Fällen zusätzliche Verarbeitung erforderlich ist - rekursive Aufrufe, Unterstützung für XSD
1.1-Erweiterungen in Form von restriction
/ extension
(mit Unterstützung für Vererbung und Überschreibung), bei denen verschiedene Typen Klassenfelder wie <element>
und <attribute>
, <sequence>
generieren <sequence>
, <choose>
und viele andere kleine Dinge. Die Implementierung war mit Ergänzungen überwachsen, aber sie erhöhte die Harmonie nicht.
Infolgedessen kehrte ich zu der Idee zurück, das Plugin xjc-documentation-annotation-plugin zu schreiben, das ich Ihnen vorstelle, in der Hoffnung, dass es für jemanden außer mir nützlich sein wird!
xjc-Dokumentation-Annotation-Plugin
Alles ist auf dem Github angelegt: https://github.com/Hubbitus/xjc-documentation-annotation-plugin
Es gibt Anweisungen, Tests und ein separates - gradle
mit einem Anwendungsbeispiel.
Ich denke, es macht keinen Sinn, die Beschreibung hier von dort zu kopieren, nur kurz zu zeigen, was es tut.
Angenommen, es gibt ein solches XSD
Fragment:
<xs:complexType name="Customer"> <xs:annotation> <xs:documentation></xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="name" type="xs:string"> <xs:annotation> <xs:documentation> </xs:documentation> </xs:annotation> </xs:element> </xs:sequence> </xs:complexType>
Standardmäßig generiert XJC
daraus eine XJC
(Getter, Setter und einige irrelevante Details werden aus XJC
Lesbarkeit weggelassen):
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Customer", propOrder = { "name", "age" }) public class Customer { @XmlElement(required = true) protected String name; @XmlElement(required = true) @XmlSchemaType(name = "positiveInteger") protected BigInteger age; }
Mit dem Plugin erhalten Sie ( Javadoc
bleibt gleich, der Einfachheit halber weggelassen):
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "Customer", propOrder = { "name", "age" }) @XsdInfo(name = "", xsdElementPart = "<complexType name=\"Customer\">\n <complexContent>\n <restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n <sequence>\n <element name=\"name\" type=\"{http://www.w3.org/2001/XMLSchema}string\"/>\n <element name=\"age\" type=\"{http://www.w3.org/2001/XMLSchema}positiveInteger\"/>\n </sequence>\n </restriction>\n </complexContent>\n</complexType>") public class Customer { @XmlElement(required = true) @XsdInfo(name = " ") protected String name; @XmlElement(required = true) @XmlSchemaType(name = "positiveInteger") @XsdInfo(name = "") protected BigInteger age; }
Überprüfen Sie die hinzugefügten @XmlType
Anmerkungen.
Dies zu verwenden ist dann so einfach wie jede andere Anmerkung:
XsdInfo xsdAnnotation = CadastralBlock.class.getDeclaredAnnotation(XsdInfo.class); System.out.println("XSD description: " + xsdAnnotation.name());
Ein Arbeitsbeispiel sind die Tests: 1 , 2 .