Buscar..


Introducción

En Java, una anotación es una forma de metadatos sintácticos que se pueden agregar al código fuente de Java. Proporciona datos sobre un programa que no forma parte del programa en sí. Las anotaciones no tienen ningún efecto directo en el funcionamiento del código que anotan. Clases, métodos, variables, parámetros y paquetes pueden ser anotados.

Sintaxis

  • @AnnotationName // 'Anotación de marcador' (sin parámetros)
  • @AnnotationName (someValue) // establece el parámetro con el nombre 'valor'
  • @AnnotationName (param1 = value1) // parámetro con nombre
  • @AnnotationName (param1 = value1, param2 = value2) // múltiples parámetros nombrados
  • @AnnotationName (param1 = {1, 2, 3}) // parámetro de matriz con nombre
  • @AnnotationName ({value1}) // array con un solo elemento como parámetro con el nombre 'value'

Observaciones

Tipos de parametros

Solo se permiten expresiones constantes de los siguientes tipos para los parámetros, así como matrices de estos tipos:

  • String
  • Class
  • tipos primitivos
  • Tipos de enumeración
  • Tipos de anotaciones

Anotaciones incorporadas

La edición estándar de Java viene con algunas anotaciones predefinidas. No es necesario que los defina por sí mismo y puede usarlos inmediatamente. Permiten al compilador habilitar algunas comprobaciones fundamentales de métodos, clases y código.

@Anular

Esta anotación se aplica a un método y dice que este método debe anular un método de superclase o implementar una definición de método de superclase abstracta. Si esta anotación se utiliza con cualquier otro tipo de método, el compilador arrojará un error.

Superclase de concreto

public class Vehicle {
   public void drive() {
        System.out.println("I am driving");
   }
}

class Car extends Vehicle {
    // Fine
    @Override
    public void drive() {
        System.out.prinln("Brrrm, brrm");
    }
}

Clase abstracta

abstract class Animal  {
   public abstract void makeNoise(); 
}

class Dog extends Animal {
    // Fine
    @Override
    public void makeNoise() {
        System.out.prinln("Woof");
    }
}

No funciona

class Logger1 {
    public void log(String logString) {
        System.out.prinln(logString);
    }
}

class Logger2 {
    // This will throw compile-time error. Logger2 is not a subclass of Logger1. 
    // log method is not overriding anything
    @Override
    public void log(String logString) {
        System.out.println("Log 2" + logString);
    }
}

El propósito principal es detectar errores, donde crees que estás anulando un método, pero en realidad estás definiendo uno nuevo.

class Vehicle {
   public void drive() {
        System.out.println("I am driving");
   }
}

class Car extends Vehicle {
    // Compiler error. "dirve" is not the correct method name to override.
    @Override
    public void dirve() {
        System.out.prinln("Brrrm, brrm");
    }
}

Tenga en cuenta que el significado de @Override ha cambiado con el tiempo:

  • En Java 5, significaba que el método anotado tenía que anular un método no abstracto declarado en la cadena de superclase.
  • Desde Java 6 en adelante, también se satisface si el método anotado implementa un método abstracto declarado en la jerarquía de superclase / interfaz de clases.

(Ocasionalmente, esto puede causar problemas al realizar un back-port del código a Java 5.)

@Obsoleto

Esto marca el método como obsoleto. Puede haber varias razones para esto:

  • la API es defectuosa y no es práctico de arreglar,

  • el uso de la API puede llevar a errores,

  • la API ha sido sustituida por otra API,

  • la API está obsoleta,

  • la API es experimental y está sujeta a cambios incompatibles,

  • o cualquier combinación de los anteriores.

El motivo específico de la desaprobación se puede encontrar en la documentación de la API.


La anotación hará que el compilador emita un error si lo usa. Los IDE también pueden resaltar este método de alguna manera como desaprobado

class ComplexAlgorithm {
    @Deprecated
    public void oldSlowUnthreadSafeMethod() {
        // stuff here
    }
    
