10

I am attempting to validate String Date using javax.validation & Hibernate validation. i need to check given String date should be past and it should be correct yyyyMMdd format with all constraints like leap year, 30th, 31st day.

 public class UserInformation {

        @NotNull 
        public String idNum = null;

        @NotNull
        //@Past
        @Pattern(regexp="\\d{4}(1[012]|0[1-9])(3[01]|[12]\\d|0[0-9])")
        public String dob= null;

    }

I tried with this code but not working. Is there any solution. if we have custom validator then is it in field level.Please give suggestion or code snippet.

Sayuri Mizuguchi
  • 5,250
  • 3
  • 26
  • 53
deadend
  • 1,286
  • 6
  • 31
  • 52

1 Answers1

15

Option 1

Change your pattern to this:

Pattern(regexp = "([0-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/[0-9]{4}")

But keep in mind that this kind of validation is not checking if February has less than 28/29 days, and other dates constraints.

Options 2

Create your custom constraint validator

Annotation

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckDateValidator.class)
@Documented
public @interface CheckDateFormat {

    String message() default "{message.key}";

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };

    String pattern();

}

Validator class

Having the Date object you can do any other validation you want (like refuse dates in the past)

public class CheckDateValidator implements ConstraintValidator<CheckDateFormat, String> {

    private String pattern;

    @Override
    public void initialize(CheckDateFormat constraintAnnotation) {
        this.pattern = constraintAnnotation.pattern();
    }

    @Override
    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
        if ( object == null ) {
            return true;
        }

        try {
            Date date = new SimpleDateFormat(pattern).parse(object);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

Use

@CheckDateFormat(pattern = "ddMMyyyy")
private String value;
Rafael Teles
  • 2,708
  • 2
  • 16
  • 32
  • Sorry to Ask this question. where to put @CheckDateFormat(pattern = "ddMMyyyy").. i cannot put like this. @CheckDateFormat(pattern = "ddMMyyyy") public String dob= null; & What should be the values for FIELD, METHOD, PARAMETER, ANNOTATION_TYPE. – deadend Jan 18 '17 at 12:22
  • FIELD, METHOD, etc are static values of ElementType, I made some edits – Rafael Teles Jan 18 '17 at 12:25
  • 2
    This one is not validating Feb 29 1987.. it returns true.. So i changed code as.. DateFormat dateFormat = new SimpleDateFormat( pattern ); dateFormat.setLenient( false ); try { dateFormat.parse(object); return true; } catch (ParseException e) { return false; } Now its working.. – deadend Jan 18 '17 at 12:40
  • 1
    Its really helped me. Thank you so much dude. – deadend Jan 18 '17 at 12:41
  • I'm noob with regex, would you be able to explain what does [0-2][0-9]/[0-1][0-9]/[0-9]{4} mean? – kevenlolo Jun 02 '18 at 13:24
  • @kevenlolo that regex is not correct, you'll probably want something like this: ([0-2][0-9]|3[0-1])\/[0-1][0-9]\/[0-9]{4}. I advice you to do some research on regex, https://regex101.com/ is a very useful site – Rafael Teles Jun 08 '18 at 11:10
  • This parse it wrongly when I add pattern = "yyyy-MM-dd-HH:mm" and value as "2022-23-23-04:00" it still sends true. – Kedar9444 Aug 18 '20 at 12:36
  • Thank you for the feedback @Kedar9444. Interesting behaviour, you should set simpleDateFormat.setLenient(false) before parsing to deal with that. But at this point in time if you can use java 8 time api, you should give it a try: LocalDateTime.parse("2022-12-23-04:00", DateTimeFormat.forPattern("yyyy-MM-dd-HH:mm")) – Rafael Teles Aug 18 '20 at 14:06