How to create Custom Annotation in Java?

Reading Time: 2 minutes

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>
view raw

gistfile1.txt

hosted with ❤ by GitHub

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 {};
}
view raw

gistfile1.txt

hosted with ❤ by GitHub

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;
}
}
view raw

gistfile1.txt

hosted with ❤ by GitHub

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;
}
view raw

gistfile1.txt

hosted with ❤ by GitHub

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

Knoldus-Scala-Spark-Services