@XmlRegistry - how does it work?
@XmlRegistry - how does it work?
@XmlRegistry
is used to mark a class that has @XmlElementDecl
annotations. To have your JAXB implementation process this class you need to ensure that it is included in the list of classes used to bootstrap the JAXBContext
. It is not enough for it to be a static inner class of one of your domain model classes:
JAXBContext context = JAXBContext.newInstance(Employee.class, Employee.XMLObjectFactory.class);
@XmlElementDecl - how does it work?
If the value of the field/property is going to be a JAXBElement
then you need to leverage @XmlElementDecl
. A JAXBElement
captures information that is can be useful:
- Element name, this is necessary if you are mapping to a choice structure where multiple elements are of the same type. If the element name does not correspond to a unique type then you would not be able to round-trip the document.
JAXBElement
can be used to represent an element withxsi:nil="true"
.
XmlObjectFactory
@XmlElementDecl
also allows you to specify a scope. I have modified the model from you post a bit. I have introduced an XmlObjectFactory
class that has two @XmlElementDecl
. Both specify a name of address
. I have leveraged the scope
property so that for properties within the Employee
class the @XmlElementDecl
corresponding to the Address
class with be used.
package forum11078850;import javax.xml.bind.JAXBElement;import javax.xml.bind.annotation.XmlElementDecl;import javax.xml.bind.annotation.XmlRegistry;import javax.xml.namespace.QName;@XmlRegistrypublic class XmlObjectFactory { @XmlElementDecl(scope = Employee.class, name = "address") JAXBElement<Address> createAddress(Address value) { return new JAXBElement<Address>(new QName("address"), Address.class, value); } @XmlElementDecl(name = "address") JAXBElement<String> createStringAddress(String value) { return new JAXBElement<String>(new QName("address"), String.class, value); }}
Employee
The @XmlElementRef
annotation will cause the value of the property to be matched on its root element name. Possible matches will include classes mapped with @XmlRootElement
or @XmlElementDecl
.
package forum11078850;import java.util.List;import javax.xml.bind.JAXBElement;import javax.xml.bind.annotation.*;@XmlRootElement@XmlType(propOrder = { "id", "name", "email", "addresses" })public class Employee { private int id; private String name; private String email; private List<JAXBElement<Address>> addresses; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @XmlElementWrapper @XmlElementRef(name="address") public List<JAXBElement<Address>> getAddresses() { return addresses; } public void setAddresses(List<JAXBElement<Address>> addresses) { this.addresses = addresses; }}
ObjectFactoryTest
package forum11078850;import java.io.FileReader;import javax.xml.bind.*;public class ObjectFactoryTest { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("src/forum11078850/input.xml"); JAXBContext context = JAXBContext.newInstance(Employee.class, XmlObjectFactory.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Object obj = unmarshaller.unmarshal(reader); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(obj, System.out); }}
The Address
class and input.xml
from my original answer can be used to run this example.
ORIGINAL ANSWER
I'm not sure how you are attempting to use @XmlRegistry
, so I will focus on the following part of your post:
When I unmarshal the employee xml using above code, the address list does not get populated. The resulting employee object only has a blank list of adresses. Is there anything wrong with my mappings?
Your list of Address
objects is wrapped in a grouping element (addresses
), so you need to use the @XmlElementWrapper
annotation to map this use case. Below is a complete example:
Employee
package forum11078850;import java.util.List;import javax.xml.bind.annotation.*;@XmlRootElement@XmlType(propOrder = { "id", "name", "email", "addresses" })public class Employee { private int id; private String name; private String email; private List<Address> addresses; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @XmlElementWrapper @XmlElement(name = "address") public List<Address> getAddresses() { return addresses; } public void setAddresses(List<Address> addresses) { this.addresses = addresses; }}
Address
package forum11078850;public class Address { private String addressLine1; private String addressLine2; private String addressLine3; public String getAddressLine1() { return addressLine1; } public void setAddressLine1(String addressLine1) { this.addressLine1 = addressLine1; } public String getAddressLine2() { return addressLine2; } public void setAddressLine2(String addressLine2) { this.addressLine2 = addressLine2; } public String getAddressLine3() { return addressLine3; } public void setAddressLine3(String addressLine3) { this.addressLine3 = addressLine3; }}
ObjectFactoryTest
package forum11078850;import java.io.FileReader;import javax.xml.bind.*;public class ObjectFactoryTest { public static void main(String[] args) throws Exception { FileReader reader = new FileReader("src/forum11078850/input.xml"); JAXBContext context = JAXBContext.newInstance(Employee.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Object obj = unmarshaller.unmarshal(reader); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(obj, System.out); }}
input.xml/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><employee> <id>1</id> <name>Vaishali</name> <email>Vaishali@example.com</email> <addresses> <address> <addressLine1>300</addressLine1> <addressLine2>Mumbai</addressLine2> <addressLine3>India</addressLine3> </address> <address> <addressLine1>301</addressLine1> <addressLine2>Pune</addressLine2> <addressLine3>India</addressLine3> </address> </addresses></employee>