#java #web-services #jaxb #jax-ws
#java #веб-сервисы #jaxb #jax-ws
Вопрос:
У меня есть веб-сервис, созданный на Java (1.6), с metro (2.0), с использованием maven, под Tomcat 6. Во всех веб-методах возвращаемый тип является универсальным классом:
public class WsResult<T> {
protected T resu< // the actual result
protected Code requestState; // 0K, or some error code if needed
protected String message; // if error, instead of result, insert a message
}
Например:
public WsResult<OtherClass> someMethod(...);
public WsResult<Foo> someMethod_2(...);
И в клиенте:
MyServiceService service = new MyServiceService();
MyService port = service.getMyServicePort();
WsResult result = port.someMethod(...);
OtherClass oc = (OtherClass) result.getResult();
WsResult res = port.someMethod_2(...);
Foo o = (Foo) res.getResult();
В некоторых веб-методах это работает.
Но когда результатом является класс с List<? class>
атрибутом, он не может отменить сопоставление.
Этот проект является частью крупнейшего. Итак, в целях тестирования я создал новый, более простой, просто проект, с той же моделью данных, и скопировал один из веб-методов, в этом случае это сработало, и после unmarshal у меня был результат, который я мог привести к ожидаемому типу.
Что может происходить?
Редактировать:
Ответ — это решение да, но генерирует средство получения для каждого типа, добавленного в объявление поля. Есть ли способ лучше?
Комментарии:
1. Можете ли вы опубликовать соответствующие фрагменты из тестового проекта?
2. Извините, что просто прокомментировал сейчас, но я очень занят. Отредактировал сообщение с примером использования.
Ответ №1:
Я не совсем уверен, что полностью понимаю вашу проблему, но мне кажется, что вы ожидаете слишком многого от JAXB здесь. Ваш WsResult
является универсальным в неограниченном параметре T
, что означает, что во время выполнения не остается ничего, кроме Object
ссылки для JAXB, с которой можно играть.
Что JAXB действительно нужно для решения такой ситуации, так это, грубо говоря, подсказка, какой класс создать для заполнения result
поля. Чтобы заполнить это, вы должны либо
- создайте конкретные подклассы
WsResult
(например, следуя вашему примеру,class OtherClassResult extends WsResult<OtherClass>
— когда вы отправляетеOtherClassResult
в JAXB, он будет знать, чтоresult
должен быть экземплярOtherClass
, и у него будет шанс действовать соответствующим образом или - прокомментируйте
result
поле@XmlElements
следующим образом:
@XmlElements({ @XmlElement(name = "text", type = String.class), // add more elems here @XmlElement(name = "other", type = OtherClass.class)}) protected Object resu<
Комментарии:
1. Для того, чтобы это работало, я использую конкретные подклассы WsResult, но я хотел бы изменить его на generic. Я не понял второй вариант, какое поле результата? У меня нет полей. Клиентская переменная или переменная тела веб-метода?
2. Поэтому, я думаю, вам придется выбрать вариант 2 (или какой-либо другой вариант, о котором я не знаю).
3. Я имел в виду
protected T result
вWsResult
, это должно содержать аннотации. Они доступны во время выполнения, поэтому JAXB может выяснить, что делать.4. Да, вы должны указать любой класс, с которым он будет использоваться, в этой аннотации. Name — это имя XML-тега, который должен быть сопоставлен классу, указанному в параметре type.
5. Я протестировал это, похоже, работает, но теперь в клиенте, в результате, у меня есть средство получения для каждого элемента класса в XmlElements, не кажущееся элегантным, но, по крайней мере, у меня работает generic. Также необходимо добавить @XmlAccessorType(XmlAccessType. ПОЛЕ) для определения класса.