Java JAXB 和构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4387296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 16:48:56  来源:igfitidea点击:

JAXB and constructors

javaconstructorjaxbcreation

提问by Stan Kurilin

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

我开始学习 JAXB,所以我的问题可能很愚蠢。现在我有课程并且想要生成 XML 模式。之后前往这个指令我得到异常

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

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

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.

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

采纳答案by bdoughan

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

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

}

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:

以及在它们之间进行转换的 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;
    }

}

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

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

} 

For a more detailed example see:

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

回答by Guillaume

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 的默认构造函数,以便能够实例化您的类。也许有一个我不知道的解决方法。

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

JAXB 特别适用于 bean-like classes,允许通过调用 setter 来配置对象。

回答by Valentin Rocher

JAXB re-creates beans from XML in a simple fashion : it creates a new instance of the bean, and then do all the setXXXneeded 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 setXXXmethods.

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

回答by Rafael M

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

您可以使用注释@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;
    }
}

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

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