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?

Original source