Это довольно хороший вопрос!
Короткий ответ: нет , использование setAdapter
на маршаллере / демаршаллере не означает, что вам не нужно использовать @XmlJavaTypeAdapter
.
Позвольте мне объяснить это гипотетическим (пока действительным!) Сценарием.
Рассмотрим в веб-приложении получение события в форме xml, имеющего следующую схему:
<xs:element name="event" >
<xs:complexType>
<xs:sequence>
<!-- Avoiding other elements for concentrating on our adapter -->
<xs:element name="performedBy" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
Эквивалентно этому, ваша модель будет выглядеть так:
@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
protected String performedBy;
}
Теперь в приложении уже есть компонент с именем User
, который поддерживает детальный
информация о пользователе.
public class User {
private String id;
private String firstName;
private String lastName;
..
}
Обратите внимание, что это User
неизвестно вашему контексту JAXB.
Для простоты у нас есть User как POJO, но это может быть любой Valid Java Class.
Что архитектор приложений хочет, чтобы Event
performedBy
было представлено как User
чтобы получить полную информацию.
Вот где @XmlJavaTypeAdapter входит в картинку
JAXBContext знает о performedBy
как xs:string
, но он должен быть представлен как
User
в памяти на Java.
Модифицированная модель выглядит так:
@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
@XmlJavaTypeAdapter(UserAdapter.class)
protected User performedBy;
}
UserAdapter.java:
public class UserAdapter extends XmlAdapter<String, User> {
public String marshal(User boundType) throws Exception {
..
}
public User unmarshal(String valueType) throws Exception {
..
}
}
Определение Адаптера говорит, что -
- BoundType - пользователь (в представлении Memeory)
- ValueType is String (Тип данных, о котором осведомлен JAXB-контекст)
Возвращаясь к вашему вопросу -
Я считаю это несколько избыточным.
Кстати, someMarshaller.setAdapter (...), похоже, ничего не делает.
Учтите, что нашему адаптеру требуется класс UserContext для успешного маршалинга / демаршалирования.
public class UserAdapter extends XmlAdapter<String, User> {
private UserContext userContext;
public String marshal(User boundType) throws Exception {
return boundType.getId();
}
public User unmarshal(String valueType) throws Exception {
return userContext.findUserById(valueType);
}
}
Теперь вопрос в том, как UserAdapter будет получать набор UserContext ??
В качестве хорошего дизайна его всегда следует поставлять, пока он создан.
public class UserAdapter extends XmlAdapter<String, User> {
private UserContext userContext;
public UserAdapter(UserContext userContext) {
this.userContext = userContext;
}
public String marshal(User boundType) throws Exception {
return boundType.getId();
}
public User unmarshal(String valueType) throws Exception {
return userContext.findUserById(valueType);
}
}
Но JAXB Runtime может принимать только адаптер с конструктором без аргументов.
(Очевидно, JAXBContext не знает о конкретной модели приложения)
Так что, к счастью, есть опция: D
Вы можете указать своему unmarshaller
использовать данный экземпляр UserAdapter
вместо того, чтобы создавать его самостоятельно.
public class Test {
public static void main(String... args) {
JAXBContext context = JAXBContext.getInstance(Event.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
UserContext userContext = null; // fetch it from some where
unmarshaller.setAdapter(UserAdapter.class, new UserAdapter(userContext));
Event event = (Event) unmarshaller.unmarshal(..);
}
}
setAdapter
метод доступен для обоих Marshaller
& Unmarshaller
Примечание:
setAdapter
на маршаллере / демаршаллере не означает, что вам не нужно использовать @XmlJavaTypeAdapter
.
@XmlRootElement(name="event")
@XmlType(name="")
public class Event {
@XmlElement(required=true)
// @XmlJavaTypeAdapter(UserAdapter.class)
protected User performedBy;
}
Если вы пропустите это время выполнения JAXB, вы не поймете, что User - это ваш тип привязки, а тип значения - это нечто другое. Он попытается маршалировать User
как есть, и у вас будет неправильный xml
(или ошибка проверки, если включена)
В то время как мы взяли сценарий, в котором Адаптер должен быть с аргументами, отсюда
используйте метод setAdapter
.
Также есть некоторые расширенные применения, даже если у вас есть конструктор по умолчанию без аргументов, но вы предоставляете экземпляр адаптера
Может этот адаптер сконфигурирован с данными, которые использует маршал / демаршал!