Джерси: ошибка, когда класс содержит аннотации JAX-RS и JAX-WS - PullRequest
2 голосов
/ 08 июня 2011

Использование Jersey 1.7, JAX-WS 2.2.3, Tomcat 6.0.30 и следующее объявление метода запрещает запуск сервлета Jersey:

@POST
@Produces("text/plain")
public void postIt(@WebParam(name = "paramOne") final String paramOne, 
                   final String paramTwo) {
    // ...
}

Сгенерированное исключение:

SEVERE: Missing dependency for method public 
        java.lang.String com.sun.jersey.issue.MyResource.postIt(
          java.lang.String,java.lang.String) at parameter at index 0
SEVERE: Method, public void 
        com.sun.jersey.issue.MyResource.postIt(
          java.lang.String,java.lang.String), 
        annotated with POST of resource, 
          class com.sun.jersey.issue.MyResource, 
          is not recognized as valid resource method.

Если аннотация @WebParam удалена, все работает нормально.

Теперь, пожалуйста, имейте в виду, что я не пытаюсь работать с простыми строками, а скорее переношу сложные объекты, которые маршалировались / разбирались с использованием SOAP, на сервисы RESTful, но я должен предоставить оба интерфейса некоторое время, не прерывая предыдущие WASD. Метод - это просто минималистичный сценарий.

Кто-нибудь из вас имеет представление о статусе этого? Это было исправлено? Предложения?

1 Ответ

2 голосов
/ 20 января 2012

Спецификация на это ясна.Раздел 3.3.2.1 сообщает нам, что:

Методы ресурса НЕ ДОЛЖНЫ иметь более одного параметра, который не аннотирован одной из перечисленных выше аннотаций.

перечисленные выше аннотации - это аннотации параметров JAX-RS: @QueryParam, @MatrixParam и т. д.

Однако существует определенный способ решения этой проблемы для Джерси.Использование InjectableProvider.Итак, метод, который определяет два не-JAX-RS параметра:

@POST
public void postIt(@CustomInjectable final Customer customer, 
                   final Transaction transaction) {
  // ...
}

Конечно, мы должны закодировать аннотацию:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface CustomInjectable {
}

Реализация InjectableProvider, которая знаеткак предоставить Customer s:

import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.sun.jersey.api.model.Parameter;

@Provider
public class CustomerInjectableProvider implements 
             InjectableProvider<CustomInjectable, Parameter> {

  // you can use @Context variables, as in any Provider/Resource
  @Context 
  private Request request;

  public ComponentScope getScope() {
    // ComponentScope.Singleton, Request or Undefined
  }

  public Injectable getInjectable(ComponentContext i, 
                                  CustomInjectable annotation, 
                                  Parameter param) {
    Injectable injectable = null;
    if (Customer.getClass().isAssignableFrom(param.getParameterClass()) {
      injectable =  getInjectable();
    }
    return injectable;
  }

  private Injectable getInjectable() {
    return new Injectable<Customer>() {
        public Customer getValue() {
          // parse the customer from request... or session... or whatever...    
        }
     };
  }
}

Но Джерси учитывает только последнюю аннотацию (см. JERSEY-ISSUE-731 ), поэтому будьте осторожны.

И, более портативный способ (если вы все равно делаете об этом заботитесь):

// simple bean
public class CustomerWithTransaction {
  private Customer customer;
  private Transaction transaction;

  // getters and setters
}

Затем измените метод на:

@POST
public void postIt(CustomerWithTransaction customerWithTransaction) {
  // ...
}

Затем создайте свойсобственные MessageBodyReader для CustomerWithTransaction, где вы также можете получить доступ к любым контекстным переменным (запрос, заголовки и т. д.).

...