・JAXB
Java Architecture for XML Binding(Wikipedia)
ということで実装していたのですが、xs:intなXMLのエレメントに文字列や空を渡した場合の挙動が不安定であることが判明。
サーバによって同じ文字列でもパース出来るときと出来ないときがある。
文字列からintへの変換の挙動が環境に依存する。
例えば、こんなXSDを用意。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="hoge">
<xs:complexType>
<xs:sequence>
<xs:element name="fuga" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
こいつをxjcコマンドでコンパイルしてObjectFactoryや以下のようなXMLエンティティを表現するObjectを生成。
@XmlRootElement(name = "hoge")
public class Hoge {
@XmlElement(name = "fuga", required = true)
protected int fuga;
これにXMLを噛ましてパースさせる。
<?xml version="1.0" encoding="utf-8" ?>
<hoge>
<fuga>123</fuga>
</hoge>
Hoge hoge = (Hoge)unmarshaller.unmarshal(reader);
これはまぁ、普通にパースできて、Hoge#fugaに123が入ってくる。
問題は、以下のようなXML
<?xml version="1.0" encoding="utf-8" ?>
<hoge>
<fuga></fuga>
</hoge>
<?xml version="1.0" encoding="utf-8" ?>
<hoge>
<fuga>abc</fuga>
</hoge>
これらをunmarshalするとJAXBExceptionが出る場合と0に変換されてパースされる状況がある。
ローカル(Windows7)で実行するとJAXBException、リモートのWindows Server上で実行すると0に変換。
全く同じソースをデプロイして、さらにはアプリ付きのサーバ(Jetty)ごとリモートに移しても挙動が一致しない。
差異はjavaのバージョンか、Windowsのバージョンぐらいしか思いつかない。。
・java -version
ローカル:1.6.0_21
リモート:1.6.0_23
・OS
ローカル:Windows7
リモート:Win2003Server R2 64bit、Win2008 Server 64bit、32bit
いずれにしてもこれぐらいの差異で環境によって異なる結果を返されると困る。。
Google先生に聞いてみたり、色々ダンプしてみたりと結構調べたのですが、原因が分からず、xs:intな項目を使わない方針に変更。
こんな感じでxs:intからxs:integerに変更
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="hoge">
<xs:complexType>
<xs:sequence>
<xs:element name="fuga" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
@XmlRootElement(name = "hoge")
public class Hoge {
@XmlElement(name = "fuga", required = true)
protected BigInteger fuga;
こうしておくと、文字列などパースできないXMLエレメントは環境に依存せずにnullにパースされてるっぽい。今のところ、、。