Я оказываюсь в следующем сценарии в RestEasy REST API:
@POST
@Path("my-endpoint")
@Produces(MediaType.APPLICATION_JSON)
public Response myEndpoint(
final @Nullable Payload payload
) {
final var result = runCommand(
new Command(payload),
withPermissions(CAN_WRITE)
);
return ok(result);
}
...
@Value
public class Payload {
@NotNull Long mSomeValidLong;
}
...
@Value
public class Command {
@NotNull @Valid mPayload;
}
Как видите, конечная точка не проверяет полезную нагрузку сразу.
Вместо этого существует вложенная логика: полезные данные передаются в Command, который затем выполняется методом runCommand.
Несмотря на то, что вы не видите, как реализован runCommand, вы можете видеть, что сначала он проверяет разрешения. Он также имеет причудливую логику для рабочих потоков и перехвата исключений.
Итог: именно команда должна проверять параметры (потому что именно тогда мы достигли места, где разрешения контролируются, и когда мы уверены, что у нас есть для этого ресурсы).
Не спрашивайте меня, почему разрешения не проверяются как @Annotation непосредственно над методом конечной точки, это устаревший код.
При такой настройке я наблюдаю следующее:
Это работает (потому что RestEasy идентифицирует метод как один из своих):
public Response myEndpoint(final @Valid @NotNull Payload payload) { ... }
Это не работает, потому что это старая старая Java:
public Command(final @Valid @NotNull Payload payload) { ... } // Constructor as it would be generated by Lombok
Мой вопрос: есть ли вообще способ заставить @Valid творить чудеса где-то еще, кроме параметров метода конечной точки?
Судя по тому, что я прочитал, jakarta.validation будет выполнять точно такую же проверку в частях кода, отличных от RestEasy.
Последующий вопрос: разумно ли иметь две разные конкурирующие системы проверки? (Проверка RestEasy, а также проверка другого типа, например проверка Джакарты)
Другими словами: Command не является компонентом, управляемым Spring. Проверка с помощью @NotNull или чего-то еще работает только с bean-компонентами, управляемыми весной. Я предполагаю, что ваше определение конечной точки находится внутри объекта, помеченного @Controllerили чем-то подобным. В этом случае проверка работает и на уровне параметров метода.
Это не конкурирующие системы проверки, они абсолютно одинаковы. Вы также используете не Spring MVC, а Джерси (независимо от того, оба поддерживают @Valid). Однако в Spring MVC это часть выполнения метода, а не при вызове обычных методов. Вы можете использовать @Validated в своем классе для запуска проверки вызовов методов, но здесь это тоже не сработает, поскольку runCommand является вызовом внутреннего метода (и это не работает с вызовами внутренних методов). Таким образом, в качестве обходного пути вы можете вручную выполнить проверку или использовать полноценный AspectJ для поддержки вызовов внутренних методов.
@ThiloSchwarz Есть ли более простая аннотация, чем @ Controller, чтобы заставить платформу внедрить свои механизмы проверки в класс? т. е. я не хочу превращать команду или объект, выполнивший команду, в контроллер.
@M.Deinum Я думаю, что на самом деле мы используем JAX-RS, а не Spring или Jersey. Виноват.
@M.Deinum Я подтверждаю, что мы используем RestEasy/JAX-RS. Итак, вы утверждаете, что единственный способ здесь — запустить проверку команды вручную?
Добавление @Valid в конструктор ничего не даст ни для Spring, ни для Jersey. С его помощью вы можете проверять аргументы метода для конечных точек JAX-RS или контроллеров Spring. Но для конструкторов это не подойдет. Если вы поместите его в другой метод, вызываемый из метода обработки, если вы не добавите какой-нибудь AOP (как упоминалось ранее), он тоже не будет работать.
На этот вопрос ответил stackoverflow.com/questions/78613823/…? Какую версию RESTEasy вы используете?
@JamesR.Perkins, нет, это совсем другой вопрос. этот вопрос касается ручного применения проверки в других областях кода, чем те, где она изначально была автоматизирована.




замените @Valid собственным @Validated Spring
Попробую, но думаю, дело не в этом. Казаться. Комментарий Дейнума под моим вопросом.
Это может быть решением: Как вручную запустить проверку Spring?
1. Внедрить валидатор
@Autowired
private Validator validator;
2. Используйте его вручную
validator.validate(myObject);
Валидатор может быть валидатором по умолчанию:
// JSR-303 Validator
import javax.validation.Validator;
...или какой-нибудь причудливый валидатор, например, валидатор, предоставленный Spring:
// Spring Validator
import org.springframework.validation.Validator;
Когда вы создаете команду с помощью
new, Spring не имеет возможности внедрить валидаторы.