web-dev-qa-db-ja.com

JAXBコンパイラはxs:booleanをブールプリミティブ型ではなくJavaブールラッパークラスにバインドしています

プロジェクトをJAXB1.0からJAXB2.1に移行していますが、データ型のマッピングに問題があります。

Ant xjcバインディングコンパイラを使用しており、(たとえば)xs:dateJavaにマップされるようにグローバルバインディングを正常に構成しました。 util.Calendar

ただし、Booleanが必要なのに対し、booleanを返す生成されたメソッドを取得しています。

複合型は次のとおりです。

<xs:element name="usage-auth-rate-charge">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="service-id" type="xs:string"/>
            <xs:element name="pricepoint_custom_fields_required" type="xs:boolean" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>

そして、生成されたクラスは次のようになります。

public class UsageAuthRateCharge {
........
public Boolean isPricepointCustomFieldsRequired() {
    return pricepointCustomFieldsRequired;
}

問題は、ボクシングは機能しますが、提供されたXMLにpricepoint_custom_fields_requiredの値が含まれていない場合、クラスのブールフィールドがfalseではなくnullになることです。したがって、次のようなことをするとNullPointerExceptions

methodWhichTakesPrimitiveBooleanArg(myUsageAuthRateChargeInstance.isPricepointCustomFieldsRequired());

nullを除いて、渡されたブール値をボックス化解除しようとするためです。


スキーマを変更できず、すべてのクライアントコードを調整してnullチェックを実行できません。

binding.xmloptionalProperty属性を次のように設定しました。

<globalBindings optionalProperty="primitive">

仕様では、「属性の値が「プリミティブ」の場合、JAXB1.0の場合と同じようにバインドされます」と記載されています。

しかし、これは明らかに起こっていません。

どうすればこの問題を解決できますか?

更新:

これはjaxb2.2.9で修正されました: https://Java.net/jira/browse/JAXB/fixforversion/1685

18
mdarwin

開発チームからの修正を待つのに飽きてしまったので、袖をまくり上げて自分でやりました。

これも問題となる人々を助けるために、以下のコードを含めています。

免責事項:私のコードはおそらく問題を解決するための最良の方法ではありませんが、それは私にとってはうまくいきます。

生成されたコードは次のようになります。

public boolean isPricepointCustomFieldsRequired() {
    if (pricepointCustomFieldsRequired == null) {
        return false;
    } else {
        return pricepointCustomFieldsRequired;
    }
}

そして、変更は次のとおりです。

com.Sun.tools.xjc.reader.xmlschema.bindinfo.BIProperty:createElementProperty、行〜358

行の後

types.addTo(prop);

次のコードを挿入します。

if (prop.isOptionalPrimitive() && getOptionalPropertyMode() == OptionalPropertyMode.PRIMITIVE &&
    !prop.getTypes().isEmpty() && "boolean".equals(prop.getTypes().get(0).getTypeName().getLocalPart()) )   {
        prop.defaultValue= CDefaultValue.create(CBuiltinLeafInfo.BOOLEAN, new XmlString("false"));
    }
0
mdarwin

問題

Booleanの代わりにbooleanを取得する理由は、要素定義にminOccurs="0"があるためです。存在しない要素にはnull値が格納されます。

<xs:element name="pricepoint_custom_fields_required" type="xs:boolean" minOccurs="0"/>

解決策はどうあるべきか

解決策は、プリミティブ型をオプションの値に使用する必要があることを示す外部バインディングファイルである必要があります(JAXB 2.2仕様のセクション7.5.1を参照)。

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
    xmlns:jaxb="http://Java.Sun.com/xml/ns/jaxb"
    version="2.1">
    <jaxb:globalBindings optionalProperty="primitive"/>
</jaxb:bindings>

外部バインディングファイルは、XJCで-bオプションを使用して指定されます。

xjc -b binding.xml my-schema.xsd

そのソリューションが機能しない理由

optionalProperty="primitive"の問題を追跡するために、次のバグが開かれています。

Workaround

JAXBでクラスが生成される方法が気に入らない場合は、自分でクラスを作成し、それをスキーマの一部としてクラス生成に引き込むことができます。

binding.xml

<jxb:bindings 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://Java.Sun.com/xml/ns/jaxb"
    version="2.1">

    <jxb:bindings schemaLocation="my-schema.xsd">
        <jxb:bindings node="//xs:element[@name='usage-auth-rate-charge']/complexType">
            <jxb:class ref="com.example.foo.UsageAuthRateCharge"/>
        </jxb:bindings>
    </jxb:bindings>
</jxb:bindings>

UsageAuthRateCharge

必要に応じてメソッドを使用してこのクラスを作成します。

XJC呼び出し

XJC呼び出しで-bフラグを使用して、binding.xmlファイルを指定します

xjc -b binding.xml my-schema.xsd

更新

私が本当に望んでいたのは、読者の1人がjaxbで簡単に変更を行えるjaxb開発チームのメンバーである可能性があるということでした。ユーザーarchenrootは、jaxb問題927(926の複製)に関するコメントで可能な解決策を提供しました。これにより、適切な人にとって、jaxbを修正するのは簡単な仕事になると思います。

私は EclipseLink JAXB(MOXy) リードです。 JAXBリファレンス実装を行っている同僚に連絡しました(彼らはOracleでも機能します)。以下は私が彼らから得た返事です:

トランクでテストしましたが、問題があります。コードをチェックして、修正がいかに簡単かを確認します。

うまくいけば、この問題の実際の修正を取得できるようになります。

27
bdoughan

これを試して...

<xs:element name="usage-auth-rate-charge">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="service-id" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="chosen" type="xs:boolean" use="required"/>
    </xs:complexType>
</xs:element>

あなたがやっていたのとは正反対のことをする方法を探していたときに、あなたの質問を見つけました。プリミティブブール値として属性を持つコードのみを生成するブール属性がありました。 jaxbにこの属性をブールプリミティブではなくブールオブジェクトとして生成させるために、xsdの属性定義のuse = "required"部分を削除しました。

3
twindham

完成させるためだけに

type="xs:boolean" minOccurs="0" maxOccurs="1"                   == Boolean value (object)

type="xs:boolean" minOccurs="0" maxOccurs="1" nillable="true"   == JAXBElement<Boolean> value (object)

type="xs:boolean" minOccurs="1" maxOccurs="1"                   == boolean value (primitive)

type="xs:boolean" minOccurs="1" maxOccurs="1" nillable="true"   == Boolean value (object)
1