GroovyでJAXB使うときには@XmlAccessorType( XmlAccessType.NONE ) する

JAXBの感触を確かめようとGroovyで弄ってみたら、ちょこっとハマりました。
さらっとバインディング対象のクラスを書いてマーシャリングしてみようって以下のようなコードを書いたんですが、

import javax.xml.bind.annotation.*
import javax.xml.bind.*

@XmlRootElement
class Foo {
    @XmlAttribute
    String id

    @XmlAttribute
    String name
}

JAXBContext.newInstance(Foo.class).createMarshaller().with {
    setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    
    marshal(new Foo(id:'100', name:'foofoo'), System.out)
}

エラーになります。

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 4 counts of IllegalAnnotationExceptions
groovy.lang.MetaClass is an interface, and JAXB can't handle interfaces.
	this problem is related to the following location:
		at groovy.lang.MetaClass
		at public groovy.lang.MetaClass Foo.getMetaClass()
		at Foo
groovy.lang.MetaClass does not have a no-arg default constructor.
	this problem is related to the following location:
		at groovy.lang.MetaClass
		at public groovy.lang.MetaClass Foo.getMetaClass()
		at Foo
Class has two properties of the same name "id"
	this problem is related to the following location:
		at public java.lang.String Foo.getId()
		at Foo
	this problem is related to the following location:
		at private java.lang.String Foo.id
		at Foo
Class has two properties of the same name "name"
	this problem is related to the following location:
		at public java.lang.String Foo.getName()
		at Foo
	this problem is related to the following location:
		at private java.lang.String Foo.name
		at Foo

idというプロパティが2つ?nameという名前のプロパティが2つ??MetaClassが悪さしてるの???ややこしそうなエラーでした。
で、ちょっと調べてみると…
http://stackoverflow.com/questions/1161147/how-do-i-get-groovy-and-jaxb-to-play-nice-together

The reason it is not working is that each Groovy Class has a metaClass property on it. JAXB is trying to expose this as a JAXB property which obviously fails. Since you don't declare the metaClass property yourself, it is not possible to annotate it to have JAXB ignore it. Instead you and set the XmlAccessType to NONE.

〜中略〜

Example:

@XmlAccessorType( XmlAccessType.NONE )
@XmlRootElement
public class PlayerGroovy {
    @XmlAttribute
    String value
}

「@XmlAccessorType( XmlAccessType.NONE )」て付けてやればmetaClassをマーシャリングしに行かなくなるから良いよって事でした。
早速やってみると…

import javax.xml.bind.annotation.*
import javax.xml.bind.*

@XmlAccessorType( XmlAccessType.NONE )
@XmlRootElement
class Foo {
    @XmlAttribute
    String id

    @XmlAttribute
    String name
}

JAXBContext.newInstance(Foo.class).createMarshaller().with {
    setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    
    marshal(new Foo(id:'100', name:'foofoo'), System.out)
}

実行してみると…

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo name="foofoo" id="100"/>

動いた!てわけで、@XmlAccessorType( XmlAccessType.NONE )重要です。

この@XmlAccessorTypeの記述、XmlTypeにも必要でした。

import javax.xml.bind.annotation.*
import javax.xml.bind.*

@XmlRootElement
@XmlAccessorType( XmlAccessType.NONE )
class Foo {
    @XmlAttribute
    String id
    
    @XmlAttribute
    String name
    
    @XmlElementWrapper
    @XmlElement(name='bar')
    List<Bar> bars = []
}

@XmlType
@XmlAccessorType( XmlAccessType.NONE )
class Bar {
    @XmlAttribute
    String name
}

JAXBContext.newInstance(Foo.class).createMarshaller().with {
    setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    
    marshal(new Foo(id:'100', name:'foofoo', bars:[new Bar(name:'barbar1'), new Bar(name:'barbar2')]), System.out)
}

こんな感じ。