@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 = 'John Smith 20 '
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.
No comments:
Post a Comment