Creating Custom Annotation in Java

Gulsum Satic
4 min readMar 24, 2024

--

Hello everyone!

Annotations are a fascinating feature in Java. While many developers use them, not everyone realizes how easy it is to create their own custom annotations. In this article, we’ll learn how to create three types of custom annotations and how you can use those annotations to enhance your programs.

What are Annotations in Java?

If you’ve been coding in Java for a while, there are probably at least a couple of annotations that you are familiar with. One example is “@Override”. Annotations serve as a mechanism for developers to annotate their code with additional information, facilitating better organization, documentation, and automation within software projects. Many frameworks also use their own annotations alongside Java’s built-in annotations.

Creating Custom Annotations

The process in Java is quite simple. The @interface keyword is used to declare an annotation.

//@Retention(...) 
//@Target(...)
public @interface CustomAnnotation{
// ...
}

Technically, all you need to create custom annotations involves defining them with the @interface keyword. However, before you can effectively use your custom annotations, there are a few things that you are going to want to customize for your specific needs. Interestingly, you are going to be using some annotations, known as Meta Annotations, namely @Target, @Retention, @Inherited, and @Documented. They can only be used to annotate other annotations. Two of them are the main annotations that we'll focus on.

@Target() : Annotation describes where you can apply your custom annotation. It takes the ElementType enumeration as its only argument, but it is also fine if you do not specify. Since we want the annotation to be valid only on classes, we will use TYPE. Also, we can pass multiple ElementTypes such as @Target({ElementType.TYPE, ElementType.METHOD}).

@Retention() : Annotation is used to determine at which level an annotation will be retained with retention policies. 99% of the time, we use RetentionPolicy.RUNTIME. This keeps the annotation available throughout the actual execution of the program.

Three Types of Custom Annotations

We can categorize annotation types into three main headings: Marker Annotation, Single Value Annotation, and Multi Value Annotation.

1- Marker Annotation do not have any methods. They are used to specify that an entity has a particular quality or represents a specific state. Let’s create example annotation called @Unrepaired which is used to mark electronic devices that have not been repaired:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)// only for fields
public @interface Unrepaired{
}
@Important
public class Electronics {

@Unrepaired
private List<String> smartPhones; // Smartphone has not been repaired.

private List<String> laptops;

private List<String> tablets;
}
public static void main(String[] args) {

Electronics electronics = new Electronics()

for(Field field: electronics.getClass().getDeclaredFields()){
if(field.isAnnotationPresent(Unrepaired.class)){
Unrepaired unrepaired = field.getAnnotation(Unrepaired.class);
System.out.println("Field: " + field.getName() + " has not been repaired.");
}
}
}
// Output: Field: smartPhones has not been repaired.

2- Single Value Annotation contains only one method. This method typically represents the value associated with the annotation.
For example, we can create a single value annotation named @Discount to apply discounts to specific categories of clothing.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)// only for method
public @interface Discount {
double value(); // unusual here we technically have to make this a method
// and not a normal class field so to do that we have to add parenthese.
}
// if we want to specify default value -> double value() default 0.0;
public class Clothing {

@Discount(0.2) // only for tshirt method has discount.
public void tshirt() {
System.out.println("Discount is applied");
}

public void dress() {
System.out.println("There is no discount");
}
}
public static void main(String[] args) {

Clothing clothing = new Clothing();

for(Method method : clothing.getClass().getDeclaredMethods()){
if(method.isAnnotationPresent(Discount.class)){
Discount discount = method.getAnnotation(Discount.class);
System.out.println("Method: " + method.getName() + " has a discount of " + discount.value());
}
}
}
// Output: Method: tshirt has a discount of 0.2

3- Multi Value Annotation have multiple elements and are typically used to specify different properties. For example, let’s create a @Restriction annotation that could be used to control the frequency of calling a method.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)// only for method
public @interface Restriction {
int minFrequency() default 1; // Minimum method invocation frequency
int maxFrequency() default Integer.MAX_VALUE; // Maximum method invocation frequency
}

The minFrequency and maxFrequency elements are used to specify how many times a method can be called. For instance, in an e-commerce application, we could use this annotation to control the frequency of adding an item to the shopping cart within a certain range.

Annotations are a crucial feature that allows us to organize, document, and automate our code effectively. Creating our custom annotations not only enhances the readability and maintainability of our code but also helps make our software projects more efficient.

I hope this article serves as a valuable guide in your Java development journey. Happy coding! 👨‍💻🚀

--

--

Gulsum Satic

As a full-stack Java developer, I discuss a wide range of topics here, particularly focusing on java, spring, reactjs, nextjs.