Java Language
Anotaciones
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 | |
CONSTRUCTOR | constructores | |
CAMPO | campos, constantes de enumeración | |
VARIABLE LOCAL | Declaraciones variables dentro de los métodos. | |
PAQUETE | paquete (en package-info.java ) | |
MÉTODO | metodos | |
PARÁMETRO | Parámetros de método / constructor | |
TIPO | clases, interfaces, enumeraciones | |
Tipo de elemento | objetivo | ejemplo de uso en el elemento de destino |
---|---|---|
TYPE_PARAMETER | Declaraciones de parámetros de tipo | |
TYPE_USE | Uso de un tipo | |
@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 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:
Build
aProject Properties
>Compiling
>Compiling
agregar marcas de verificación para
Enable Annotation Processing
yEnable Annotation Processing in Editor
haga clic en
Add
junto a la lista de procesadores de anotacionesen la ventana emergente que aparece, ingrese el nombre de clase completamente calificado del procesador de anotaciones y haga clic en
Ok
.
Resultado
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 laupdate
. - 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 laupdate
.
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")