ZetCode

Java annotations

last modified July 4, 2024

In this article we talk about Java annotations.

Annotations are a special kind of code element that provides additional information about a program. They are attached to classes, methods, fields, and other program elements using the @ symbol.

Annotations themselves don't directly affect how the code runs, but instead provide metadata that can be used by various tools:

Here are some key points about Java annotations:

The @Override annotation

The @Override annotation in Java is specifically used for method overriding in inheritance. It's a marker annotation to improve code clarity and catch errors during compilation.

Here's what @Override does:

@Override is not mandatory for overriding methods. The compiler can usually figure out if a method is intended to override based on the signature. However, it's considered good practice to use @Override for better code clarity and catching potential errors early on.

@Override is not used for implementing methods in interfaces. Interfaces only declare methods, and subclasses implementing interfaces must provide their own implementation. The compiler inherently checks for this relationship.

Main.java
class User {

    private final String firstName;
    private final String lastName;
    private final String occupation;

    public User(String firstName, String lastName, String occupation) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.occupation = occupation;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getOccupation() {
        return occupation;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("User{");
        sb.append("firstName='").append(firstName).append('\'');
        sb.append(", lastName='").append(lastName).append('\'');
        sb.append(", occupation='").append(occupation).append('\'');
        sb.append('}');
        return sb.toString();
    }
}


void main() {

    User[] users = {
        new User("John", "Doe", "gardener"),
        new User("Roger", "Roe", "driver"),
        new User("Paul", "Smith", "teacher"),
    };

    for (User user : users) {
        System.out.println(user);
    }

}

In the example, we override the Object's toString method. The method is annotated with @Override. If the function does not match the parent's one (for instance we use private instead of public) we get a warning: Cannot reduce the visibility of the inherited method from Object.

@Deprecated annotation

The @Deprecated annotation in Java is used to mark classes, methods, fields, or constructors that are no longer recommended for use. It serves as a warning to developers that they should avoid using these elements and consider alternatives.

Key features of the @Deprecated annotation:

Additional features of the @Deprecated annotation (Java 9 onwards):

Main.java
class PassWordGenerator {

    @Deprecated
    public String generatePassword() {
        return "generated password";
    }

    public String generateSecurePassword() {
        return "a secure password";
    }
}

// @SuppressWarnings("deprecation")
void main() {

    var pgen = new PassWordGenerator();
    System.out.println(pgen.generateSecurePassword());
    System.out.println(pgen.generatePassword());
}

In the example, we mark the generatePassword with the @Deprecated annotation, because it is being replaced with a more secure alternative.

The @Deprecated annotation can be suppressed with @SuppressWarnings("deprecation") annotation.

Custom annotation

We can create our own annotations in Java. Key elements of a custom Java annotation are summarized in the following table:

Element Description
@interface Declaration for creating a custom annotation.
@Target Specifies where the annotation can be applied (fields, classes, methods, etc.).
@Retention Determines how long the annotation information is retained (compile-time or runtime).
Elements (methods) Define attributes or parameters for the annotation (with data types and default values).
Doc comments Optional comments to document the annotation and its usage.

The next example creates a custom annotation.

com/zetcode/ClassDescription.java
package com.zetcode;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassDescription {
    String description();
}

We have a ClassDescription that is targeted on classes.

com/ztetcode/AnnotationProcessor.java
package com.zetcode;

import java.util.List;
import java.util.Optional;

public class AnnotationProcessor {

    public void process(List<Object> objects) {
        objects.forEach(obj -> {

            Class<?> clazz = obj.getClass();
            ClassDescription annotation = clazz.getAnnotation(ClassDescription.class);

//            if (annotation != null) {
//                System.out.println(annotation.annotationType().getName());
//                System.out.println(annotation.description());
//            }

            Optional.ofNullable(annotation)
                    .ifPresentOrElse(
                            ann -> {
                                System.out.println(ann.annotationType().getName());
                                System.out.println(ann.description());
                            },
                            () -> System.out.println("No annotation found")
                    );


        });
    }
}

The AnnotationProcessor will process the annotation.

com/zetcode/CustomAnnotation.java
package com.zetcode;

import java.util.List;

@ClassDescription(description = "this is a User class")
class User {

}

@ClassDescription(description = "this is a Test class")
class Test {

}

class Hello {

}


public class CustomAnnotation {

    private String field;

    public static void main(String[] args) {

        List<Object> objects = List.of(new User(), new Test(), new Hello());

        var processor = new AnnotationProcessor();
        processor.process(objects);

    }
}

We have two classes that are decorated with @ClassDescription. We process the instance objects with AnnotationProcessor that will print the description of the decorated class.

Source

Java annotations - tutorial

In this article we covered annotations in Java. We have shown how to use existing annotations and how to create custom one.

Author

My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Java tutorials.