Today, I am going to show you a very interesting thing. That is, creating custom annotations and processing them using reflection. We will first create an annotations for fields that will be used to check if the field is null or not.

Creating annotation

Following is the code to create a new annotation named “NotNull” that will be used to validate the field value:

 Java |  copy code |? 
01
02
package com.raistudies;
03
 
04
import java.lang.annotation.ElementType;
05
import java.lang.annotation.Retention;
06
import java.lang.annotation.RetentionPolicy;
07
import java.lang.annotation.Target;
08
 
09
@Target(ElementType.FIELD)
10
@Retention(RetentionPolicy.RUNTIME)
11
public @interface NotNull {
12
 
13
    String message();
14
 
15
}
16

You may notice some new things if you are new to developing custom annotations. Here is the explanation:

  1. @interface : This indicates that the declared interface is an annotation.
  2. @Target : This tells on which type of elements the newly created annotation will be used. Here it is on field types. you can specify other also  ElementType.METHOD, ElementType.PACKAGE and many more as per your need.
  3. @Retention : This indicated the retention type of the annotation or when it will be taken care by the JVM. In our case, it is runtime. You can also set it compile time if you want.

Creating annotation processing class

So, you have created an annotation, now we have to create a processing code that will process object of any class to see if their fields are annotated with @NotNull and the value of the field contains null.

Following is the code:

 Java |  copy code |? 
01
02
package com.raistudies;
03
 
04
import java.lang.reflect.Field;
05
import java.util.ArrayList;
06
import java.util.List;
07
 
08
 
09
public class NotNullChecker {
10
 
11
    public static List<String> validate(Object obj){
12
        List<String> errors = new ArrayList<String>();
13
        Field[] fields = obj.getClass().getFields();
14
        for( int i = 0; i < fields.length; i++ ){
15
            NotNull annotations = (NotNull)fields[i].getAnnotation(NotNull.class);
16
            if(annotations != null ){
17
                try{
18
                    if(fields[i].get(obj) == null){
19
                        errors.add(((NotNull)annotations).message());
20
                    }
21
                }catch(Exception e){
22
                    e.printStackTrace();
23
                }
24
            }
25
        }
26
        return errors;
27
    }
28
 
29
}
30
 
31

The code contains a lot of java refection related code to manipulate the object. The method validate() is responsible for validating an object with respective to the annotations @NotNull. For this, the method performs the following steps:

  • Get all fields from the class of the object using the code obj.getClass().getFields()
  • For each field, it gets the NotNull annotation using getAnnotation(NotNull.class), it will return the annotation object if @NotNull is associated with the field otherwise returns null.
  • If the annotation get in above step is not null then it checks if the value stored in the field of object is null using fields[i].get(obj) == null and on null it add the error message to an array list by getting the error message from annotation object using ((NotNull)annotations).message()
  • Then the method returns the array list object will contains error message if the object has null value fields with annotation @NotNull

Testing the implementation

For testing the created annotation, I have coded a domain class:

 Java |  copy code |? 
01
02
 
03
package com.raistudies.domain;
04
 
05
import com.raistudies.NotNull;
06
 
07
public class Person {
08
 
09
    @NotNull(message="Name can not be null.")
10
    public String name;
11
 
12
    @NotNull(message="Addess of a person can not be null.")
13
    public String address;
14
}
15
 
16

The Person class has two fields with annotated with @NotNull. I have also a tester class that will test by creating the object of the person class and the checking the object:

 Java |  copy code |? 
01
02
 
03
package com.raistudies;
04
 
05
import com.raistudies.domain.Person;
06
import java.util.List;
07
 
08
public class CustomAnnotationRunner {
09
 
10
    public static void main(String... args){
11
        Person p = new Person();
12
        p.name = "Rahul Mondal";
13
        List errors = NotNullChecker.validate(p);
14
        if(errors.isEmpty()){
15
            System.out.print("There is no error in object");
16
        }else{
17
            System.out.print("Errors in object: \n");
18
            for(int i = 0; i< errors.size(); i++){
19
                System.out.print((i+1) + ". " + errors.get(i).toString() + "\n");
20
            }
21
        }
22
    }
23
 
24
}
25

The runner class is creating an object of the class Person and then filling only the value for the field “name” and then call the validate method to check if it returns an error and displaying the result.

The out put of the above program is shown bellow:

Errors in object:
1. Addess of a person can not be null.