基本問題
空String
はその型の有効な値ではありませんxsd:date
。XML スキーマで有効にするには、オプションの要素を存在しないノードとして表す必要があります。
根本的な問題があなたに影響を与えている理由
すべての JAXB 実装は、空String
が の有効な値ではないことを認識しますxsd:date
。のインスタンスに報告することでこれを行いますValidationEventHandler
。これは、次のようにして自分で確認できます。
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
@Override
public boolean handleEvent(ValidationEvent event) {
System.out.println(event);
return true;
}
});
使用している JAX-WS の実装は、EclipseLink MOXyを JAXB プロバイダーとして活用します。また、MOXy を使用しているバージョンでは、参照実装のようValidationEvent
に重大度ERROR
が検出されると、デフォルトで例外がスローされます。FATAL_ERROR
これは、次のバグで修正されています。
回避策
JAXB API を直接使用している場合は、単純にデフォルトをオーバーライドできますValidationEventHandler
。JAX-WS 環境では、XmlAdapter
を使用してカスタム変換ロジックを提供できます。を活用して、XmlAdapter
との間の変換の処理方法をオーバーライドしますDate
。
XmlAdapter (日付アダプター)
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class DateAdapter extends XmlAdapter<String, Date>{
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date unmarshal(String v) throws Exception {
if(v.length() == 0) {
return null;
}
return dateFormat.parse(v);
}
@Override
public String marshal(Date v) throws Exception {
if(null == v) {
return null;
}
return dateFormat.format(v);
}
}
Java モデル (ルート)
は注釈XmlAdapter
を使用して参照されます。@XmlJavaTypeAdapter
これXmlAdapter
を のすべてのインスタンスに適用する場合はDate
、パッケージ レベルで登録できます ( http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.htmlを参照)。
import java.util.Date;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlSchemaType(name = "date")
@XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
private Date abc;
@XmlSchemaType(name="date")
@XmlJavaTypeAdapter(value=DateAdapter.class, type=Date.class)
private Date qwe;
}
デモコード
以下は、すべてが機能することを確認するために実行できるスタンドアロンの例です。
jaxb.properties
jaxb.propeties
MOXy を JAXB プロバイダーとして使用するスタンドアロンの例では、次のエントリを使用して、ドメイン モデルと同じパッケージで 呼び出されるファイルを含める必要があります( http://blog.bdoughan.com/2011/05/specifying-eclipselinkを参照)。 -moxy-as-your.html )。
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
入力.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<abc></abc>
<qwe>2013-09-05</qwe>
</root>
デモ
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum18617998/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
出力
マーシャリングされた XML では、Date
null だったフィールドが存在しない要素としてマーシャリングされていることに注意してください ( http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.htmlを参照)。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<qwe>2013-09-05</qwe>
</root>