Anotaciones Java
Las últimas versiones de JDK han estado apuntando a la mejora de las facilidades de desarrollo. Una de estas facilidades de desarrollo son las ya conocidas anotaciones.
Una anotación es una forma de añadir metadatos al código fuente de Java que están disponibles para la aplicación en tiempo de ejecución. Cuando se compila el código fuente, el compilador almacena los metadatos de las anotaciones en los ficheros de clases. Posteriormente la JVM (maquina virtual) busca los metadatos para determinar como interactuar con los elementos del programa o cambiar su comportamiento.
Como observan, la ventaja de las anotaciones es que nos permiten declarar en el código fuente como debe comportarse el software. Sin embargo, una de las desventajas mas claras es que añadir metadatos en tiempo de ejecución puede causar sobrecarga adicional de memoria (existen pocos estándares que indiquen como usarlos). A partir de aquí, se hablará sobre las anotaciones de manera mas detallada.
Cuando se habla de anotaciones hay que considerar lo que es una anotación que es una meta-etiqueta que se usa en el código fuente para darle algo de vida, y un tipo de anotación que es la definición de una anotación. Entonces, a partir de ello afirmamos que el tipo de anotación es el que se usa y la anotación es el uso específico de ese tipo.
Un tipo de anotación esta definido de la siguiente manera:
public @interface MiAnotacion{
String mensaje();
}
Una anotación esta definida de la siguiente manera:
@MiAnotacion (mensaje=”Anotación en Java”)
public void MiMetodo(){
//...
}
Los tipos de anotaciones son básicamente tres:
1. Marcador, que son las que no tienen elementos (llameasen elementos a los que están declarados dentro de los paréntesis en la definición) como por ejemplo:
Definición:
public @interface MiAnotacion{}
Uso:
@MiAnotacion
public void MiMetodo(){
//...
}
2. Valor único, que son aquellas que tienen un solo elemento. Este elemento puede estar declarado como un par de nombre-valor o solamente el nombre.
Definición:
public @interface MiAnotacion(){
String mensaje();
}
Nota: Cuando se declara el(los) elemento(s) sin valor, siempre deben de tener al final los paréntesis, caso contrario, cuando se declara el elemento con valor, los paréntesis no van.
public @interface MiAnotacion(){
String mensaje=”Java”;
}
Uso:
@MiAnotacion(mensaje=”Anotación Java”)
public void MiMetodo(){
//...
}
Nota: Por defecto, cuando se trata de un tipo de anotación de valor único, en el uso de la anotación se puede omitir el nombre del elemento.
@MiAnotacion(”Anotación Java”)
public void MiMetodo(){
//...
}
3. Valores múltiples, que son aquellos que tienen más de un elemento declarado. Al igual que en los de valor único, pueden estar definido como un par de nombre-valor o solamente nombre.
Definición:
public @interface MiAnotacion(){
String mensaje();
int cantidad();
}
Uso:
@MiAnotacion(mensaje=”Anotación Java”,cantidad=1)
public void MiMetodo(){
//...
}
Nota: Cuando se trata de un tipo de anotación de valor múltiple, en el uso de la anotación se puede es obligatorio escribir el nombre del elemento.
Las reglas básicas para definir un tipo de anotación son:
- La declaracion de un tipo de anotacion debe empezar con el signo @, seguido de la palabra interface y el nombre de la anotacion.
- Los metodos de las declaraciones (elementos) no deben tener ningun parámetro.
- Los metodos de las declaraciones no deben tener las clasulas throw.
- El tipo de retorno de los metodos deben ser uno de los siguientes:
o Primitives (int, double, float, long, bolean, byte, char)
o String
o Class
o Enum
o Array de algunos tipos mencionados.
JDK posee dos tipos de anotaciones:
1. Anotaciones simples que son los tipos básicos de anotación. No se pueden utilizar estos tipos de anotaciones para crear a partir de ellos un nuevo tipo de anotación.
2. Meta Anotaciones que son los tipos de anotaciones designados para anotar una anotar un tipo de anotación. Comúnmente son denominadas como anotaciones de las anotaciones.
Dentro de las anotaciones simples tenemos tres tipos:
1. Override que indica que el método de la anotación es requerido implementarlo nuevamente para anular al método de la clase superior. Ejemplo:
public class demo{
@Override
public String toString(){
return super.toString() + " usando @Override";
}
public static void main(String[] arhs){
demo d = new demo();
System.out.println(d.toString());
}
}
Que pasaría si el método de la anotación se escribiera mal, por ejemplo si se cambia el nombre del método toString a tostring?. Pues sencillamente el compilador nos advertirá de un error:
Error: method does not override or implement a method
from a supertype
@Override
1 error
Esto es debido a que no existe un método con el nombre tostring perteneciente a una clase superior (jerárquicamente) para anular y volver a sobrescribirlo.
2. Deprecated que indica que cuando se utiliza un elemento (sea atributo, método, etc) obsoleto desde otra clase, el compilador debería advertir sobre ello.
public class demo{
@Deprecated
public void imprimir(){
System.out.println("usando @Deprecated");
}
}
public class test{
public static void main(String[] arhs){
demo d = new demo();
d.imprimir();
}
}
Si compilamos la clase demo, el compilador no debería de mostrarnos ningún mensaje. Pero si compilamos la clase test, el compilador nos mostrara un mensaje (warning) de que el método es obsoleto para su uso.
test.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
3. Suppresswarnings que indica que las advertencias (warnings), que el compilador muestra, sean suprimidas. El tipo de warning que se desea suprimir es dado como argumento en la anotacion (“deprecation”, ”all”, ”try”, etc).
public class demo{
@Deprecated
public void imprimir(){
System.out.println("usando @Deprecated");
}
}
public class test{
@SuppressWarnings("deprecation")
public void star(){
demo d = new demo();
d.imprimir();
}
public static void main(String[] arhs){
new test().star();
}
}
Si compilamos la clase test, el compilador no mostrará ningún mensaje de obsolescencia de método (deprecated) debido a que ese warning ha sido suprimido por el método star que es el que tiene la anotación SuppressWarnings. Sin embargo ese warning ha sido de alguna manera resguardado por el compilador.
Las Meta Anotaciones, más conocidas como anotaciones de las anotaciones, tienen 4 tipos:
1. Target que indican los elementos específicos de una clase en la que el tipo de anotación se le aplicará. Entre ellos tenemos:
@Target(ElementType.TYPE)– aplicable a cualquier elemento de una clase.@Target(ElementType.FIELD)– aplicable a propiedades o atributos de una clase.@Target(ElementType.METHOD)– aplicable a métodos de una clase.@Target(ElementType.PARAMETER)– aplicable a parámetros de un método .@Target(ElementType.CONSTRUCTOR)– aplicable a constructores.@Target(ElementType.LOCAL_VARIABLE)– aplicable a variables locales.- @Target(ElementType.ANNOTATION_TYPE) – indica que la declaración del mismo tipo es un tipo de anotación.
En el siguiente ejemplo, primero definimos el tipo de anotación. El código lo guardamos en un archivo llamado anotacion.java
import java.lang.annotation.*;
@Target(ElementType.METHOD)
public @interface anotacion{
public String mensaje();
}
Uso del tipo de anotación:
public class test{
@anotacion(mensaje="target")
public void star(){
System.out.println("usando @Target");
}
public static void main(String[] arhs){
new test().star();
}
}
El tipo de anotación creada indica que solamente puede ser utilizable para métodos. Entonces, si compilamos en código anterior, no habrá mensajes de advertencia. Ahora ¿que pasará si la anotación la usamos para una variable?.
public class test{
@anotacion(mensaje="target")
String variable = "";
public void star(){
System.out.println("usando @Target");
}
public static void main(String[] arhs){
new test().star();
}
}
Sencillamente el compilador mostrará un error en el que nos informa que el tipo de anotacion que se esta usando no es valida para el elemento de la clase (variable).
annotation type not applicable to this kind of declaration
@anotacion(mensaje="target")
1 error
Nota: Si se desea utilizar un tipo de anotación para varios elementos, estos tendrán que ser declarados separados por comas.
//...
@Target(ElementType.METHOD, ElementType.FIELD)
//...
2. Retention que indican donde las anotaciones serán tomadas en cuenta. Dentro de estas anotaciones existen tres valores:
RetentionPolicy.SOURCE– las anotaciones serán tomadas en cuenta a nivel de código fuente y serán ignoradas por el compilador.RetentionPolicy.CLASS– las anotaciones serán tomadas en cuenta por el compilador pero serán ignoradas por la JVM (maquina virtual).RetentionPolicy.RUNTIME– las anotaciones serán tomadas en cuenta por la JVM (maquina virtual) en tiempo de ejecución.
En el siguiente código mostramos un tipo de anotación que será tomada en cuenta en tiempo de ejecución.
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface anotacion{
public String mensaje();
}
3. Documented que indican que las anotaciones debería ser documentada por la herramienta javadoc. Por defecto, las anotaciones no están incluidas en javadoc, sin embargo las anotaciones deberían de estar incluidas en la generación del documento.
En el siguiente código mostramos dos tipos de anotaciones (una retention y otra documented) en donde la notación documented será documentada por la herramienta javadoc.
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface retention{
public String mensaje();
}
import java.lang.annotation.*;
@Documented
public @interface documented{
public String mensaje();
}
public class test{
@retention(mensaje="anotacion java")
public void imprime_retention(){
System.out.println("usando @Retention");
}
@documented(mensaje="anotacion java")
public void imprime_documented(){
System.out.println("usando @Documented");
}
public static void main(String[] arhs){
new test().imprime_retention();
new test().imprime_documented();
}
}
Luego de ello procederemos a documentar las clases antes descritas utilizando la herramienta javadoc. En linea de comando se logra con el comando:
#javadoc test.java
Y lo que obtendremos es un archivo html en donde se puede observar que el método imprime_retention no tiene información sobre el tipo de anotación que se la ha asignado, sin embargo para el método imprimir_documented si lo tiene por el mismo hecho de haberle colocado una anotación de tipo documented.

4. Inherited que indica que la clase de la anotación pueden ser heredada por cualquier otra subclase. Más detalladamente, si se define una anotación inherited las subclases descendientes obtienen todas las propiedades de la clase madre, al mismo estilo que la herencia tradicional de Java.
Vamos a ver en el siguiente código como una anotación es heredada de otra anotación.
Anotación padre:
import java.lang.annotation.*;
@Inherited
public @interface padre{
public boolean esHeredada() default true;
public String mensaje() default "Anotacion";
}
Anotación hijo:
@padre
public class hijo{
//...
}
Como se puede observar, no se tiene que definir los métodos de la interfaz dentro de la clase, pues éstos son heredados automáticamente al utilizar la etiqueta @Inherited.
Ahora se tendra en la cabeza: que pasaria si se define la clase hijo al estico clasico de Java, es decir, hacer descender de la clase padre con “implements”?. En este caso si tendra que redefinir todos los metodos pertenecientes a la interfaz (clase padre) ademas de redefinir los metodos equals(), toString(), y hasCode() de la clase java.lang.Object y annotationType () de la clase java.lang. annotation.Annotation.
Entonces nuestra clase hijo seria algo así:
import java.lang.annotation.*;
public class hijo implements padre{
public boolean esHeredada(){
return false;
}
public String mensaje(){
return "";
}
public boolean equals(Object obj){
return false;
}
public int hasCode(){
return 0;
}
public String toString(){
return "";
}
public Class annotationType(){
return null;
}
}
Conclusión
El objetivo es pasar más tiempo en el análisis e implementación de las reglas de negocio (lógica de negocio) y no en el código fuente (la forma como se implementa).
Bibliografía
http://www.developer.com/java/other/article.php/10936_3556176_1
Referencia
http://tirandolineas.wordpress.com/2007/10/23/anotacionesjava/
Una introducción estupenda a las anotaciones, me ha servido de mucho. Un saludo
Elena
6 julio 2009 a 9:49 am
Esta genial, gracias por tu apoyo!!!
Alan
3 febrero 2010 a 4:02 pm
Muy buena tu introduccion a las anotaciones. Me sirvio mucha para entender como funcionan.!!
Cristian
19 febrero 2010 a 1:53 pm
Por fin encontre el material que me permitio comenzar a entender este tema de las Anotaciones en Java..
Muchas gracias por tu aporte.
Carlos Alberto
9 septiembre 2010 a 7:45 pm