Как правильно валидировать LocalDate в RestController

Возник вопрос о том, как провести валидацию спринг бинов при их получении из json.

Есть такой дто класс:

public class Employee {
    @NotNull(message = "birthday can't be null")
    @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
    @ValidateDate(message = "def msg")
    @Past(message = "birthday can't be before current date")
    private LocalDate birthday;
}

Я создал свою аннотацию @ValidateDate для валидации датты

@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateValidator.class)
@Documented
public @interface ValidateDate {

    String message() default "Invalid date format";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}


public class DateValidator implements ConstraintValidator<ValidateDate, LocalDate> {

    private static final String DATE_PATTERN = "yyyy/MM/dd";

    @Override
    public boolean isValid(LocalDate value, ConstraintValidatorContext context) {

        DateFormat sdf = new SimpleDateFormat(DATE_PATTERN);
        sdf.setLenient(false);
        try {
            sdf.parse(value.toString());
        } catch (ParseException e) {
            return false;
        }
        return true;
    }
}

Проблемы появляются в тот момент, когда я передаю своему контроллеру строку, которую нельзя преобразовать к датте. Самое непонятное, почему не возникает никакой исключительной ситуации.

Я хочу сделать валидацию таким образом, что-бы при передаче данных, которые нельзя преобразовать к датте пользователю выдавалось сообщекие о том, что данные некорректны и приммер требуемого формата данных.

ControllerAdvice который обрабатывает ошибки валидации

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

    public static final String NO_SUCH_EMPLOYEE = "There is no such employee";
    public static final String VALIDATION_ERROR = "Validation error";

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(
            MethodArgumentNotValidException ex,
            HttpHeaders headers,
            HttpStatus status,
            WebRequest request) {
        List<String> errors = new ArrayList<>();
        for (FieldError error : ex.getBindingResult().getFieldErrors()) {
            errors.add(error.getField() + ": " + error.getDefaultMessage());
        }
        for (ObjectError error : ex.getBindingResult().getGlobalErrors()) {
            errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
        }

        ErrorResponse errorResponse = new ErrorResponse(VALIDATION_ERROR, errors, HttpStatus.BAD_REQUEST);
        return handleExceptionInternal(ex, errorResponse, headers, errorResponse.getHttpStatus(), request);
    }

Есть мысль сделать тип поля birthday, в классе Employee, как String и уже строку валидировать кастомным валидатором но возможно я что-то упускаю. Подскажите пожалуйста как лучше провести валидацию в данном случае.


Ответы (1 шт):

Автор решения: sKon

Как я и думал, при работе со строкой вместо LocalDate валидация работает и проблема в том, что нужно как-то обрабатывать эту ситуацию до десериализации из json в объект Employee. Решил свою проблему созданием дополнительного класса, аналогичного классу Employee но содержащий только String и Long поля, после того как этот класс успешно десерализован и провалидирован на его основе создается полноценный класс Employee. Это конечно работает, но меня не покидает ощущение, что я создал какой-то костыль. Если у вас есть какие-либо замечания, я весь внимание.

→ Ссылка