Java Model
CustomerFactory
We will use a factory class to create instances of Customer. The factory class must have a public, static, zero-argument method that returns an instance of the desired domain object.
package blog.factory;
import java.util.Date;
public class CustomerFactory {
public static Customer createCustomer() {
return new Customer(new Date());
}
}
Customer
We configure the Customer class to be instantiated using CustomerFactory via the @XmlType annotation.
package blog.factory;
import java.util.Date;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement
@XmlType(
propOrder={"name", "address", "phoneNumbers"},
factoryClass=CustomerFactory.class,
factoryMethod="createCustomer")
public class Customer {
private String name;
private Address address;
private List<PhoneNumber> phoneNumbers;
private Date createTime;
public Customer(Date time) {
this.createTime = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@XmlElement(name="phone-number")
public List<PhoneNumber> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
Address
If we use the @XmlType annotation to specify a factoryMethod, without a factoryClass, then the JAXB implementation will look for the method on the domain class.
package blog.factory;
import java.util.Date;
import javax.xml.bind.annotation.XmlType;
@XmlType(factoryMethod="createAddress")
public class Address {
private String street;
private Date createTime;
public Address(Date time) {
this.createTime = time;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public static Address createAddress() {
return new Address(new Date());
}
}PhoneNumber
If a factory method is not specified then JAXB will use the no-argument constructor. This is the default behaviour.
package blog.factory;
import javax.xml.bind.annotation.XmlValue;
public class PhoneNumber {
private String value;
@XmlValue
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}Demo Code
The following code can be used to run this example. The different instantiation mechanisms will be leveraged during the unmarshal operation.
package blog.factory;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/blog/factory/input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
XML Input (input.xml)
Below is the XML that will be unmarshalled.
Below is the XML that will be unmarshalled.
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<name>Jane Doe</name>
<address>
<street>123 A Street</street>
</address>
<phone-number>555-1111</phone-number>
<phone-number>555-2222</phone-number>
</customer>Further Reading
If you enjoyed this post, you may also be interested in:
My goodness, I spent the last several hours looking in vain for clues as to how to get my factory method to work, until I finally read this. Thank you!
ReplyDelete