Как я могу программным образом вызывать тот же валидатор, который работает по методу @RequestMethod с параметром @Valid в Spring?

У меня есть класс с аннотацией проверки гибернации на некоторых полях (например, @NotNull и @Size(min = 4, max = 50) и т.д.)

public class MyClass {

    Long id;

    @NotEmpty
    @Size(min = 4, max = 50)
    String machineName;

    @NotEmpty
    @Size(min = 4, max = 50)
    String humanName;

    // Getters, setters, etc…
}

У меня также есть пользовательский контроллер, который действует как JSON API и десериализатор JSON, который создает объекты MyClass при вызове методов API. В моем настраиваемом контроллере у меня есть метод для создания нового объекта такого типа:

@RequestMapping(method = RequestMethod.POST)
public long createMyObject(@RequestBody @Valid MyClass newObj) {
    // Create the object in the database
    return newObj.getId();
}

и другой метод, который обновляет существующий объект

@RequestMapping(method = RequestMethod.PUT)
public void updateMyObject(@RequestBody MyClass updatedObj) {
    MyClass existingObj = // Get existing obj from DB by updatedObj.getId();

    // Do some secondary validation, such as making sure that a specific
    // field remains unchanged compared to the existing instance
    if (existingObj.getMachineName() != null && 
            !existingObj.getMachineName().equals(updatedObj.getMachineName())) {
        throw new CannotChangeMachineNameException();
    }
    else {
        updatedObj.setMachineName(existingObj.getMachineName());
    }

    // [HERE IS WHERE I WANT THE MAGIC TO HAPPEN]

    // Save updatedObj to the database
}

В то время как я могу использовать @Valid в createMyObject, я не могу использовать его в updateMyObject, потому что для нашей реализации API требуется, чтобы имя машины оставалось неизменным - пользователи могут вызывать API с объектом JSON, который либо полностью исключает машинное имя, либо заполняет его с тем же значением, которое существует в базе данных. *

Прежде чем сохранять обновленный объект в базу данных, я хочу вызвать тот же валидатор, что и вызывающая @Valid-аннотация. Как я могу найти этот валидатор и использовать его?

Ответ 1

Ничего не сказано, что вам нужно использовать @Valid только в ваших методах контроллера. Почему бы не сделать метод проверки, который принимает параметр, который вы комментируете как @Valid, а затем просто возвращаете тот же параметр.

Вот так:

public Book validateBook(@Valid Book book) {
   return book;
}

Похоже, альтернативой будет использование пакета проверки Hibernate. Здесь есть документация.

В принципе, вы получаете Validator от ValidationFactory, а затем используете валидатор следующим образом:

 @Test
    public void manufacturerIsNull() {
        Car car = new Car(null, "DD-AB-123", 4);

        Set<ConstraintViolation<Car>> constraintViolations =
            validator.validate(car);

        assertEquals(1, constraintViolations.size());
        assertEquals("may not be null", constraintViolations.iterator().next().getMessage());
}