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