JAXB和构造函数

Sta*_*lin 28 java constructor creation jaxb

我开始学习JAXB,所以我的问题可能非常愚蠢.现在我有类并希望生成XML Schema.遵循条指令,我得到了例外

IllegalAnnotationExceptions ...没有no-arg默认构造函数.

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

bdo*_*han 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

然后,对于引用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;
    }

} 
Run Code Online (Sandbox Code Playgroud)

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

  • 请不要直接复制链接,解释答案中的基础知识,并最终链接到博客文章,如果需要更多解释.这样,如果链接丢失,我们仍然会得到答案. (3认同)
  • 我同意不只是复制链接.这个答案是在我上班途中通过手机发布的.当我在电脑前时,我会提供更多细节.如果有帮助,链接到我自己的博客 (2认同)

Raf*_*l M 14

您可以使用注释@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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 创建公共方法将使任何人都可以访问它,而不仅仅是JAXB,这可能会破坏您的设计,并对设计时引入的字段进行无效和约束.我不推荐这个解决方案! (3认同)
  • 您可以将修饰符更改为"protected"或"private".所以你的设计不会完全被破坏. (3认同)

Gui*_*ume 5

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

JAXB特别适合类似bean的类,允许通过调用它们上的setter来配置对象.

  • 如果JAXB可以创建您的对象,那么它不是不可变的.JAXB无法猜测要使用哪个构造函数,因为构造函数中可能的其他操作可能导致错误的对象. (2认同)