Writing JAXB in Groovy

Suppose you want write a jaxb class in groovy. Why? Because you do not have to write these all getters, setters and other methods. You only have to write your fields down.@XmlRootElement@HashCodeAndEquals@ToStringclass Person { String firstName String …

Suppose you want write a jaxb class in groovy. Why? Because you do not have to write these all getters, setters and other methods. You only have to write your fields down.

@XmlRootElement 
@HashCodeAndEquals 
@ToString 
class Person {
    String firstName String lastName Integer age
}

 

Lets check if we could unmarshal xml to Person class:

def 'should unmarshall person xml to object'(){
    given:
        JAXBContext jc = JAXBContext.newInstance(Person)
        String xml = 'JohnSmith20' 
    expect:
        jc.createUnmarshaller().unmarshal(new StringReader(xml)) == new Person(firstName: 'John', lastName: 'Smith', age: 20)
}

 

When we try this, then we obtain an eception:

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 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 com.blogspot.przybyszd.jaxbingroovy.Person.getMetaClass()
  at com.blogspot.przybyszd.jaxbingroovy.Person

 at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:445)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:277)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:124)
 at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1123)
 at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:147)
 at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247)
 at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234)
 at javax.xml.bind.ContextFinder.find(ContextFinder.java:462)
 at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
 at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
 at com.blogspot.przybyszd.jaxbingroovy.PersonJaxbTest.should unmarshall person xml to object(PersonJaxbTest.groovy:10)

It is because groovy defines getMetaClass method for us. Marshaller and Unmarshaller use by default

XmlAccessType.PUBLIC_MEMBER what means that public getters and setters should be used during marshalling/unmarshalling. To solve this just add XmlAccessorType annotatnio with XmlAccessType.FIELD on jaxb class:

@XmlRootElement @EqualsAndHashCode @XmlAccessorType(XmlAccessType.FIELD) class Person {
    String firstName String lastName Integer age
}

 

Of course if you want to apply this rule for each jaxb class in package, then you could put XmlAccessorType in pacakge-info.java file.

@XmlAccessorType(XmlAccessType.FIELD) package com.blogspot.przybyszd.jaxbingroovy;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

 

Great, it works. Now let’s check out marshaller:

def 'should marshall person'() {
    given:
        JAXBContext jc = JAXBContext.newInstance(Person)
        Person p = new Person(firstName: 'John', lastName: 'Smith', age: 20)
        StringWriter sw = new StringWriter()
    when:
        jc.createMarshaller().marshal(p, sw)
    then:
        String xml = sw.toString()
        GPathResult gPathResult = new XmlSlurper().parseText(xml)
        gPathResult.name() == 'person'
        gPathResult.firstName == 'John'
        gPathResult.lastName == 'Smith'
        gPathResult.age == '20'
}

 

And it also works. Source is available here.

You May Also Like

micro-burn has Trello integration

After a few long evenings I've finally integrated micro-burn with Trello. All you need to run it for your Trello board is to write short configuration and run fat jar. It renders burndown chart visualising progress of cards on your board.You can specif...After a few long evenings I've finally integrated micro-burn with Trello. All you need to run it for your Trello board is to write short configuration and run fat jar. It renders burndown chart visualising progress of cards on your board.