jaxbバインディングファイル:xmladaptersとパッケージ名
質問
このようなバインディングファイルがあります
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<jxb:bindings schemaLocation="example.xsd" node="/xs:schema">
<jxb:schemaBindings>
<jxb:package name="example" />
</jxb:schemaBindings>
<jxb:globalBindings>
<jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
<jxb:javaType name="java.util.Calendar" xmlType="xs:date"
parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
printMethod="javax.xml.bind.DatatypeConverter.printDate" />
<jxb:javaType name="java.util.Calendar" xmlType="xs:time"
parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
printMethod="javax.xml.bind.DatatypeConverter.printTime" />
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>
スキーマクラスは「例」(正しい)で生成されますが、「org.w3._2001.xmlschema」(間違った)のxmladaptersが生成されます。どうすればこれを修正できますか?
解決
私もこの問題を抱えていました、それを使って解決しました これ.
基本的な前提は、次のコンテンツを含むXJCコンピレーションにスキーマを含めることです。
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<annotation><appinfo>
<jaxb:schemaBindings>
<jaxb:package name="org.acme.foo"/>
</jaxb:schemaBindings>
</appinfo></annotation>
</schema>
次に、生成されたアダプターを配置する場所にパッケージ名を調整します。 XJCは、このスキーマはW3C XMLスキーマ自体のスキーマセットの一部であり、そのバインディングを称えると信じています。
他のヒント
org.w3._2001.xmlschema
XJCが拡張するクラスを生成する必要があるため、パッケージはここで作成されます javax.xml.bind.annotation.adapters.XmlAdapter
, 、それはあなたの解析/印刷の静的メソッドを呼び出します。何らかの理由で、より便利な場所ではなく、このパッケージに入れます。
どのjaxb実装を使用しているかについては言いませんが、Jaxb Riには javaType
のサブクラスを指定できるバインディングカスタマイズ XmlAdapter
直接、ではなく parseMethod
/printMethod
ペア。これにより、合成を生成する必要性が削除されます XmlAdapter
ブリッジクラス。を参照してください RIドキュメント これを行う方法のために。
Eclipselink/Moxyにはこれに似たものがあると思いますが、Java6に出荷するXJCがそれができるかどうかはわかりません(太陽はJREに持ち込んだときにRIから有用なものの半分を除去したようです) 。
Apache CXFユーザーの場合、最もクリーンな方法は -p
によって提供されるオプション wsdl2java
.
-p [wsdl-namespace =] packageName
生成されたコードに使用するゼロ、またはそれ以上のパッケージ名を指定します。オプションでは、WSDL名空間をパッケージ名マッピングに指定します。
私たちの場合には
-p http://www.w3.org/2001/XMLSchema=org.acme.foo
cxf-codegen-pluginを使用する場合は、別のペアを追加するだけです <extraarg>
.
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
[...]
<extraarg>-p</extraarg>
<extraarg>http://www.w3.org/2001/XMLSchema=org.acme.foo</extraarg>
[...]
</plugin>
予約されたXSDネームスペースを指すTargetNamesSpaceの必要はなく、Catch-All JaxBパッケージバインディングは必要ありません。
グローバルバインディングを使用するより良い方法は、この解析/印刷ペアを使用する代わりに明示的なアダプターを指定することです。たとえば、以下の代わりに:
<jaxb:javaType name="java.lang.Long" xmlType="xs:long"
parseMethod="com.mypackage.myclass.parseLong"
printMethod="com.mypackage.myclass.print"/>
代わりに、次のようにする必要があります。
<xjc:javaType name="java.lang.Long" xmlType="xs:long"
adapter="com.mypackage.LongAdapter"/>
XJCの名前空間を追加することを忘れないでください:
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc"
クラスのlongadapterは次のようになります:
public class LongAdapter
extends XmlAdapter<String, Long>
{
public Long unmarshal(String value) {
return your_util_class.parseLong(value);
}
public String marshal(Long value) {
return your_util_class.print(value);
}
}
このように、アダプタークラスを明示的に指定したため、JaxBはデフォルトのパッケージ名org.w3._2001.xmlschemaでデフォルトアダプターを生成しません。
デフォルトのパッケージ名org.w3._2001.xmlschemaを使用することを避けることは非常に重要です。 1つの例を挙げて、1つのプロジェクトAと1つのプロジェクトBがあり、両方ともスキーマとバインディングがある場合。古い方法では、どちらもまったく同じ完全な名前のアダプターを生成します。ただし、このアダプターはプロジェクトAで長く、プロジェクトBでは整数の場合、AとBの両方を使用してダウンストリームプロジェクトCがあるとしましょう。これで問題は厄介になります。 Cがadapter1を使用する必要がある場合、使用済みのものは長いAから、または整数のBから予測することはできません。その後、アプリケーションCはしばらくの間正常に動作する可能性がありますが、他の状況では奇妙な方法で失敗する可能性があります。これが発生した場合、タイプの例外は次のようになります。
org.w3._2001.xmlschema.Adapter1 is not applicable to the field type java.lang.Double...
Roy Trueloveが言及したソリューションは、理論が正しい場合でもMaven-Jaxb2-Pluginを使用して環境で試してみたときに機能しないようです。
一般的なデータタイプに組み込まれたコンバーターを使用します。
<jxb:javaType name="java.lang.Integer" xmlType="xs:integer"
parseMethod="javax.xml.bind.DatatypeConverter.parseInt"
printMethod="javax.xml.bind.DatatypeConverter.printInt" />