    public void quickThreadSafeMethod() {
        // client code should use this instead
    }
}

@SuppressWarnings

En casi todos los casos, cuando el compilador emite una advertencia, la acción más apropiada es corregir la causa. En algunos casos (por ejemplo, el código genérico que usa un código pre-genérico seguro para los tipos) puede que no sea posible y es mejor suprimir las advertencias que espera y no puede corregir, por lo que puede ver más claramente las advertencias inesperadas.

Esta anotación se puede aplicar a toda una clase, método o línea. Toma la categoría de advertencia como parámetro.

@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
    // several methods calling deprecated code here
}

@SuppressWarning("finally")
public boolean checkData() {
    // method calling return from within finally block
}

Es mejor limitar el alcance de la anotación tanto como sea posible, para evitar que también se supriman las advertencias inesperadas. Por ejemplo, al limitar el alcance de la anotación a una sola línea:

ComplexAlgorithm algorithm = new ComplexAlgorithm();
@SuppressWarnings("deprecation") algoritm.slowUnthreadSafeMethod(); 
// we marked this method deprecated in an example above

@SuppressWarnings("unsafe") List<Integer> list = getUntypeSafeList(); 
// old library returns, non-generic List containing only integers

Las advertencias admitidas por esta anotación pueden variar de compilador a compilador. Solo las advertencias unchecked y de deprecation se mencionan específicamente en el JLS. Se ignorarán los tipos de advertencia no reconocidos.

@SafeVarargs

Debido al borrado de tipo, el void method(T... t) se convertirá al void method(Object[] t) lo que significa que el compilador no siempre puede verificar que el uso de varargs es de tipo seguro. Por ejemplo:

private static <T> void generatesVarargsWarning(T... lists) {

Hay casos en que el uso es seguro, en cuyo caso puede anotar el método con la anotación SafeVarargs para suprimir la advertencia. Esto obviamente oculta la advertencia si su uso no es seguro también.

@FunctionalInterface

Esta es una anotación opcional utilizada para marcar un FunctionalInterface. Hará que el compilador se queje si no cumple con la especificación FunctionalInterface (tiene un solo método abstracto)

@FunctionalInterface
public interface ITrade {
  public boolean check(Trade t);
}

@FunctionalInterface
public interface Predicate<T> {
  boolean test(T t);
}

Comprobaciones de anotación en tiempo de ejecución a través de la reflexión.

La API de Reflection de Java permite al programador realizar varias comprobaciones y operaciones en campos de clase, métodos y anotaciones durante el tiempo de ejecución. Sin embargo, para que una anotación sea visible en el tiempo de ejecución, la RetentionPolicy debe cambiarse a RUNTIME , como se muestra en el siguiente ejemplo:

@interface MyDefaultAnnotation {

}

@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeVisibleAnnotation {

}

public class AnnotationAtRuntimeTest {

    @MyDefaultAnnotation
    static class RuntimeCheck1 {
    }
    
    @MyRuntimeVisibleAnnotation
    static class RuntimeCheck2 {
    }
    
    public static void main(String[] args) {
        Annotation[] annotationsByType = RuntimeCheck1.class.getAnnotations();
        Annotation[] annotationsByType2 = RuntimeCheck2.class.getAnnotations();

        System.out.println("default retention: " + Arrays.toString(annotationsByType));
        System.out.println("runtime retention: " + Arrays.toString(annotationsByType2));
    }
}

Definición de tipos de anotación.

Los tipos de anotación se definen con @interface . Los parámetros se definen de manera similar a los métodos de una interfaz regular.

@interface MyAnnotation {
    String param1();
    boolean param2();
    int[] param3();  // array parameter 
}

Valores predeterminados

@interface MyAnnotation {
    String param1() default "someValue";
    boolean param2() default true;
    int[] param3() default {};
}

Meta-Anotaciones

Las meta-anotaciones son anotaciones que se pueden aplicar a los tipos de anotación. La meta-anotación predefinida especial define cómo se pueden usar los tipos de anotación.

@Objetivo

La meta-anotación de @Target restringe los tipos a los que se puede aplicar la anotación.

@Target(ElementType.METHOD)
@interface MyAnnotation {
    // this annotation can only be applied to methods
}

Se pueden agregar varios valores utilizando la notación de matriz, por ejemplo, @Target({ElementType.FIELD, ElementType.TYPE})

Valores disponibles

Tipo de elemento objetivo ejemplo de uso en el elemento de destino
ANNOTATION_TYPE tipos de anotaciones
@Retention(RetentionPolicy.RUNTIME) 
@interface MyAnnotation
CONSTRUCTOR constructores
@MyAnnotation
public MyClass() {}
CAMPO campos, constantes de enumeración
@XmlAttribute
private int count;
VARIABLE LOCAL Declaraciones variables dentro de los métodos.
for (@LoopVariable int i = 0; i < 100; i++) {
@Unused
String resultVariable;
}
PAQUETE paquete (en package-info.java )
@Deprecated
package very.old;
MÉTODO metodos
@XmlElement
public int getCount() {...}
PARÁMETRO Parámetros de método / constructor
public Rectangle(
@NamedArg("width") double width,
@NamedArg("height") double height) {
...
}
TIPO clases, interfaces, enumeraciones
@XmlRootElement
public class Report {}
Java SE 8
Tipo de elemento objetivo ejemplo de uso en el elemento de destino
TYPE_PARAMETER Declaraciones de parámetros de tipo
public <@MyAnnotation T> void f(T t) {}
TYPE_USE Uso de un tipo
Object o = "42";
String s = (@MyAnnotation String) o;

@Retencion

La meta-anotación de @Retention define la visibilidad de la anotación durante el proceso de compilación o ejecución de las aplicaciones. De forma predeterminada, las anotaciones se incluyen en los archivos .class , pero no son visibles en tiempo de ejecución. Para hacer que una anotación sea accesible en tiempo de ejecución, RetentionPolicy.RUNTIME debe establecerse en esa anotación.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    // this annotation can be accessed with reflections at runtime
}

