The main benefit of annotations doesn't come from using the standard ones that are already in the JDK. At the same time, there is rarely a need to create your own annotation. But if we're developing a large system or creating a separate library, then at the architectural level, implementing our own annotation will definitely yield dividends.

Let's try to create an annotation.

To do this, create a file, but instead of writing class or interface, write @interface. This will be the file for our annotation. The internal structure of an annotation is similar to that of an interface.

public @interface Sum {
   int sum() default 0;

@interface indicates that this is an annotation,
default says that the parameter will have a specific default value.

Ta-da! We created an annotation! Theoretically we can use it already, but first it would be better to configure it.

Without configuration, our annotation can be applied to anything (to classes, methods, attributes, etc.), so it makes little sense to use it at this point. Strange as it may seem, our annotation needs to be annotated with other annotations!

Let's start with @Target.

The @Target annotation (relevant since Java 1.5) restricts the ability to apply an annotation. To limit usage to a certain level, we need to pass an argument to the @Target annotation to indicate which types it can be applied to. Here are some of the commonly used types:

@Target(ElementType.PACKAGE) for packages
@Target(ElementType.TYPE) for classes
@Target(ElementType.CONSTRUCTOR) for constructors
@Target(ElementType.METHOD) for methods
@Target(ElementType.FIELD) for attributes (variables) in a class
@Target(ElementType.PARAMATER) for method parameters
@Target(ElementType.LOCAL_VARIABLE) for local variables

If you need an annotation for several types, then you can pass several arguments as an array:

@Target({ ElementType.PARAMETER, ElementType.LOCAL_VARIABLE })

The next important part of configuration is the @Retention annotation.

This annotation indicates the parts of the code life cycle in which our annotation will be available:

RetentionPolicy.SOURCE Annotations marked with the SOURCE retention policy are discarded at run time.
RetentionPolicy.CLASS Annotations marked with the CLASS retention policy are written to the .class file, but are removed at run time.
RetentionPolicy.RUNTIME Annotations marked with the RUNTIME retention policy persist at run time and can be accessed in our program at run time.

There are a few more annotations you can use for configuration:

Annotation Value
@Inherited Indicates that a derived class inherits a parent class's implementation of the annotation.
@Documented This indicates that the annotation will be included in the generated Javadoc documentation.

Now let's try to create our own annotation.

We'll create an annotation that is for classes and methods and contains information about the code's author and version:

    @Target({ElementType.TYPE, ElementType.METHOD})
public @interface Info {
   String author() default "Author";
   String version() default "0.0";

We can apply our annotation to methods and classes. Our annotation's metadata will be available at run time. Pay attention to our annotation's parameters: We can supply two arguments (author and version), or we can omit them. If we omit them, then the specified default values (default "Author" and default "0.0") will be used.

It is worth noting that we don't have to specify a default value for parameters. In this case, the parameter becomes mandatory.

When passing arguments, we must specify the corresponding parameter using the notation value = "value". The parameter must always be named explicitly, even if the annotation has a single parameter.

Let's apply our annotation to a few classes:

public class MyClass1 {
   public void myClassMethod() {}
@Info(version = "2.0")
public class MyClass2 {
   @Info(author = "Anonymous")
   public void myClassMethod() {}
@Info(author = "Anonymous", version = "2.0")
public class MyClass3 {
   @Info(author = "Anonymous", version = "4.0")
   public void myClassMethod() {}