Generieren einer JAXB-Klasse, die eine Schnittstelle implementiert

Lesezeit: 11 Minuten

Generieren einer JAXB Klasse die eine Schnittstelle implementiert
Alex Spurling

Ich verwende derzeit JAXB, um Java-Klassen zu generieren, um XML zu entmarshallieren. Jetzt möchte ich ein neues Schema erstellen, das dem ersten sehr ähnlich ist, und die generierten Klassen dieselbe Schnittstelle implementieren lassen.

Angenommen, ich habe zwei Schemadateien, die XML mit ähnlichen Tags definieren:

adult.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:element name="Person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="Age" type="xs:integer" />
      <xs:element name="Job" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

kind.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:element name="Person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Name" type="xs:string" />
      <xs:element name="Age" type="xs:integer" />
      <xs:element name="School" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:element>

Mit JAXB und XJC möchte ich zwei Klassendateien generieren:

public class Adult implements Person {
    ...
    public String getName() { ... }
    public int getAge() { ... }
    public String getJob { ... }
}

public class Kid implements Person {
    ...
    public String getName() { ... }
    public int getAge() { ... }
    public String getSchool { ... }
}

wobei die Person-Schnittstelle die definiert getName() und getAge() Methoden.

Ich habe mir einige angeschaut Dokumentation für die Zuordnung von Schnittstellen, aber dies scheint nur für die Situation zu gelten, in der Sie bereits Java-Klassen haben, die Sie einem DOM zuordnen möchten.

Außerdem habe ich versucht, dies zu verwenden externes Plugin aber es scheint nicht zu funktionieren. Hier ist meine XJB-Bindungsdatei:

<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
  xmlns:ext="http://xml.w-wins.com/xjc-plugins/interfaces"
  jxb:extensionBindingPrefixes="xjc">

    <jxb:bindings schemaLocation="xsd/adult.xsd" node="xs:schema/xs:complexType[@name="Person"]">
        <ext:interface>mypackage.Hello</ext:interface> 
    </jxb:bindings>

</jxb:bindings>

aber dies gibt den folgenden Fehler:

$ java -cp "lib/activation.jar;lib/InterfacesXJCPlugin.jar;lib/jaxb1-impl.jar;lib/jaxb-api.jar;lib/jaxb-xjc.jar;lib/jsr173_1.0_api.jar" com.sun.tools.xjc.XJCFacade -p mypackage.myxml -extension -Xinterfaces xsd/adult.xsd -b binding.xjb
parsing a schema...
[ERROR] XPath evaluation of "xs:schema/xs:complexType[@name="Person"]" results in empty target node
  line 8 of file:/C:/dev/jaxb/jaxb-ri/binding.xjb

Failed to parse a schema.

Ist es möglich, mit JAXB eine Klasse zu generieren, die eine Schnittstelle implementiert?

Aktualisieren

Ich habe versucht, die zu verwenden Schnittstelleneinfügung plugin, kann es aber aus irgendeinem Grund nicht zum Laufen bringen. So rufe ich xjc auf, aber es ist, als ob das Plugin-Jar nicht vom Klassenpfad abgeholt wird:

$ java -cp "lib/xjc-if-ins.jar;lib/jaxb-xjc.jar" com.sun.tools.xjc.XJCFacade -p mypackage -extension -Xifins myschema.xsd -b binding.xjb

Ich bekomme den Fehler:

unrecognized parameter -Xifins

Irgendwelche Ideen?

  • Das Interface Insertion Plugin kann verwendet werden, um eine aus einem XSD-Element generierte Klasse dazu zu bringen, eine bestimmte Schnittstelle zu implementieren. Hier möchten Sie eine Klasse basierend auf ihrem Schemanamen generieren – dazu benötigen Sie ein anderes Plugin. Ich habe das Einfügen der Schnittstelle erfolgreich mit maven zum Laufen gebracht. Lassen Sie mich wissen, wenn Sie die Details benötigen. Die Quellen der Schnittstelleneinfügung sind hier: jaxb2-commons.dev.java.net/interface-insertion/…

    – rochb

    13. November 2009 um 16:43 Uhr

  • ist der richtige Weg.

    – rochb

    21. November 2009 um 14:44 Uhr