Valores disponibles

Política de retención Efecto
CLASE La anotación está disponible en el archivo .class , pero no en tiempo de ejecución
RUNTIME La anotación está disponible en tiempo de ejecución y se puede acceder a través de la reflexión
FUENTE La anotación está disponible en tiempo de compilación, pero no se agrega a los archivos .class . La anotación se puede utilizar, por ejemplo, por un procesador de anotaciones.

@Documentado

La meta-anotación @Documented se usa para marcar anotaciones cuyo uso debe ser documentado por los generadores de documentación API como javadoc . No tiene valores. Con @Documented , todas las clases que usan la anotación la incluirán en su página de documentación generada. Sin @Documented , no es posible ver qué clases usan la anotación en la documentación.

@Heredado

La meta-anotación @Inherited es relevante para las anotaciones que se aplican a las clases. No tiene valores. Marcar una anotación como @Inherited altera la forma en que funciona la consulta de anotación.

  • Para una anotación no heredada, la consulta solo examina la clase que se está examinando.
  • Para una anotación heredada, la consulta también verificará la cadena de superclase (recursivamente) hasta que se encuentre una instancia de la anotación.

Tenga en cuenta que solo se consultan las superclases: se ignorarán todas las anotaciones asociadas a las interfaces en la jerarquía de clases.

@Repeable

La meta-anotación @Repeatable se agregó en Java 8. Indica que se pueden adjuntar múltiples instancias de la anotación al destino de la anotación. Esta meta-anotación no tiene valores.

Obtención de valores de anotación en tiempo de ejecución

Puede obtener las propiedades actuales de la anotación utilizando Reflexión para obtener el Método o el Campo o la Clase que tiene aplicada una anotación, y luego obtener las propiedades deseadas.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    String key() default "foo";
    String value() default "bar";
}


