Search code examples
javaconstructorjaxbcreation

JAXB and constructors


I'm starting learning JAXB, so my question can be very silly. Now I have classes and want generate XML Schema. Going after this instruction I get exception

IllegalAnnotationExceptions ... does not have a no-arg default constructor.

Yeah. My classes haven't default no-arg constructors. It's too easy. I have classes with package visible constructors / final methods and off course with arguments. What shall I do - create some specific momemto/builder classes or specify my constructors to JAXB (in what way?) ? Thanks.


Solution

  • JAXB can support this case using an XML Adapter. Consider you have the following object with no zero-arg constructor:

    package blog.immutable;
    
    public class Customer {
    
        private final String name;
        private final Address address;
    
        public Customer(String name, Address address) {
            this.name = name;
            this.address = address;
        }
    
        public String getName() {
            return name;
        }
    
        public Address getAddress() {
            return address;
        }
    
    }
    

    You simply need to create a mappable version of this class:

    package blog.immutable.adpater;
    
    import javax.xml.bind.annotation.XmlAttribute;
    import blog.immutable.Address;
    
    public class AdaptedCustomer {
    
        private String name;
        private Address address;
    
        @XmlAttribute
        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;
        }
    
    }
    

    And an XML Adapter to convert between them:

    package blog.immutable.adpater;
    
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    import blog.immutable.Customer;
    
    public class CustomerAdapter extends XmlAdapter<AdaptedCustomer, Customer> {
    
        @Override
        public Customer unmarshal(AdaptedCustomer adaptedCustomer) throws Exception {
            return new Customer(adaptedCustomer.getName(), adaptedCustomer.getAddress());
        }
    
        @Override
        public AdaptedCustomer marshal(Customer customer) throws Exception {
            AdaptedCustomer adaptedCustomer = new AdaptedCustomer();
            adaptedCustomer.setName(customer.getName());
            adaptedCustomer.setAddress(customer.getAddress());
            return adaptedCustomer;
        }
    
    }
    

    Then for properties that refer to the Customer class, simply use the @XmlJavaTypeAdapter annotation:

    package blog.immutable;
    
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import blog.immutable.adpater.CustomerAdapter;
    
    @XmlRootElement(name="purchase-order")
    public class PurchaseOrder {
    
        private Customer customer;
    
        @XmlJavaTypeAdapter(CustomerAdapter.class)
        public Customer getCustomer() {
            return customer;
        }
    
        public void setCustomer(Customer customer) {
            this.customer = customer;
        }
    
    } 
    

    For a more detailed example see: