I have found some examples of JAXB2 @XmlRegistry
over the internet but no good in-depth tutorials that talk about the concept of using @XmlRegistry
wit
You have to take a List object of Address. In that object, you will have to add the object which contains data like addressline1. addressline2 and so on.
i.e.
List addrObjList = new List();
addrObjList.add(object); // Bind an object containing data and add one by one
@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:
JAXBElement
can be used to represent an element with xsi: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;
@XmlRegistry
public 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>