1645706830 106 Generieren einer JAXB Klasse die eine Schnittstelle implementiert
Jim Hurne

Leider sieht es so aus, als ob das in einigen anderen Antworten erwähnte Interface-Injection-Plugin nicht mehr gut unterstützt wird. Tatsächlich habe ich Probleme, das JAR zum Herunterladen zu finden.

Zum Glück ist die JAXB2-Grundlagen-Plugins bietet einen ähnlichen Mechanismus zum Hinzufügen einer Schnittstelle zu den generierten JAXB-Stubs (siehe die Vererbungs-Plugin).

Die Dokumentation des Inheritance-Plugins enthält ein Beispiel, das zeigt, wie die XML-Schemadatei aussehen könnte. Da Sie das Schema jedoch nicht ändern können, können Sie stattdessen eine externe Bindungsdatei verwenden:

<?xml version="1.0"?>
<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
  xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
  jxb:extensionBindingPrefixes="xjc">

    <jxb:bindings schemaLocation="xsd/adult.xsd">
      <jxb:bindings node="//xs:complexType[@name="Person"]">
        <inheritance:implements>mypackage.Hello</inheritance:implements> 
      </jxb:bindings>
    </jxb:bindings>

</jxb:bindings>

Die JAXB2 Basics Plugins-Dokumentation enthält Anweisungen zur Verwendung des Plugins mit Ant und Maven. Sie können es auch direkt von der Befehlszeile aus verwenden, aber der Befehl ist etwas chaotisch (aufgrund der Anzahl der JAR-Dateien, die Sie dem Klassenpfad hinzufügen müssen):

java -jar jaxb-xjc.jar 
     -classpath jaxb2-basics-0.5.3.jar,jaxb2-basics-runtime-0.5.3.jar,
                jaxb2-basics-tools-0.5.3.jar,commons-beanutils-0.5.3.jar,
                commons-lang.jar,commons-logging.jar
     -p mypackage.myxml -extension -Xinheritance xsd/adult.xsd -b binding.xjb

Die JAXB2 Basics Plugins bieten eine Reihe anderer Dienstprogramme, die Sie möglicherweise ebenfalls nützlich finden (z. B. die automatische Generierung von Gleichheits-, HashCode- und toString-Methoden).

  • Ihr Beispiel nutzt eine Erweiterung oder Core-Fähigkeit der maven-jaxb2-plugin … gibt es eine ähnliche Erweiterung für cxf-xjc-plugin damit können wir so etwas wie einrichten -Xinheritance?

    – Pulkitsinghal

    28. Dezember 2013 um 18:24 Uhr


  • Herausfinden, dass cxf-xjc-plugin kann auch ein ähnliches Setup nutzen, wenn es wie folgt optimiert ist: gist.github.com/pulkitsinghal/8163296

    – Pulkitsinghal

    28. Dezember 2013 um 19:44 Uhr

  • Außerdem sollte der richtige XPATH für das gegebene Beispiel //xs:element sein[@name=’Person’]/xs:komplexerTyp[1]

    – Roy B

    30. Dezember 2014 um 13:57 Uhr

  • jaxb-xjc.jar von maven gibt no main in METAINF Error. Woher bekommen wir jaxb-xjc.jar, das mit ausgeführt wird? java -jar Möglichkeit ?

    – ulab

    17. Mai 2016 um 11:34 Uhr

  • Ich habe gerade 2 Stunden beim Debuggen dieser Lösung verloren … es ist sehr wichtig, Knoten wie diesen zu deklarieren node=”/xs:schema/xs:element[@name=’Person’]/xs:complexType”. Im Gegensatz dazu wird das Vererbungs-Tag ignoriert

    – Levijatanu

    25. Februar 2020 um 9:24 Uhr

1645706831 941 Generieren einer JAXB Klasse die eine Schnittstelle implementiert
Chris

Es könnte für Ihre Situation übertrieben sein, aber ich habe dies mit AspectJ gemacht (wir haben bereits Aspekte in diesem Projekt verwendet, also hatten wir bereits die Abhängigkeit und die Exposition).

Sie würden einen Aspekt wie folgt deklarieren:

public aspect MyAspect
{
    declare parents: 
        com.foo.generated.Adult
    implements com.foo.Person;

    declare parents: 
        com.foo.generated.Kid
    implements com.foo.Person;
}

