I want to validate form in Spring application using JPA and I have a problem with field production year. The validation succeeds when I use a year with exactly 4 digits, like 2010. However, when I enter into form value less than 1000 or greater than 9999 (value with not 4 digits) I get this exception:
Failed to convert property value of type java.lang.String to
required type java.time.Year for property productionYear;
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [java.lang.String] to
type [@javax.persistence.Convert @javax.persistence.Column
@javax.validation.constraints.NotNull @com.kucharek.motorcycleshop.data.ProductionYearConstraint
java.time.Year] for value 12345;
nested exception is java.lang.IllegalArgumentException:
Parse attempt failed for value [12345]
SQL declaration of that field:
production_year year not null
check (production_year between
year("1885-01-01") and year(current_date())
)
Java declaration in the entity class:
@Convert(converter = YearAttributeConverter.class)
@Column(name = "production_year")
@NotNull(message = "Production year is obligatory")
@ProductionYearConstraint(message = "Production year should be between 1885 and current year")
private Year productionYear;
Converter class:
@Converter(autoApply = true)
public class YearAttributeConverter
implements AttributeConverter<Year, Short> {
@Override
public Short convertToDatabaseColumn(Year attribute) {
return (short) attribute.getValue();
}
@Override
public Year convertToEntityAttribute(Short dbData) {
return Year.of(dbData);
}
}
Annotation for validation:
@Constraint(validatedBy = ProductionYearValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ProductionYearConstraint {
String message() default "Invalid production year";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator class:
public class ProductionYearValidator
implements ConstraintValidator<ProductionYearConstraint, Year> {
@Override
public boolean isValid(Year year, ConstraintValidatorContext context) {
return year != null && year.getValue() >= 1885 &&
year.getValue() < Year.now().getValue() ;
}
}
What did I do wrong? Should I change type of data in database or in model? How can I handle exception and print to user my custom error message instead of print stack trace?