class AnnotationExample {
    // Put the Annotation on the method, but leave the defaults
    @MyAnnotation
    public void testDefaults() throws Exception {
        // Using reflection, get the public method "testDefaults", which is this method with no args
        Method method = AnnotationExample.class.getMethod("testDefaults", null);

        // Fetch the Annotation that is of type MyAnnotation from the Method
        MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

        // Print out the settings of the Annotation
        print(annotation);
    }

    //Put the Annotation on the method, but override the settings
    @MyAnnotation(key="baz", value="buzz")
    public void testValues() throws Exception {
        // Using reflection, get the public method "testValues", which is this method with no args
        Method method = AnnotationExample.class.getMethod("testValues", null);

        // Fetch the Annotation that is of type MyAnnotation from the Method
        MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

        // Print out the settings of the Annotation
        print(annotation);
    }

    public void print(MyAnnotation annotation) {
        // Fetch the MyAnnotation 'key' & 'value' properties, and print them out 
        System.out.println(annotation.key() + " = " + annotation.value());
    }

    public static void main(String[] args) {
        AnnotationExample example = new AnnotationExample();
        try {
            example.testDefaults();
            example.testValues();
        } catch( Exception e ) {
            // Shouldn't throw any Exceptions
            System.err.println("Exception [" + e.getClass().getName() + "] - " + e.getMessage());
            e.printStackTrace(System.err);
        }
    }
}

La salida será

foo = bar
baz = buzz

Repetir anotaciones

Hasta Java 8, dos instancias de la misma anotación no se podían aplicar a un solo elemento. La solución estándar era usar una anotación de contenedor que contenga una matriz de alguna otra anotación:

// Author.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
    String value();
}

// Authors.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
    Author[] value();
}

// Test.java
@Authors({
    @Author("Mary"),
    @Author("Sam")
})
public class Test {
    public static void main(String[] args) {
        Author[] authors = Test.class.getAnnotation(Authors.class).value();
        for (Author author : authors) {
            System.out.println(author.value());
            // Output:
            // Mary
            // Sam
        }
    }
}
Java SE 8

Java 8 proporciona una forma más limpia y transparente de usar anotaciones de contenedor, utilizando la anotación @Repeatable . Primero agregamos esto a la clase de Author :

@Repeatable(Authors.class)

Esto le dice a Java que trate las múltiples anotaciones de @Author como si estuvieran rodeadas por el contenedor @Authors . También podemos usar Class.getAnnotationsByType() para acceder a la matriz @Author por su propia clase, en lugar de a través de su contenedor:

@Author("Mary")
@Author("Sam")
public class Test {
    public static void main(String[] args) {
        Author[] authors = Test.class.getAnnotationsByType(Author.class);
        for (Author author : authors) {
            System.out.println(author.value());
            // Output:
            // Mary
            // Sam
        }
    }
}

Anotaciones heredadas

Por defecto, las anotaciones de clase no se aplican a los tipos que las extienden. Esto se puede cambiar agregando la anotación @Inherited a la definición de anotación

Ejemplo

Considere las siguientes 2 anotaciones:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {
}

y

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UninheritedAnnotationType {
}

Si se anotan tres clases así:

@UninheritedAnnotationType
class A {
}

@InheritedAnnotationType
class B extends A {
}

class C extends B {
}

ejecutando este código

System.out.println(new A().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(new A().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(UninheritedAnnotationType.class));

imprimirá un resultado similar a este (dependiendo de los paquetes de la anotación):

null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null

Tenga en cuenta que las anotaciones solo pueden heredarse de las clases, no de las interfaces.

Procesamiento de tiempo de compilación utilizando procesador de anotación

Este ejemplo muestra cómo realizar la comprobación de tiempo de compilación de un elemento anotado.

La anotacion

La anotación @Setter es un marcador que se puede aplicar a los métodos. La anotación se descartará durante la compilación y no estará disponible posteriormente.

package annotation;

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

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Setter {
}

El procesador de anotaciones.

El SetterProcessor utiliza la clase SetterProcessor para procesar las anotaciones. Comprueba, si los métodos anotados con la anotación @Setter son public , static métodos no static con un nombre que comienza con set y que tienen una letra mayúscula como cuarta letra. Si una de estas condiciones no se cumple, se escribe un error en el Messager . El compilador escribe esto en stderr, pero otras herramientas podrían usar esta información de manera diferente. Por ejemplo, el IDE de NetBeans permite al usuario especificar procesadores de anotación que se utilizan para mostrar mensajes de error en el editor.

package annotation.processor;

import annotation.Setter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {

    private Messager messager;

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // get elements annotated with the @Setter annotation
        Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(Setter.class);

        for (Element element : annotatedElements) {
            if (element.getKind() == ElementKind.METHOD) {
                // only handle methods as targets
                checkMethod((ExecutableElement) element);
            }
        }

        // don't claim annotations to allow other processors to process them
        return false;
    }

    private void checkMethod(ExecutableElement method) {
        // check for valid name
        String name = method.getSimpleName().toString();
        if (!name.startsWith("set")) {
            printError(method, "setter name must start with \"set\"");
        } else if (name.length() == 3) {
            printError(method, "the method name must contain more than just \"set\"");
        } else if (Character.isLowerCase(name.charAt(3))) {
            if (method.getParameters().size() != 1) {
                printError(method, "character following \"set\" must be upper case");
            }
        }

        // check, if setter is public
        if (!method.getModifiers().contains(Modifier.PUBLIC)) {
            printError(method, "setter must be public");
        }

        // check, if method is static
        if (method.getModifiers().contains(Modifier.STATIC)) {
            printError(method, "setter must not be static");
        }
    }

    private void printError(Element element, String message) {
        messager.printMessage(Diagnostic.Kind.ERROR, message, element);
    }

    @Override
    public void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);

        // get messager for printing errors
        messager = processingEnvironment.getMessager();
    }

}

embalaje

Para ser aplicado por el compilador, el procesador de anotaciones debe estar disponible para el SPI (ver ServiceLoader ).

Para hacer esto, se debe agregar un archivo de texto META-INF/services/javax.annotation.processing.Processor al archivo jar que contiene el procesador de anotaciones y la anotación además de los otros archivos. El archivo debe incluir el nombre completo del procesador de anotaciones, es decir, debe tener este aspecto

annotation.processor.SetterProcessor

Asumiremos que el archivo jar se llama AnnotationProcessor.jar continuación.

Ejemplo de clase anotada

La siguiente clase es una clase de ejemplo en el paquete predeterminado con las anotaciones aplicadas a los elementos correctos de acuerdo con la política de retención. Sin embargo, solo el procesador de anotaciones solo considera el segundo método como un objetivo de anotación válido.

import annotation.Setter;

public class AnnotationProcessorTest {
    
    @Setter
    private void setValue(String value) {}

    @Setter
    public void setString(String value) {}
    
    @Setter
    public static void main(String[] args) {}
    
}

Usando el procesador de anotaciones con javac

Si el procesador de anotaciones se descubre utilizando el SPI, se utiliza automáticamente para procesar elementos anotados. Ej. Compilar la clase AnnotationProcessorTest usando

javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java

produce la siguiente salida

AnnotationProcessorTest.java:6: error: setter must be public
    private void setValue(String value) {}
                 ^
AnnotationProcessorTest.java:12: error: setter name must start with "set"
    public static void main(String[] args) {}
                       ^
2 errors

En lugar de compilar normalmente. No se crea ningún archivo .class .

Esto se podría evitar especificando la opción -proc:none para javac . También puede renunciar a la compilación habitual especificando -proc:only lugar.

Integración IDE

Netbeans

Los procesadores de anotación se pueden utilizar en el editor de NetBeans. Para hacer esto, el procesador de anotaciones debe especificarse en la configuración del proyecto:

  1. Build a Project Properties > Compiling > Compiling

  2. agregar marcas de verificación para Enable Annotation Processing y Enable Annotation Processing in Editor

  3. haga clic en Add junto a la lista de procesadores de anotaciones

  4. en la ventana emergente que aparece, ingrese el nombre de clase completamente calificado del procesador de anotaciones y haga clic en Ok .

Resultado

Ventana del editor con mensaje de error personalizado

La idea detrás de las anotaciones.

La especificación del lenguaje Java describe las anotaciones de la siguiente manera:

Una anotación es un marcador que asocia información con una construcción de programa, pero no tiene efecto en el tiempo de ejecución.

Las anotaciones pueden aparecer antes de los tipos o declaraciones. Es posible que aparezcan en un lugar donde se puedan aplicar tanto a un tipo como a una declaración.
A qué se aplica exactamente una anotación se rige por la "meta-anotación" @Target . Consulte "Definición de tipos de anotación" para obtener más información.

Las anotaciones se utilizan para una multitud de propósitos. Los marcos como Spring y Spring-MVC hacen uso de anotaciones para definir dónde se deben inyectar las dependencias o dónde se deben enrutar las solicitudes.

Otros marcos usan anotaciones para la generación de código. Lombok y JPA son ejemplos principales, que usan anotaciones para generar código Java (y SQL).

Este tema tiene como objetivo proporcionar una visión global de:

  • ¿Cómo definir tus propias anotaciones?

  • ¿Qué anotaciones proporciona el lenguaje Java?

  • ¿Cómo se utilizan las anotaciones en la práctica?

Anotaciones para 'este' y parámetros del receptor.

Cuando se introdujeron las anotaciones de Java por primera vez, no había ninguna disposición para anotar el objetivo de un método de instancia o el parámetro de constructor oculto para un constructor de clases internas. Esto se solucionó en Java 8 con la adición de declaraciones de parámetros del receptor ; ver JLS 8.4.1 .

El parámetro receptor es un dispositivo sintáctico opcional para un método de instancia o un constructor de clase interno. Para un método de instancia, el parámetro receptor representa el objeto para el que se invoca el método. Para el constructor de una clase interna, el parámetro receptor representa la instancia inmediatamente adjunta del objeto recién construido. De cualquier manera, el parámetro del receptor existe únicamente para permitir que el tipo del objeto representado se indique en el código fuente, de modo que el tipo pueda ser anotado. El parámetro receptor no es un parámetro formal; más precisamente, no es una declaración de ningún tipo de variable (§4.12.3), nunca se vincula a ningún valor pasado como un argumento en una expresión de invocación de método o expresión de creación de instancia de clase calificada, y no tiene ningún efecto en absoluto correr tiempo

El siguiente ejemplo ilustra la sintaxis para ambos tipos de parámetros del receptor:

public class Outer {
    public class Inner {
        public Inner (Outer this) {
           // ...
        }
        public void doIt(Inner this) {
           // ...
        }
    }
}

El único propósito de los parámetros del receptor es permitirle agregar anotaciones. Por ejemplo, puede tener una anotación personalizada @IsOpen cuyo propósito es afirmar que un objeto Closeable no se ha cerrado cuando se llama a un método. Por ejemplo:

public class MyResource extends Closeable {
    public void update(@IsOpen MyResource this, int value) {
        // ...
    }

    public void close() {
        // ...
    }
}

En un nivel, la anotación @IsOpen sobre this podría simplemente servir como documentación. Sin embargo, potencialmente podríamos hacer más. Por ejemplo:

  • Un procesador de anotaciones podría insertar una verificación de tiempo de ejecución de que this no está en estado cerrado cuando se llama a la update .
  • Un verificador de código podría realizar un análisis de código estático para encontrar casos donde this podría cerrarse cuando se llama a la update .

Añadir múltiples valores de anotación

Un parámetro de anotación puede aceptar múltiples valores si se define como una matriz. Por ejemplo, la anotación estándar @SuppressWarnings se define así:

public @interface SuppressWarnings {
    String[] value();
}

El parámetro de value es una matriz de cadenas. Puede establecer varios valores utilizando una notación similar a los inicializadores de matriz:

@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})

Si solo necesita establecer un único valor, se pueden omitir los paréntesis:

@SuppressWarnings("unused") 


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow