Метод "getter" REST Джерси JAX-RS всегда вызывается - PullRequest
0 голосов
/ 02 июня 2018

Я использую веб-приложение в Glasshfish 5, которое предоставляет конечную точку REST, используя Jersey JAX-RS.Он также использует проверку бина.У меня проблема в том, что любой метод, начинающийся с «get», всегда вызывается, когда он возвращает что-то с аннотацией @Valid.

Пример:

@Path("/hello")
public class HelloResource {

  @GET
  public @Valid HelloMessage getSomething() {
    HelloMessage helloMessage = new HelloMessage();
    helloMessage.setMessage("Hello World!");
    return helloMessage;
  }

  @POST
  public @Valid HelloMessage updateMessage(@Valid HelloMessage message) {
    return message;
  }
}

Если я выполняю POSTв / hello, вы увидите вызываемый метод getSomething до вызова updateMessage.Если я удаляю аннотацию @Valid для типа возврата метода getSomething, то getSomething не вызывается.

Это соответствует спецификациям?Должны ли вы в принципе никогда не называть метод, начинающийся с «get» в классе REST?

В прошлом я сообщал об этой проблеме на github, но никогда не получал ответ.

https://github.com/eclipse-ee4j/jersey/issues/3743

Другие классы:

@ApplicationPath("/")
public class HelloApplication extends Application {

  @Override
  public Set<Class<?>> getClasses() {
    return Collections.singleton(HelloResource.class);
  }
}

public class HelloMessage {

  @Size(max = 100)
  private String message;

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }
}

Минимальный проект можно найти на https://github.com/robertatgh/stackoverflow-50658396/tree/develop

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Просто добавив два моих цента к вершине Ответ Таруна .

Когда я увидел, что Джерси проверяет классы ресурсов, я пытался придумать вариант использования, почемубыть подтвержденным.И причина, по которой я могу придумать, - это случай, когда мы вводим @PathParam s и другие @XxxParam s как поля в ресурс

@Path("/person/{email}")
public class PersonResource {

    @Email // email constraint validator
    @PathParam("email")
    private String email;
}

вместо внедрения @PathParam в метод ресурсапараметр, как вы обычно видите, мы вводим его как поле.И когда ресурс проверяется, поле email будет проходить через валидатор ограничения электронной почты.

Что касается свойств, они могут быть полями или методами стиля JavaBean (которые также называются «свойствами»)."), которые являются методами получения и установки, начинающимися с get и set, соответственно.Таким образом, наше именование методов с помощью get и set добавляет их в список свойств.

Теперь я не знаю, подумали ли разработчики об этом при разработке кода, но если они это сделали иони решили, что это не проблема, я бы предположил, что их аргумент таков: проверка бина на Джерси предназначена для проверки входящих данных;это могут быть данные, поступающие от клиента в виде тела объекта или в виде различных параметров, таких как путь, заголовок или строка запроса.Общим фактором является то, что все они поступают от клиента.Следовательно, если нарушено какое-либо ограничение, это будет ошибка клиента , следовательно, статус ответа 400 Bad Request, что означает ошибка клиента .

сказал, что когда у нас есть возвращаемые значения в наших ресурсных методах, это не собранных клиентом данных;это значения, полученные при обработке на стороне сервера.Поэтому, если на эти объекты нарушено какое-то ограничение, они не должны обрабатываться с той же семантикой, что и клиентские входящие объекты.Да, вы можете захотеть, чтобы эти объекты были проверены, но IMO, это должно быть проверено в другом процессе и не должно приводить к тем же 400, что было бы с ошибкой на стороне клиента.Это должно привести к 500 внутренних ошибок сервера.Это определенно не ошибка клиента, что есть проблема с возвращаемым значением.Мы, как разработчики, должны выполнить эти проверки.

Теперь, если вы do хотите самостоятельно проверить возвращаемое значение, вы можете просто использовать API-интерфейсы валидации, чтобы выполнить валидацию вручную.И чтобы сделать его СУХИМЫМ и прозрачным, вы можете использовать возможности AOP HK2 (Jersey DI) для перехвата вызова метода.Я собрал PoC в этом GitHub репо .

0 голосов
/ 06 июня 2018

Так что это оказалось забавной проблемой из-за соглашения об именах.Отлаживая исходный код джерси, вы увидите, что он проходит через строку

org.glassfish.jersey.server.validation.internal.DefaultConfiguredValidator.onValidate (ValidationInterceptorContext): 166

public void onValidate(final ValidationInterceptorContext ctx) {

    final Object resource = ctx.getResource();
    final Invocable resourceMethod = ctx.getInvocable();
    final Object[] args = ctx.getArgs();

    final Set<ConstraintViolation<Object>> constraintViolations = new HashSet<>();
    final BeanDescriptor beanDescriptor = getConstraintsForClass(resource.getClass());

    // Resource validation.
    if (beanDescriptor.isBeanConstrained()) {
        constraintViolations.addAll(validate(resource));
    }

    if (resourceMethod != null
            && configuration.getBootstrapConfiguration().isExecutableValidationEnabled()) {
        final Method handlingMethod = resourceMethod.getHandlingMethod();

Интересная часть около

// Resource validation.
if (beanDescriptor.isBeanConstrained()) {
    constraintViolations.addAll(validate(resource));
}

Определение того же значения

@Override
public final boolean isBeanConstrained() {
    return hasConstraints() || !constrainedProperties.isEmpty();
}

Теперь, если вы посмотрите на значение constrainedProperties, оно будет показано ниже

getSomething is a property

Поэтому он считает, что getSomething означает свойство something, которое затем вставляет проверку в само свойство.

Так что теперьесли мы переименуем метод, как показано ниже

  @GET
  public @Valid HelloMessage doGetSomething() {
    System.out.println("* * * *---==** getSomething() called **==---* * * *");
    HelloMessage helloMessage = new HelloMessage();
    helloMessage.setMessage("H");
    return helloMessage;
  }

  @POST
  public  @Valid HelloMessage updateMessage(@Valid HelloMessage message) {
      message.setMessage("H");
    System.out.println("* * * *---==** updateMessage() called **==---* * * *");

    return message;
  }

и снова запустим его из командной строки

getSomething is not Called

И, конечно, если я исправлювозвращаемое значение с действительными данными

getSomething not called

...