私の質問は、文字列が空だがnullでない場合にJAXBで空のタグをマーシャリングするのを防ぐ方法に非常に似ています
違いは、ビルドごとにすべての JAXB タイプがスキーマから生成されるため、package-info.java にアノテーションを追加できないことです。また、可能であれば JAXB プロバイダーを変更したくありません。
私が達成したいのは、空の文字列を設定しても要素が作成されないということですが、多くのスキーマから生成されたすべての JAXB タイプに対してこれを設定する必要があります。生成されたすべての JAXB クラスのすべての文字列フィールドにこれを適用する方法はありますか?
更新 次の変更を加えることで、スキーマ内のすべての文字列に対して XML アダプターを生成することができました。
プロジェクト POM で、これを maven-jaxb2-plugin に追加しました。
<bindingDirectory>src/main/resources</bindingDirectory>
<bindingIncludes>
<include>bindings.xjb</include>
</bindingIncludes>
そして、ここに私の bindings.xjb ファイルがあります:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jxb:globalBindings>
<jxb:javaType name="java.lang.String" xmlType="xs:token"
parseMethod="com.project.Formatter.parseString"
printMethod="com.project.Formatter.printString"/>
</jxb:globalBindings>
</jxb:bindings>
そしてフォーマット方法:
public static String printString(final String value)
{
if (StringUtils.isBlank(value))
{
return null;
}
return value;
}
問題は、これにより JAXB の奥深くで Null Pointer Exception が発生することです。スタックトレースは次のとおりです。
Caused by: java.lang.NullPointerException
at com.sun.xml.bind.v2.runtime.output.SAXOutput.text(SAXOutput.java:158)
at com.sun.xml.bind.v2.runtime.XMLSerializer.leafElement(XMLSerializer.java:321)
at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:210)
at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl$1.writeLeafElement(RuntimeBuiltinLeafInfoImpl.java:209)
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor$CompositeTransducedAccessorImpl.writeLeafElement(TransducedAccessor.java:250)
at com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.serializeBody(SingleElementLeafProperty.java:98)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
at com.sun.xml.bind.v2.runtime.property.ArrayElementNodeProperty.serializeItem(ArrayElementNodeProperty.java:65)
at com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:168)
at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:152)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:322)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:681)
at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:150)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:156)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl$1.serializeBody(ElementBeanInfoImpl.java:185)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeBody(ElementBeanInfoImpl.java:305)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:312)
at com.sun.xml.bind.v2.runtime.ElementBeanInfoImpl.serializeRoot(ElementBeanInfoImpl.java:71)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:490)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:257)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:103)
この問題の原因は、次の方法に要約されます。
com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.CompositeTransducedAccessorImpl.hasValue(BeanT)
上記のメソッドは、アダプターが実行される前に値が null でない場合に要素をレンダリングします。
要素をレンダリングするかどうかを決定する前にアダプターを実行するように、JAXB で使用されるアクセサーをオーバーライドする方法はありますか? 私が望むものを達成する別の方法はありますか?