Hey everyone,
Have you ever faced with the scenario where you have to apply some constraint/validations on your field and the built-in constraints/validations are not sufficient for your application? If yes, then you are at right place. So in this blog, we will learn how we can write our own constraint with the help of the example.
So, our constraint is as follows:
We have to validate whether the input field(of type String) storing date should be either Future Date and should be within the seven day period.
Add the following dependency
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<dependency> | |
<groupId>org.hibernate</groupId> | |
<artifactId>hibernate-validator</artifactId> | |
<version>6.0.10.Final</version> | |
</dependency> |
For creating a custom constraint, We have to create an annotation interface and a validator class that actually consists of the logic for validating the date.
Create Annotation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.validation.Constraint; | |
import javax.validation.Payload; | |
import java.lang.annotation.Documented; | |
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.annotation.Target; | |
@Target({ElementType.METHOD, ElementType.FIELD}) | |
@Retention(RetentionPolicy.RUNTIME) | |
@Constraint(validatedBy = FutureAndWithinSevenDaysValidator.class) | |
public @interface FutureAndWithinSevenDays { | |
String message() default "The date should be future or within the seven days period."; | |
Class<?>[] groups() default {}; | |
Class<? extends Payload>[] payload() default {}; | |
} |
In the above example, you can see multiple annotations. let’s discuss that
@Target({ElementType.METHOD, ElementType.FIELD}): It tells you the contexts in which annotation type is applicable like where annotations may appear in the program (FIELD, TYPE, METHOD, PARAMETER, CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME): It specifies that our custom Annotation will be used by Runtime Environment.
@Constraint(validatedBy = FutureAndWithinSevenDaysValidator.class): It marks the annotation as being a Validation Constraint and validatedBy specifies the Validator class where we have written the logic of validating the input field.
And moreover, you can see the three attributes message, groups, and payload.
In the above example, we have message() having a default value date should be future or within the seven days period which will be reflected when the input field is not valid.
Create Validator Class
This validator class will consist of the logic of validation. Now in the following example, the class consists of a single method: isValid. This isValid method takes the input field and decides whether the input is valid or not.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.validation.ConstraintValidator; | |
import javax.validation.ConstraintValidatorContext; | |
import java.time.LocalDate; | |
import java.time.format.DateTimeFormatter; | |
import java.time.temporal.ChronoUnit; | |
public class FutureAndWithinSevenDaysValidator implements ConstraintValidator<FutureAndWithinSevenDays, String> { | |
@Override | |
public final boolean isValid(final String value, | |
final ConstraintValidatorContext context) { | |
if (value != null) { | |
LocalDate formattedDate = LocalDate.parse(value, DateTimeFormatter.BASIC_ISO_DATE); | |
long day = ChronoUnit.DAYS.between(LocalDate.now(), formattedDate); | |
return formattedDate.isAfter(LocalDate.now()) && day <= 7; | |
} | |
return true; | |
} | |
} |
Now this Custom annotation can be used in the POJO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Person { | |
String id; | |
@FutureAndWithinSevenDays | |
String dateValue; | |
String name; | |
} |
Conclusion
It’s pretty straightforward. If you want to create a customized annotation for validating your field then create an annotation, write the validator class that consists your logic and use it in your POJO.
Hope this is helpful. Please feel free to provide your suggestions 🙂 .
References:
https://beanvalidation.org/2.0/
https://dzone.com/articles/create-your-own-constraint-with-bean-validation-20