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