JAXB и конструкторы
Я начинаю изучать JAXB, поэтому мой вопрос может быть очень глупым. Теперь у меня есть классы и я хочу сгенерировать XML-схему. Идя после этой инструкции, я получаю исключение
IllegalAnnotationExceptions ... не имеет конструктора по умолчанию без аргументов.
Да уж. Мои классы не имеют конструкторов по умолчанию без аргументов. Это слишком просто. У меня есть классы с видимыми конструкторами / финальными методами и, конечно, с аргументами. Что мне делать - создавать какие-то определенные классы momemto/builder или указывать мои конструкторы для JAXB (каким образом?)? Благодарю.
4 ответа
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;
}
}
Для более подробного примера см.:
Вы можете использовать аннотацию @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
метод в любом месте вашего кода, так как он вернет недопустимый экземпляр.
У вас должен быть конструктор по умолчанию для JAXB, чтобы иметь возможность создавать экземпляры ваших классов. Может быть, есть обходной путь, который я не знаю, хотя.
JAXB специально приспособлен для классов, подобных bean-компонентам, позволяя конфигурировать объекты, вызывая для них сеттеры.
JAXB воссоздает bean-компоненты из XML простым способом: он создает новый экземпляр bean-компонента, а затем выполняет все setXXX
необходимо установить атрибуты. Итак, если у вашего компонента нет конструктора без аргументов, JAXB не сможет его создать. Как сказано в других ответах, JAXB лучше работает для простых "контейнерных" bean-компонентов, для которых конструктор без аргументов на самом деле не является проблемой. Если вы пытаетесь создать bean-компоненты, которые нуждаются в особой инициализации, вам нужно сделать это в setXXX
методы.