Below is the model (Customer & Address) we'll use, the get/set methods have been omitted to simplify the example.
Customer
public class Customer { private Address billingAddress; private Address shippingAddress; }
Address
public class Address { private String street; }
jaxb.properties
We will add a jaxb.properties file in with our model classes to specify that MOXy should be used as our JAXB implementation. The file must have the following content:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Customer.class); Customer customer = new Customer(); Address billingAddress = new Address(); billingAddress.setStreet("1 Billing Street"); customer.setBillingAddress(billingAddress); Address shippingAddress = new Address(); shippingAddress.setStreet("2 Shipping Road"); customer.setShippingAddress(shippingAddress); Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.marshal(customer, System.out); } }
Standard JAXB Runtime
Using standard JAXB annotations:
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { private Address billingAddress; private Address shippingAddress; }
We can easily produce the following output using our Demo class:
<customer> <billingAddress> <street>1 Billing Street</street> </billingAddress> <shippingAddress> <street>2 Shipping Road</street> </shippingAddress> </customer>
Using MOXy to Add a Grouping Element
Sometimes grouping elements are added to your document to organize data. JAXB has this concept for collection properties in the form of @XmlElementWrapper. Here we'll use @XmlPath for non-collection properties, In this case we'll nest the billing/shipping address data within the "contact-info" element.
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlPath("contact-info/billing-address") private Address billingAddress; @XmlPath("contact-info/shipping-address") private Address shippingAddress; }
Now if we run our Demo class we will get the following output:
<customer> <contact-info> <billing-address> <street>1 Billing Street</street> </billing-address> <shipping-address> <street>2 Shipping Road</street> </shipping-address> </contact-info> <customer>
Using MOXy to Map by Position
Normally in JAXB elements with the same name must be mapped to a collection property. Using MOXy's path based mapping you map non-collection properties to a repeated element by index.
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlPath("address[1]") private Address billingAddress; @XmlPath("address[2]") private Address shippingAddress; }
Running the Demo class will produce the following output, notice how both address properties map to the "address" elements:
<customer> <address> <street>1 Billing Street</street> </address> <address> <street>2 Shipping Road</street> </address> </customer>
Using MOXy to Map Two Objects to the Same Node
We have seen how MOXy can be used to expand the structure by adding a grouping element. MOXy can also be used to collapse the structure by mapping two objects to the same node. Again this is done using @XmlPath.
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlPath(".") private Address billingAddress; private Address shippingAddress; }
Running the Demo class one more time produces the following XML. Notice how the street element corresponding to the billing address now appears under the customer element.
<customer> <street>1 Billing Street</street> <shippingAddress> <street>2 Shipping Road<street> </shippingAddress> </customer>
Further Reading
If you enjoyed this post you may also be interested in:
HI Blaise,
ReplyDeleteJust while searching for Jaxb related topics, stumbled upon ur blog and it is really very informative.. Thanks for the same.. :)
I am new to Web Services[Soap,wsdl,xml] etc.. Could you please post more articles on
[a]how to determine xpath,
[b]how to parse xml,
[c]how to marshal and unmarshal objects in java,
[d] Jaxb binding..
I mean could you please elaborate your writing on various such 'basics' so that it would be very helpful for beginners like us..
Thanks,
NSP.
@XmlPath annotation is not working. help me out from this. what should i do for that??
ReplyDeleteHave you properly specified EclipseLink JAXB (MOXy) as your JAXB provider?
ReplyDelete- Specifying EclipseLink MOXy as Your JAXB Provider
Also what environment are you running in? The following may help if you are using GlassFish:
- Creating a RESTful Web Service - Part 3/5
-Blaise
Hi Blaise,
ReplyDeletewhen using @XmlPath(".") is there a way to
a) rename the elements, in your example "billingAdressStreet" instead of "street"
b) specify which bean properties of the referenced object should be mapped to XML (without changing the referenced class - in your example Address - itself)?
Thanks,
Uli