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

Simple HBase ORM

When dealing with data stored in HBase, you are quick to come to a conclusion, that it is extremaly inconvenient to reach to it via HBase native API. It is very verbose and you always need to convert between bytes and simple types - a pain. While I wa...When dealing with data stored in HBase, you are quick to come to a conclusion, that it is extremaly inconvenient to reach to it via HBase native API. It is very verbose and you always need to convert between bytes and simple types - a pain. While I wa...

HISE

HISE stands for Human Interactions Service Engine.I have recently posted a proposal, which was accepted by Apache ODE PMC, which means the development will start soon.If you are interested in this project, you are welcome to join us.HISE stands for Human Interactions Service Engine.I have recently posted a proposal, which was accepted by Apache ODE PMC, which means the development will start soon.If you are interested in this project, you are welcome to join us.