29

我开始学习 JAXB,所以我的问题可能非常愚蠢。现在我有类并且想要生成 XML 模式。遵循条指令,我得到了异常

IllegalAnnotationExceptions ... 没有无参数默认构造函数。

是的。我的类没有默认的无参数构造函数。这太容易了。我有带有包可见构造函数/最终方法的类,并且带有参数。我该怎么办 - 创建一些特定的 momemto/builder 类或将我的构造函数指定给 JAXB(以什么方式?)?谢谢。

4

4 回答 4

42

JAXB 可以使用 XML 适配器支持这种情况。考虑您有以下没有零参数构造函数的对象:

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;
    }

}

您只需要创建此类的可映射版本:

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;
    }

}

以及在它们之间进行转换的 XML 适配器:

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;
    }

}

然后对于引用 Customer 类的属性,只需使用 @XmlJavaTypeAdapter 注释:

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;
    }

} 

有关更详细的示例,请参见:

于 2010-12-08T12:42:18.380 回答
15

您可以使用注解@XmlType并以各种组合使用 factoryMethod / factoryClass 属性,例如:

@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;
    }
}

令人惊讶的是,这很有效,并且在解组时您会得到一个初始化的实例。您应该注意不要newInstance在代码的任何地方调用该方法,因为它会返回一个无效的实例。

于 2011-07-14T22:43:00.737 回答
5

您应该有一个 JAXB 的默认构造函数,以便能够实例化您的类。也许有一个我不知道的解决方法。

JAXB 尤其适用于类 bean 类,允许通过在对象上调用 setter 来配置对象。

于 2010-12-08T12:26:48.130 回答
3

JAXB 以一种简单的方式从 XML 重新创建 bean:它创建 bean 的一个新实例,然后执行setXXX设置属性所需的所有操作。因此,如果您的 bean 没有无参数构造函数,则 JAXB 无法创建它。正如在其他答案中所说,JAXB 更适用于简单的“容器”bean,对于这些 bean,无参数构造函数并不是真正的问题。如果您尝试创建需要特定初始化的 bean,则需要在setXXX方法中进行。

于 2010-12-08T12:30:57.007 回答