The @ValidateDateRange is a class-level constraint annotation that will validate a date range represented by two java.util.Date properties of an object. This can be reused in any class.
@ValidateDateRange(start="startDate", end="endDate") public class MyEntity { private Date startDate; private Date endDate; ... }
The annotation definition are as follows:
package blogspot.soadev.validator; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.Date; import javax.validation.Constraint; import javax.validation.ConstraintPayload; @Target( { TYPE, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = {DateRangeValidator.class} ) @Documented public @interface ValidateDateRange { String message() default "{end} should be later than {start}"; String start(); String end(); Class[] groups() default {}; Class[] payload() default {}; }And the implementing DateRangeValidator are as follows:
package blogspot.soadev.validator; import java.lang.reflect.Field; import java.util.Date; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class DateRangeValidator implements ConstraintValidator{ private String start; private String end; public void initialize(ValidateDateRange validateDateRange) { start = validateDateRange.start(); end = validateDateRange.end(); } public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) { try { Class clazz = object.getClass(); Date startDate = null; Method startGetter = clazz.getMethod(getAccessorMethodName(start), new Class[0]); Object startGetterResult = startGetter.invoke(object, null); if (startGetterResult != null && startGetterResult instanceof Date){ startDate = (Date) startGetterResult; }else{ return false; } Date endDate = null; Method endGetter = clazz.getMethod(getAccessorMethodName(end), new Class[0]); Object endGetterResult = endGetter.invoke(object, null); if (endGetterResult == null){ return true; } if (endGetterResult instanceof Date){ endDate = (Date) endGetterResult; } return (startDate.before(endDate)); } catch (Throwable e) { System.err.println(e); } return false; } private String getAccessorMethodName(String property){ StringBuilder builder = new StringBuilder("get"); builder.append(Character.toUpperCase(property.charAt(0))); builder.append(property.substring(1)); return builder.toString(); } }
Related Posts
- JSR 303 Bean Validation: @AssertMethodAsTrue - A reusable constraint annotation that spans multiple properties.
- JSR 303 Bean Validation: Error "java.lang.NoSuchMethodError: javax.persistence.Persistence.getPersistenceUtil()Ljavax/persistence/PersistenceUtil;"
- Integrating JSR 303 Bean Validation with Oracle ADF 11g
Cheers!
Do you know any automatic way to interpolate (for example via resource bundle) the field names in the message? By this I mean, the user should not see 'code' such as "endDate should be later than startDate". Would you recommend just specifying a different message each time your constraint is used?
ReplyDeleteHi Peter,
ReplyDeleteThe field names by default are being interpolated into the message (check the default message on the "ValidateDateRange" interface definition above)and you can also do the same on a resource bundle.
FYI,
Rommel Pino
Can not run in Weblogic 10.3.3?
ReplyDeleteAny thoughts on how you would approach validating a class that has more than one start and end date.
ReplyDelete