@XMLRootElementや@XMLAttributeなどのアノテーションや設定値は、XML Schemaと対応する。
XML Schemaについて触りを掴んでおくと、トラブルシューティングしやすい。
@XmlAccessTypeに指定できるNONE/FIELD/PROPERTY/PUBLIC_MEMBERを意識する。
適当に@XmlElementとかを付けると「Class has two properties of the same name」のようなエラーに頭を悩ませることになる…。
- NONE
- 明示的に@XmlElement/@XmlAttributeを指定したフィールドのみがバインド対象
- FIELD
- 何も指定がないフィールドは、基本的に@XmlElementが指定されたものとして扱われ、明示的にバインド対象外とするには@XmlTransientを指定する。
- PROPERTY
- @XmlElement/@XmlAttributeを指定したフィールドのみがバインド対象。
- PUBLIC_MEMBER
- 何も指定がないフィールドは、基本的にバインド対象外となる。getter/setterがあるフィールドや@XmlElement/@XmlAttributeがあるフィールドはバインド対象になる。getter/setterがあり、かつ、@XmlElement/@XmlAttributeがあるフィールドはエラー。
なんかデフォルトがPROPERTYになっていた方が余計な混乱がない気もするけど、煩雑になるのかな…。
getter/setterのメソッド名、getterの戻り値/setterの引数の型は対応が取れていないとバインド対象として認識されない。なんかこの挙動を逆手に取るとうまいことできるかも。
使ってみて起きた他のエラーとしては、バインド対象のフィールドのクラスはデフォルトコンストラクタを持っていないとならないってのがあったんだけど、これはたまにネックかな。
@XmlTransientをつけると、getter/setterがあってもそのフィールドはバインド対象にならない、ってのを覚えておこう。
あとは、ちゃんとマーシャリングできるかを確認するためのソースコード
JAXBContext context = JAXBContext.newInstance(Book.class); StringWriter writer = new StringWriter(); context.createMarshaller().marshal(book, writer); System.out.println(writer.toString());
JAX-RSを使ったアプリケーションで、XMLやJSONなどの変換を意識しなくて済むのは非常にありがたいけど、ユニットテストレベルで不正なアノテーション指定によりマーシャリングできない可能性は潰しておきたい。