Welches wird die Schnittstelle hinzufügen com.foo.Person zu den Klassen com.foo.generated.Adult und com.foo.generated.Kid

Könnte für Ihren Zweck übertrieben sein, aber es hat für uns funktioniert.

  • Ich denke, das funktioniert nur mit Weben zur Kompilierzeit, sonst beschweren sich Marshaller über das Extra ajc$instance Eigenschaften.

    – Orangenhund

    22. September 2016 um 16:36 Uhr


Die Antwort, die für mich funktioniert hat, war Jim Hurnes Beispiel für die Verwendung des JAXB2 Basics-Plugins. Die von ihm verlinkte Dokumentation scheint jedoch nicht mehr verfügbar zu sein. Als Referenz habe ich das Maven-Plugin so konfiguriert:

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>0.8.2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    </execution>
            </executions>
            <configuration>
                <extension>true</extension>
                <args>
                    <arg>-Xinheritance</arg>
                </args>
                <bindingDirectory>src/main/resources/xjb</bindingDirectory>
                <bindingIncludes>
                    <include>**.xml</include> <!-- This Should reference the binding files you use to configure the inheritance -->
                </bindingIncludes>
                <schemaDirectory>src/main/resources/xsd</schemaDirectory>
                <generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory>
                <generatePackage>mypackage</generatePackage>
                <plugins>
                    <plugin>
                        <groupId>org.jvnet.jaxb2_commons</groupId>
                        <artifactId>jaxb2-basics</artifactId>
                        <version>0.5.3</version>
                    </plugin>
                </plugins>
            </configuration>
        </plugin>

  • das hat perfekt funktioniert. Die Versionen sind jedoch ziemlich alt und ich konnte nicht die gleiche Lösung mit den “neuesten” Versionen zum Laufen bringen

    – Sean

    28. Juni 2016 um 16:15 Uhr

Für diesen einfachen Fall ist es möglich, dies zu erreichen, ohne ein Plug-in eines Drittanbieters zu verwenden JAXB RI Anbietererweiterungen xjc:superInterface-Anpassung. Es sollte beachtet werden, dass dieser Ansatz bewirkt, dass alle generierten Klassen die Schnittstelle implementieren.

Beispielbindungsdatei:

<jxb:bindings version="1.0" 
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
  jxb:extensionBindingPrefixes="xjc">
    <jxb:bindings schemaLocation="adult.xsd" node="/xs:schema">
    <jxb:globalBindings>
        <xjc:superInterface name="com.example.model.Person"/>
    </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>

Sie müssen dann nur noch laufen xjc Angabe der Bindungsdatei und Setzen des Flags -extension. Viel schneller/einfacher als das Einbringen von JAXB2Basics!

Ich war anfangs skeptisch, ob dies funktionieren würde, da in der Dokumentation angegeben ist:

Die Anpassung ermöglicht es Ihnen, den vollständig qualifizierten Namen der Java-Schnittstelle anzugeben, die als Root-Schnittstelle aller generierten Schnittstellen verwendet werden soll. Diese Anpassung hat keine Auswirkungen, es sei denn, Sie generieren speziell Schnittstellen mit dem Schalter globalBindings generateValueClass=”false”.

Aber als ich es mit einer ähnlichen Bindung wie der obigen ausprobierte (ohne GenerateValueClass=”false” anzugeben und Klassen, nicht Schnittstellen zu generieren), gab es mir die gewünschte Ausgabe – alle meine generierten Klassen implementierten die gemeinsame Schnittstelle.

1645706831 575 Generieren einer JAXB Klasse die eine Schnittstelle implementiert
cfsch

In meinem Fall funktioniert der Kommandozeilenaufruf über java -jar:

java -jar $somepath/jaxb-xjc.jar -classpath $somepath/xjc-if-ins.jar my.xsd -d $destdir -b $bindingconfig -p $desiredpackage -extension -Xifins

Beim Ausführen der xjc-Ant-Task bleibt der Fehler jedoch bestehen. Die angezeigte Fehlermeldung ist irritierend, da der wahre Grund in meinem Fall eine falsche Versionsnummer in einer Klassendatei ist, die Ameise zu laden versucht (siehe Stacktrace unten). Diese korrekte Fehlermeldung erscheint nur, wenn Sie Folgendes zu ANT_OPTS hinzufügen:
-Dcom.sun.tools.xjc.Options.findServices=true

