Custom Java Annotation tutorial – How often do you use them?

22 02 2014

@Override, @Test and @Deprecated annotations are widely used. They make code more readable and clean. You can facilitate Java Annotations features fully by creating your custom annotation for classes, fields etc.

The use case

Simple example, I figured out to illustrate this post, regards the PersonInfo class. This is in fact data class that contains… well… person info. Some of the data in it may be sensitive personal data (like email address), and some not personal (like name) and some may even not be personal data (like storageId in my example).
Let’s assume that the user of this class needs two print methods: first printing all data, and second to print data that is not sensitive.

The Idea behind it

To mark PersonInfo fields as sensitive data or not, I use custom annotation: @PersonData, that indicates that field is in fact person data, and a flag indicating if it is sensitive (class’ field annotation). Then my print method finds all annotated fields, checks the ‘sensitive’ flag value and decides whether to print particular field, or not.

This finding is made by reflection, the one that is safe and will not cause many errors in runtime, because it operates on classess well known during compilation time.

The source code

As always in my tutorials, you can download the source code from here.

1. How to use a custom annotation

This is the result of applying my custom annotation:

public class PersonInfo {

  private String name;

  private String surname;

  private String email;

  private String phoneNumber;

  private long storageId;


LooksOK, doesn’t it?

2. Parse annotatated fields

The print method (overloaded toString() in my case) algorythm is as follows:

1. it iterates all the fields in PersonInfo class

2. if field is annotated with PersonalData annotation, it checks the ‘sensitive’ flag value

3. if value is marked as sensitive it may decide whether to print it or not

The reflection is used to find all class fields and read their annotations. The method is designed to use it in PersonInfo class, since it uses this object. If you’d wish to put it in another file, you’d have to pass the class as a parameter. Analyze method’s body carefully:

public String processAnnotations(boolean includeSensitiveData) {
  StringBuilder sb = new StringBuilder();
   for(Field classField : this.getClass().getDeclaredFields()) {
    for(Annotation annotation : classField.getAnnotations()) {
     if(annotation.annotationType() == PersonalData.class) {
      PersonalData personalData = (PersonalData) annotation;
      String result = printPersonalData(includeSensitiveData, classField, personalData);
  } catch (IllegalArgumentException | IllegalAccessException e) {

 return sb.toString();

Note: Use Java 7 to compile it. Otherwise refactor the catch block to two separate blocks, each catching one exception.

The printPersonalData() method is as follows:

private String printPersonalData(boolean includeSensitiveData, Field classField, PersonalData personalData)
   throws IllegalAccessException {
  StringBuilder sb = new StringBuilder();
  return sb.toString();

And buildText() is the simple one. It concatenates the field’s name and its value:

private String buildText(Field f) throws IllegalArgumentException, IllegalAccessException {
  return f.getName() + ": " + f.get(this) + "\n";

3. Create your annotation

Creating custom annotation is as simple as creating Java interface. This is the PersonalData annotation’s implementation:


public @interface PersonalData {
  boolean isSensitive();

The interface definitione is simple. It is syntaxed like any other java interface, but with the @interface annotation. The interface withoud methods would be enough to make it work. The boolean isSensitive(); method declaration gives the ability to define more details while annotating the field.

There are three builtin annotations used in front of @interface definition. This is their meaning:

@Documented means that this annotation will appear in JavaDoc

@Target(ElementType.FIELD) indicates that this annotation may be used with fields only. Other options are methods, types, packages, etc.

@Retention(RetentionPolicy.RUNTIME) means that annotation will be preserved at runtime. Other option is SOURCE, meaning that it would be available only at development time.

4. Get the source code

You are welcome to tinker with my code freely, on your own. Just download the source code from here.

Did I help you?
I manage this blog and share my knowledge for free, sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!

%d bloggers like this: