2010-12-08 100 views
28

我开始学习JAXB,所以我的问题可能非常愚蠢。现在我有类并且想要生成XML Schema。 this指令后去我得到异常JAXB和构造函数

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

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

回答

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

} 

有关更详细的例子请参阅:

5

您应该有一个JAXB的默认构造函数来实例化您的类。也许有一种解决办法我不知道。

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

+1

为所有类创建默认构造函数是一个非常糟糕的想法。必须有一些解决方法。 – 2010-12-08 12:29:38

+0

我也不喜欢这种设计,但这是标准的JAXB方式... – Guillaume 2010-12-08 12:31:42

+0

我坦率地不真正理解无参数的种族主义。您的bean类只能是info的容器,它可以很容易地转换成XML,而不是复杂初始化的类。 – 2010-12-08 12:32:22

3

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

13

可以使用注释@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. */ 
    public static PurchaseOrder newInstance() { 
     return new PurchaseOrder(); 
    } 

    public String getAddress() { 
     return address; 
    } 

    public Customer getCustomer() { 
     return customer; 
    } 
} 

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