[xjc] java.lang.UnsupportedClassVersionError: Bad version number in .class file
[xjc]     at java.lang.ClassLoader.defineClass1(Native Method)
[xjc]     at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
[xjc]     at org.apache.tools.ant.AntClassLoader.defineClassFromData(AntClassLoader.java:1134)
[xjc]     at org.apache.tools.ant.AntClassLoader.getClassFromStream(AntClassLoader.java:1320)
[xjc]     at org.apache.tools.ant.AntClassLoader.findClassInComponents(AntClassLoader.java:1376)
[xjc]     at org.apache.tools.ant.AntClassLoader.findClass(AntClassLoader.java:1336)
[xjc]     at org.apache.tools.ant.AntClassLoader.loadClass(AntClassLoader.java:1074)
[xjc]     at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
[xjc]     at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
[xjc]     at com.sun.tools.xjc.Options.findServices(Options.java:936)
[xjc]     at com.sun.tools.xjc.Options.getAllPlugins(Options.java:336)
[xjc]     at com.sun.tools.xjc.Options.parseArgument(Options.java:632)
[xjc]     at com.sun.tools.xjc.Options.parseArguments(Options.java:742)
[xjc]     at com.sun.tools.xjc.XJC2Task._doXJC(XJC2Task.java:444)
[xjc]     at com.sun.tools.xjc.XJC2Task.doXJC(XJC2Task.java:434)
[xjc]     at com.sun.tools.xjc.XJC2Task.execute(XJC2Task.java:369)
[xjc]     at com.sun.istack.tools.ProtectedTask.execute(ProtectedTask.java:55)
[xjc]     at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
[xjc]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[xjc]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[xjc]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[xjc]     at java.lang.reflect.Method.invoke(Method.java:585)
[xjc]     at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
[xjc]     at org.apache.tools.ant.Task.perform(Task.java:348)
[xjc]     at org.apache.tools.ant.Target.execute(Target.java:390)
[xjc]     at org.apache.tools.ant.Target.performTasks(Target.java:411)
[xjc]     at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1360)
[xjc]     at org.apache.tools.ant.Project.executeTarget(Project.java:1329)
[xjc]     at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[xjc]     at org.apache.tools.ant.Project.executeTargets(Project.java:1212)
[xjc]     at org.apache.tools.ant.Main.runBuild(Main.java:801)
[xjc]     at org.apache.tools.ant.Main.startAnt(Main.java:218)
[xjc]     at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
[xjc]     at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)
[xjc]
[xjc] failure in the XJC task. Use the Ant -verbose switch for more details

1645706832 748 Generieren einer JAXB Klasse die eine Schnittstelle implementiert
Thimmayya

Die Dokumentation für das Interface-Insertion-Plugin schlägt Folgendes vor

[
To call xjc with the Interface Insertion Plugin from the command line, you may write:

java -cp $JAXB_HOME/share/lib/xjc-if-ins.jar -extension -Xifins schema

]

Ich vermute, dass Sie die Hauptmethode der falschen Klasse aufrufen – com.sun.tools.xjc.XJCFacade. Sie sollten es wahrscheinlich mit der genauen Syntax erneut versuchen.

Hier ist ein Link zu einem anderen Forum, in dem ein ähnliches Problem diskutiert wird.
http://forums.java.net/jive/message.jspa?messageID=220686

  • Ich hätte dies als Kommentar gepostet, aber ich habe nicht genug Punkte, um einen Kommentar abzugeben.

Generieren einer JAXB Klasse die eine Schnittstelle implementiert
Skaffmann

Ein XJC-Plygin irgendeiner Beschreibung ist die Antwort auf Ihr Problem, es geht nur darum, einen zu finden, der funktioniert. Die beste Quelle für sie ist hier:

https://jaxb2-commons.dev.java.net/

Insbesondere dieser:

https://jaxb2-commons.dev.java.net/interface-insertion/

843240cookie-checkGenerieren einer JAXB-Klasse, die eine Schnittstelle implementiert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy