Annotations in JAVA

Notes

  • The article was written on the basis of a course from Oracle “Learning the Java language”section “Annotations”.

  • The article is suitable for those who have met annotations in practice and want to deepen or refresh their theoretical knowledge.

Annotation Basics

Definition

Annotations are a form of metadata. They provide information about the program, but they are not part of the program themselves.

Application

  • Information for the compiler. Can be used by the compiler to detect errors and suppress warnings.

  • Processing at compile time and deployment. The program can create code, XML files, and so on. based on annotations.

  • Processing at run time. Some annotations can be used at runtime.

Syntax

Start with @may include elements that are assigned values:

@Author(
    name = "Benjamin Franklin"
    date = "3/27/2003"
)
class MyClass{...}

If there is only one such element, its name can be omitted:

@SupressWarnings("unchecked")
void MyMethod() {...}

If there are no such elements, you can omit the parentheses. You can use multiple annotations in one declaration:

@Author(name = "Jane Doe")
@EBook 
class MyClass { ... }

Annotations can be repeated.

@Author(name = "Jane Doe")
@Author(name = "John Smith")
class MyClass { ... }

Where can annotations be used in code?

Annotations are applied to declarations of classes, fields, and other program elements.

Annotations used on types are called type annotations. Examples of such annotations:

new @Interned MyObject(); 
myString = (@NonNull String) str;
class UnmodifiableList<T>
    implements @Readonly List<@Readonly T> { ... }
void monitorTemperature() throws
    @Critical TemperatureException { ... }

Creating an annotation

Syntax

The description of an annotation resembles the description of an interface. It starts with @Interfaceand its elements are like methods that can have default values.

Example

For example, in some IT company, the bodies of all classes begin with comments containing important information:

public class Generation3List extends Generation2List { 

    // Author: John Doe 
    // Date: 3/17/2002
    // Current revision: 6 
    // Last modified: 4/12/2004 
    // By: Jane Doe 
    // Reviewers: Alice, Bill, Cindy 
    // class code goes here
 }

Description of the annotation that will replace the comments:

@interface ClassPreamble {
    String author();
    String date(); 
    int currentRevision() default 1; 
    String lastModified() default "N/A";
    String lastModifiedBy() default "N/A"; 
    // Можно использовать массив
    String[] reviewers(); 
 }

Using the generated annotation:

@ClassPreamble ( 
    author = "John Doe", 
    date = "3/17/2002", 
    currentRevision = 6, 
    lastModified = "4/12/2004", 
    lastModifiedBy = "Jane Doe", 
    reviewers = {"Alice", "Bob", "Cindy"} 
) 
public class Generation3List extends Generation2List {
...
...
} 

Comment: to add an annotation to Javadocs, you need to use @Documented:

import java.lang.annotation.*; 

@Documented 
@interface ClassPreamble { 
    // Описание элементов аннотации 
}

Predefined annotations

Java has annotations that are described in advance. Some of them provide information for the compiler, some apply to other annotations.

Annotations used by the compiler

They are located in the java.lang package.

@Deprecated

The element marked with this annotation is deprecated and should no longer be used (it’s worth noting in the Javadoc). If there is such an element in the program, the compiler will generate a warning.

// Комментарий Javadoc:
/** 
* @deprecated 
* объяснение, почему метод устарел.
*/ 
@Deprecated 
static void deprecatedMethod() { }

@Override

Informs the compiler that the annotated element should override the parent class element. If redefined incorrectly, the compiler will generate an error.

@Override
int overriddenMethod() { }

@SuppressWarnings

Suppresses compiler-generated warnings.

Warnings are divided into unchecked (unchecked) and obsolete (deprecation). The first ones occur when using deprecated code written before generics, the second – when using code marked with the @Deprecated annotation.

You can suppress one category or both at once:

@SuppressWarnings({"unchecked", "deprecation"})

@SafeVarargs

