インターフェースを実装する JAXB クラスの生成
-
13-09-2019 - |
質問
現在、XML をアンマーシャリングするために JAXB を使用して Java クラスを生成しています。ここで、最初のスキーマとよく似た新しいスキーマを作成し、生成されるクラスに同じインターフェイスを実装させたいと思います。
たとえば、類似のタグを持つ XML を定義する 2 つのスキーマ ファイルがあるとします。
アダルト.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>
kid.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>
JAXB と XJC を使用して、2 つのクラス ファイルを生成したいと思います。
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 { ... }
}
ここで、 Person インターフェースは getName()
そして getAge()
メソッド。
いくつか見てみましたが、 ドキュメンテーション インターフェースをマッピングするためのものですが、これは DOM にマッピングする Java クラスがすでにある場合にのみ適用されるようです。
あと、これも使ってみました 外部プラグイン しかし、うまくいかないようです。これが私のxjbバインディングファイルです。
<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>
しかし、これにより次のエラーが発生します。
$ 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.
JAXB を使用してインターフェースを実装するクラスを生成することはできますか?
アップデート
使ってみました インターフェースの挿入 プラグインですが、何らかの理由で機能しません。これは xjc を呼び出す方法ですが、プラグイン jar がクラスパスから取得されていないように見えます。
$ 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
エラーが発生します:
unrecognized parameter -Xifins
何か案は?
解決
残念ながら、他の回答の一部で言及されているインターフェイスインジェクションプラグインは、もはや十分にサポートされていないようです。実際、ダウンロードする JAR を見つけるのに苦労しています。
ありがたいことに、 JAXB2 基本プラグイン は、生成された JAXB スタブにインターフェイスを追加するための同様のメカニズムを提供します ( 継承プラグイン).
Inheritance プラグインのドキュメントには、XML スキーマ ファイルがどのようなものかを示す例が含まれています。ただし、スキーマは変更できないため、代わりに外部バインディング ファイルを使用できます。
<?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>
JAXB2 Basics Plugins ドキュメントには、Ant および Maven でプラグインを使用する手順が含まれています。コマンド ラインから直接使用することもできますが、コマンドは少し面倒です (クラスパスに追加する必要がある jar の数のため)。
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
JAXB2 Basics Plugins は、他にも便利なユーティリティ (equals、hashCode、toString メソッドの自動生成など) を多数提供します。
他のヒント
あなたの状況にはやりすぎかもしれませんが、私はAspectJを使用してこれを実行しました(そのプロジェクトではすでにアスペクトを使用していたので、依存関係と公開がすでにありました)。
次の行に沿ってアスペクトを宣言します。
public aspect MyAspect
{
declare parents:
com.foo.generated.Adult
implements com.foo.Person;
declare parents:
com.foo.generated.Kid
implements com.foo.Person;
}
インターフェースを追加します com.foo.Person
クラスへ com.foo.generated.Adult
そして com.foo.generated.Adult
あなたの目的にはやり過ぎかもしれませんが、私たちにとってはうまくいきました。
私にとってうまくいった答えは、JAXB2 Basics プラグインの使用例である Jim Hurne でした。しかし、彼がリンクしたドキュメントはもう利用できないようです。そのため、参考までに、Maven プラグインを次のように構成しました。
<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>
この単純なケースでは、サードパーティのプラグインを使用せずに、 JAXB RI ベンダー拡張機能 xjc:superInterface のカスタマイズ。このアプローチでは、生成されたすべてのクラスがインターフェイスを実装することになることに注意してください。
バインディング ファイルの例:
<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>
あとは実行するだけです XJC バインディング ファイルを指定し、-extension フラグを設定します。JAXB2Basics を導入するよりもはるかに速く/簡単です。
私は当初、ドキュメントに記載されているようにこれが機能するかどうか懐疑的でした。
カスタマイズにより、生成されるすべてのインターフェイスのルート インターフェイスとして使用される Java インターフェイスの完全修飾名を指定できます。このカスタマイズは、globalBindingsgenerateValueClass="false" スイッチを使用してインターフェイスを明確に生成しない限り、効果はありません。
しかし、上記と同様のバインディング (generateValueClass="false" を指定せず、インターフェイスではなくクラスを生成しなかった) で試してみたところ、必要な出力が得られました。生成されたすべてのクラスは共通のインターフェイスを実装していました。
私の場合、java -jar によるコマンドライン呼び出しは機能します。
java -jar $somepath/jaxb-xjc.jar -classpath $somepath/xjc-if-ins.jar my.xsd -d $destdir -b $bindingconfig -p $desiredpackage -extension -Xifins
ただし、xjc ant-task を実行するとエラーが残ります。私の場合の本当の理由は、Ant がロードしようとしているクラス ファイルのバージョン番号が間違っているため、表示されるエラー メッセージは腹立たしいです (下記のスタックトレースを参照)。この正しいエラー メッセージは、以下を ANT_OPTS に追加した場合にのみ表示されます。-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
インターフェイス挿入プラグインのドキュメントでは、次のことが示唆されています。
コマンドラインからインターフェイス挿入プラグインを使用してXJCを呼び出すには、次のことを記述できます。
java -cp $JAXB_HOME/share/lib/xjc-if-ins.jar -extension -Xifins schema
]
間違ったクラスのメインメソッド(com.sun.tools.xjc.XJCFacade)を呼び出しているのではないかと思います。おそらく、正確な構文で再試行する必要があります。
これは、同様の問題を議論する別のフォーラムのリンクです。http://forums.java.net/jive/message.jspa?messageID=220686
- これをコメントとして投稿したかったのですが、コメントするには十分なポイントがありません。
より複雑なスキーマ用の JAXB データ バインディング ファイルの構築を支援したい方のために、最新のオープン ソース XML ツールである CAM Editor v2.2 がこれをサポートするようになりました。
ステップバイステップ ガイドのリソースとダウンロード サイトにアクセスし、ページ上部にあるツールのダウンロード セクションを参照することができます。
http://www.cameditor.org/#JAXB_Bindings
楽しむ。
何らかの説明の XJC プラグインが問題の解決策になります。問題は、機能するものを見つけるだけです。それらに関する最良の情報源は次のとおりです。
https://jaxb2-commons.dev.java.net/
特にこれは: