JAXB and constructors

爷,独闯天下 提交于 2019-12-28 04:49:26

问题


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.


回答1:


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:

  • http://bdoughan.blogspot.com/2010/12/jaxb-and-immutable-objects.html



回答2:


You can use the annotation @XmlType and use factoryMethod / factoryClass attributes in various combinations such as:

@XmlType(factoryMethod="newInstance")
@XmlRootElement
public class PurchaseOrder {
    @XmlElement
    private final String address;
    @XmlElement
    private final Customer customer;

    public PurchaseOrder(String address, Customer customer){
        this.address = address;
        this.customer = customer;
    }

    private PurchaseOrder(){
        this.address = null;
        this.customer = null;
    }
    /** Creates a new instance, will only be used by Jaxb. */
    private static PurchaseOrder newInstance() {
        return new PurchaseOrder();
    }

    public String getAddress() {
        return address;
    }

    public Customer getCustomer() {
        return customer;
    }
}

Surprisingly this works and you get an initialized instance when unmarshalling. You should make note not to call the newInstance method anywhere on your code as it will return an invalid instance.




回答3:


You should have a default constructor for JAXB to be able to instantiate your classes. Maybe there is a workaround I don't know though.

JAXB is especially fitted for bean-like classes, permitting to configure objects by calling setters on them.




回答4:


JAXB re-creates beans from XML in a simple fashion : it creates a new instance of the bean, and then do all the setXXX needed to set the attributes. So, if your bean doesn't have a no-args constructor, JAXB can't create it. As said in other answers, JAXB works better for simple "container" beans, for which no-args constructor isn't really a problem. If you're trying to create beans that need specific initialization, you'll need to do it in the setXXX methods.



来源:https://stackoverflow.com/questions/4387296/jaxb-and-constructors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!