В настоящее время я изучаю создание API с помощью Spring. Я работаю с Spring Validator, чтобы проверить свой ввод. Вот мой кастомный валидатор:

public class NewHoldValidator implements Validator {

    private EntityManager manager;

    public NewHoldValidator(EntityManager manager) {
        this.manager = manager;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return NewHoldRequest.class.isAssignableFrom(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        if (errors.hasErrors()) {
            return;
        }

        NewHoldRequest request = (NewHoldRequest) target;

        Patron patron = manager.find(Patron.class, request.patronId);
        BookInstance bookInstance = manager.find(BookInstance.class, request.bookInstanceId);

        Assert.state(patron != null, "Patron does not exists.");
        Assert.state(bookInstance != null, "Book instance does not exists.");

        if (!bookInstance.acceptToBeHoldTo(patron)) {
            errors.reject(null, "This book instance cannot be hold to this patron");
        }

        if (!request.hasDaysHold()) {
            if (!patron.researcher()) {
                errors.rejectValue("daysHold", null, "You need to pass a daysHold attribute");
            }
        }
    }
}

А вот и мой класс NewHoldRequest:

public class NewHoldRequest {
    @NotNull
    public final Long patronId;
    @NotNull
    public final Long bookInstanceId;
    @Positive
    @Max(60)
    public final Integer daysHold;

    public NewHoldRequest(@NotNull Long patronId, @NotNull Long bookInstanceId, @Positive @Max(60) Integer daysHold) {
        this.patronId = patronId;
        this.bookInstanceId = bookInstanceId;
        this.daysHold = daysHold;
    }

    @Override
    public String toString() {
        return "NewHoldRequest{" + "patronId=" + patronId + ", bookId=" + bookInstanceId + ", daysHold=" + daysHold + '}';
    }

    public boolean hasDaysHold() {
        return this.daysHold != null;
    }

Даже если мое поле daysHold является общедоступным, мне все равно нужно создать для него геттер, чтобы Spring мог правильно отображать отклоненную ошибку, в противном случае он выдаст NotReadablePropertyException . Есть ли способ определить, что Spring может отклонять общедоступные поля без геттеров, или мне нужно будет добавить методы доступа ко всем полям, которые я хочу отклонить?

Вот сообщение, которое появляется, когда срабатывает моя проверка.

org.springframework.beans.NotReadablePropertyException: Invalid property 'daysHold' of bean class [com.api.library.usecases.newhold.NewHoldRequest]: Bean property 'daysHold' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
2
Henrique Lopes 11 Фев 2021 в 15:04

1 ответ

Лучший ответ

Советую воспользоваться интерфейсом ConstraintValidator. Это общий интерфейс, без кастинга и других проблем. Вы должны создать для вас аннотацию пользовательского ограничения, это @NewHoldValid, после этого реализуйте интерфейс CustomValidator:

@Component
public class NewHoldValidator implements ConstraintValidator<NewHoldValid, NewHoldRequest> {   

    @Override
    public boolean isValid(NewHoldRequest  value, ConstraintValidatorContext context) {
        if(ANY_CONDITION){
           return true;
       }else {
          return false;
       }
    }

После этого используйте аннотацию @NewHoldValid над NewHoldRequest. Если вы хотите установить текст сообщения об ошибке, отличный от текста по умолчанию, используйте это:

context.buildConstraintViolationWithTemplate("Your error message").addConstraintViolation();
1
Dmitrii Bykov 11 Фев 2021 в 16:39