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

HISE home page

Apache HISE has recenlty kickstarted and has a home page here: http://incubator.apache.org/hise/index.html.Apache HISE is Human Interactions Service Engine. It's an open source implementation of WS HumanTask specification.HISE proposal can be found her...Apache HISE has recenlty kickstarted and has a home page here: http://incubator.apache.org/hise/index.html.Apache HISE is Human Interactions Service Engine. It's an open source implementation of WS HumanTask specification.HISE proposal can be found her...

Mock Retrofit using Dagger and Mockito

Retrofit is one of the most popular REST client for Android, if you never use it, it is high time to start. There are a lot of articles and tutorial talking about Retrofit. I just would like to show how to mock a REST server during develop of app and i...Retrofit is one of the most popular REST client for Android, if you never use it, it is high time to start. There are a lot of articles and tutorial talking about Retrofit. I just would like to show how to mock a REST server during develop of app and i...