Springboot form validation for ensuring one date does not come before another?
java, spring-boot, spring-mvc, validation
Solution
You could create your own validator/validation annotation (see https://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/chapter-bean-constraints.html#d0e371 )
Annotation:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=YourDateValidator.class)
public @interface ValidDates {
String message() default "{message.id}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class YourDateValidator implements ConstraintValidator< ValidDates,
TypeToBeValidated> {
@Override
public void initialize(ValidDates constraintAnnotation) {
}
@Override
public boolean isValid(TypeToBeValidated value, ConstraintValidatorContext context)
{
< validation code, returning true for a valid value >
}
}
Usage:
@ValidDates
class TypeToBeValidated {
private String dateFrom;
private String dateTo;
}
Problem
After following this guide: https://spring.io/guides/gs/validating-form-input/, I want to do form validation that checks if the `dateTo` value comes before the `dateFrom` value. It would be awesome if there were some kind of annotation solution. They are stored as strings in the empty model supplied by my form. ``` @NotNull(message="You must select a date.") @NotBlank(message="You must select a date.") private String dateFrom; @Min(dateFrom) private String dateTo; ``` Obviously this doesn't work because we can't compare whether one String is smaller than the other... Is there an alternative? The problem is that I want to provide a message in the UI right from the form validation check, just like how I can check if the message is null or blank. ``` // Create Request @RequestMapping(value = "/save", method = RequestMethod.POST) String saveRequest(Principal principal, @Valid @ModelAttribute(value = "requestModel") RequestModel requestModel, BindingResult bindingResult, RedirectAttributes redirectAttributes) { .... if (bindingResult.hasErrors()) { // log.info("There are binding errors."); return "send"; } .... // Format given date Date dateFrom = null; try { SimpleDateFormat formatter = new SimpleDateFormat(DateUtil.dateFormat); dateFrom = formatter.parse(requestModel.getDateFrom()); } catch (ParseException e) { e.printStackTrace(); return "send"; } try { if (requestModel.getDateTo() != null && !(requestModel.getDateTo().isEmpty())) { SimpleDateFormat formatter = new SimpleDateFormat(DateUtil.dateFormat); Date dateTo = formatter.parse(requestModel.getDateTo()); // Check if dateTo is before dateFrom if (!dateTo.before(dateFrom)) { // If not (proper case), set the date requestDOOb.setDateTo(dateTo); } else { // Improper case, log error //TODO Update UI? log.info("dateTo cannot come before dateFrom"); return "send"; } } else { requestDOOb.setDateTo(dateFrom); } } catch (ParseException e) { e.printStackTrace(); return "send"; } ``` I don't want to have to perform the validation in the POST method itself... Update: ``` @AssertTrue(message="The end date cannot come before the initial date.") private boolean isValid() { return !dateTo.before(dateFrom) && this.dateFrom.before(this.dateTo); } public Date getDateFrom() { return dateFrom; } public void setDateFrom(Date dateFrom) { this.dateFrom = dateFrom; } public Date getDateTo() { return dateTo; } public void setDateTo(Date dateTo) { this.dateTo = dateTo; } ``` What about something like the above?