This is not going to be an entry of JAXB specially when there are hundreds of blog entries and even books covering the topic widely.
I'm going to create a very simple example to unmarshall a given object instance to XML. So here we have the XML source
Don Xijote Manuel De Cervantes Catcher in the Rye JD Salinger Alice in Wonderland Lewis Carroll Don Xijote Manuel De Cervantes
Before doing anything, just remind you that the code is available at Github.
And now we should be creating the classes which are going to map the XML fragments in which I'm interested.
- Author
package github.groovy.xml.jaxb import javax.xml.bind.annotation.* @XmlRootElement(name="author") @XmlAccessorType(XmlAccessType.FIELD) class Author{ @XmlAttribute Long id @XmlElement String name }
- Book
package github.groovy.xml.jaxb import javax.xml.bind.annotation.* @XmlRootElement(name="book") @XmlAccessorType(XmlAccessType.FIELD) class Book{ @XmlAttribute Long id @XmlElement String title @XmlElement Author author }
Basically I'm using the following annotations:
- @XmlRootElement: for be able to marshal the object without having to include it in a another object having this annotation. Only objects annotated with this annotation can be marshaled directly.
- @XmlAccessorType(XmlAccessType.FIELD): Because we're using Groovy, and there is "a lot of magic" at runtime you should tell JAXB to stick to the fields, otherwise it will try to unmarshall crazy things.
- @XmlElement: To tell JAXB what's going to be a tag element
- @XmlAttribute: To tell JAXB what's going to be an attribute element
Unmarshalling (XML --> Object)
Well let's say we have an XML full of books and authors and we want to unmarshal them into objects. If we wanted to unmarshall the XML above to get only books and authors, we should pre-process the XML to get rid of the response/data tags. And only then unmarshal the remaining XML.
So the previous code becomes:
import javax.xml.bind.* //...Omitted code def "Unmarshalling the first book with boilerplate code"(){ setup: "Building the unmarshaller" def jaxbContext= JAXBContext.newInstance(Book) def unmarshaller = jaxbContext.createUnmarshaller() and: "Filtering the xml" def response = new XmlSlurper().parse(xmlFile) and: "Getting only the first book" def firstBook = response.'**'.find{it.name() =='book'} def jaxbSource= XmlUtil.serialize(firstBook) def newXmlSource = new StringReader(jaxbSource) when: "Unmarshalling the source" def jaxbBook = unmarshaller.unmarshal(newXmlSource) then: "We make sure the conversion took place" jaxbBook instanceof Book and: "Checking Book properties" jaxbBook.title jaxbBook.author jaxbBook.author.id }I've created an utility class to avoid most of the repeated code when creating a Marshaller/Unmarshaller:
package github.groovy.xml.jaxb import javax.xml.bind.* import github.groovy.xml.util.ResourcesUtil /** * This class helps us to handle marshalling and unmarshalling of JAXB objects **/ class JaxbUtils { def object2MarshalType def source2Unmarshall def marshal(object){ object2MarshalType = object.getClass() this } def to(File file){ throwIfNull(object2Marshal) throwIfNull(file) buildMarshaller(object2MarshalType).marshal(object2MarshalType,file) } def unmarshal(source){ source2Unmarshall = source this } def to(Class anyType){ throwIfNull(source2Unmarshall) throwIfNull(anyType) buildUnmarshaller(anyType).unmarshal(source2Unmarshall) } def buildMarshaller(Class type){ def jaxbContext= JAXBContext.newInstance(type) def marshaller = jaxbContext.createMarshaller() marshaller } def buildUnmarshaller(Class type){ def jaxbContext= JAXBContext.newInstance(type) def unmarshaller = jaxbContext.createUnmarshaller() unmarshaller } def throwIfNull(value,message="You should have provided any value"){ if (!value){ throw new Exception(message) } } }
So the previous code becomes:
def "Unmarshalling the first book the good way"(){ setup: "Parsing the document" def response = new XmlSlurper().parse(xmlFile) and: "Getting only the first book" def firstBook = response.'**'.find{it.name() =='book'} def jaxbSource= XmlUtil.serialize(firstBook) when: "Convert to Jaxb object" def newXmlSource = new StringReader(jaxbSource) def jaxbBook = unmarshal(newXmlSource).to(Book) then: "We make sure the conversion took place" jaxbBook instanceof Book and: "Checking Book properties" jaxbBook.title jaxbBook.author jaxbBook.author.id }
Marshalling (Object --> XML)
I was a little bit lazy and I didn't build any example for marshalling an object to XML. Maybe I will update this entry later on with a working example.
Resources
- JAXB Official Page: http://jaxb.java.net
- I found this entry using Groovy, JAX-WS and JAXB altogether, highly advisable: http://weblogs.java.net/blog/lamineba/archive/2012/05/20/building-restful-web-services-jax-rs-jaxb-and-groovy
I have a Xml which i am not able to marshall these is:
ReplyDelete30
121
STATUSCODE
Delete20
DISPLAYID
30
DISPLAYID
STATUSCODE