Unmarshal генерирует нулевое поле в generic с полем List

#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. ПОЛЕ) для определения класса.