Чтобы ответить на ваш вопрос: я думаю, что это просто плохой дизайн в JAXB (или, возможно, в реализациях JAXB).Существование конструктора без аргументов проверяется при создании JAXBContext
и поэтому применяется независимо от того, хотите ли вы использовать JAXB для маршалинга или демаршаллинга.Было бы здорово, если бы JAXB отложил этот тип проверки до JAXBContext.createUnmarshaller()
.Я думаю, что было бы интересно разобраться, действительно ли этот дизайн предписан спецификацией или это проект реализации в JAXB-RI.
Но действительно есть обходной путь.
JAXB не делаетна самом деле не нужен конструктор без аргументов для сортировки.Далее я предполагаю, что вы используете JAXB исключительно для маршалинга, а не демаршаллинга.Я также предполагаю, что у вас есть контроль над неизменным объектом, который вы хотите маршалировать, чтобы вы могли его изменить.Если это не так, то единственный путь вперед - это XmlAdapter
, как описано в других ответах.
Предположим, у вас есть класс Customer
, который является неизменным объектом.Инстанцирование происходит через Pattern Builder или статические методы.
public class Customer {
private final String firstName;
private final String lastName;
private Customer(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// Object created via builder pattern
public static CustomerBuilder createBuilder() {
...
}
// getters here ...
}
Правда, по умолчанию вы не можете заставить JAXB разобрать такой объект.Вы получите ошибку " .... У клиента нет конструктора по умолчанию без аргументов ".
Есть как минимум два способа решения этой проблемы.Они оба используют метод или конструктор исключительно для того, чтобы сделать интроспекцию JAXB счастливой.
Решение 1
В этом методе мы сообщаем JAXB, что существует статический метод фабрики, который он может использовать для создания экземпляра класса.Мы знаем, но JAXB не знает, что это никогда не будет использовано.Хитрость заключается в аннотации @XmlType
с параметром factoryMethod
.Вот как это делается:
@XmlType(factoryMethod="createInstanceJAXB")
public class Customer {
...
private static CustomerImpl createInstanceJAXB() { // makes JAXB happy, will never be invoked
return null; // ...therefore it doesn't matter what it returns
}
...
}
Не имеет значения, является ли метод закрытым, как в примере.JAXB все еще примет это.Ваша IDE пометит метод как неиспользуемый, если вы сделаете его закрытым, но я все еще предпочитаю частный.
Решение 2
В этом решении мы добавляем приватный no-argконструктор, который просто передает null в реальный конструктор.
public class Customer {
...
private Customer() { // makes JAXB happy, will never be invoked
this(null, null); // ...therefore it doesn't matter what it creates
}
...
}
Не имеет значения, является ли конструктор закрытым, как в примере.JAXB все еще примет это.
Резюме
Оба решения удовлетворяют стремление JAXB к созданию экземпляров без аргументов.Обидно, что нам нужно это делать, когда мы сами знаем, что нам нужно только маршалировать, а не демаршалировать.
Я должен признать, что не знаю, в какой степени это хак, который будетработать только с JAXB-RI, а не, например, с EclipseLink MOXy.Это определенно работает с JAXB-RI.