Applied to a method or constructor and asserts that the code does not perform potentially unsafe operations on varargs parameters. Using the annotation suppresses unchecked warnings associated with varargs.

@SafeVarargs // На самом деле не безопасно!
static void m(List<String>... stringLists) { 
    Object[] array = stringLists; 
    List<Integer> tmpList = Arrays.asList(42);
    array[0] = tmpList; //Написано неверно, но скомпилируется без предупреждения
    String s = stringLists[0].get(0); //ClassCastException 
}

@FunctionalInterface

Used when describing a functional interface. Emphasizes that this is a functional interface.

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

}

Annotations that apply to other annotations (meta-annotations)

They are located in the java.lang.annotation package.

@Retention

Specifies how long the marked annotation is kept.

  • RetentionPolicy.SOURCE. The marked annotation is stored only at the source code level and is ignored by the compiler.

  • RetentionPolicy.CLASS. Stored by the compiler at compile time, but ignored by the JVM.

  • RetentionPolicy.RUNTIME. Stored by the JVM for use during program execution.

@Documented

Specifies that the annotation should be documented in a Javadoc (annotations are not documented by default).

@Target

Specifies the access rights of the annotation (to which elements it can be applied). In the annotation @Target one of the following values ​​is specified:

  • ElementType.ANNOTATION_TYPE. Applied to annotation

  • ElementType.CONSTRUCTOR. Applies to the constructor.

  • ElementType.FIELD. Applies to a field or property.

  • ElementType.LOCAL_VARIABLE. Applies to a local variable.

  • ElementType.METHOD. Applied to a method.

  • ElementType.PARAMETER. Applies to a method parameter.

  • ElementType.TYPE. Applies to any member of the class.

@Inherited

The annotation will be inherited by the child class (annotations are not inherited by default). Applies to class definitions only.

@Repeatable

Specifies that the annotation is repeated.

Repeating annotations

Definition

Annotations that can be applied to the same element more than once.

Example

Let’s say you need to write an annotation that runs a method at a given time or schedule. In the example, the created annotation @Schedule will run the method every last day of the month and every Friday at 23:00.

@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23") 
public void doPeriodicCleanup() { ... }

Create a repeating annotation

For backwards compatibility, repeated annotations are stored in an annotation container, which is automatically generated by the java compiler. The following descriptions are required for generation:

  1. Description of the repeating annotation

The annotation must be marked with @Repeatable, the annotation container type is indicated in parentheses.

import java.lang.annotation.Repeatable;

@Repeatable(Schedules.class) 
public @interface Schedule { 
    String dayOfMonth() default "first"; 
    String dayOfWeek() default "Mon"; 
    int hour() default 12; 
}

The container must contain an array of repeated annotations.

public @interface Schedules { 
    Schedule[] value(); 
} 

Getting duplicate annotations

The Reflection API provides methods for getting annotations. When receiving duplicate annotations, the behavior of methods that return a single annotation (for example, AnnotatedElement.getAnnotation(Class<T>)) does not change. If you need to return more than one, then you must first get the container. Therefore, the legacy code continues to work. You can also use the Java SE 8 methods (‘AnnotatedElement.getAnnotationsByType(Class)’) to get duplicate annotations.

For information about all methods, refer to the class documentation AnnotatedElement.

Type annotations

Definition

Type annotations are annotations that are applied along with types. Wherever you see a type, you can use this annotation. For example, with the new operator, when casting, when implementing, and when using throws.

Creating Type Annotations

To create type annotations in @Target The following values ​​are specified, or one of them:

@Target ({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public @interface Test {

}

TYPE_PARAMETERmeans that the annotation can be applied to type variables (for example, MyClass<T>). TYPE_USEallows use with any types.

Application

Type annotations are intended for better program parsing and stronger type checking. For example, @NonNull String str;. Java SE8 defines type annotations but does not implement them. Instead, it is suggested to use third-party frameworks that implement them (Checker Framework).

Similar Posts

Leave a Reply