En el lenguaje de programación de computadoras Java , una anotación es una forma de metadatos sintácticos que se pueden agregar al código fuente de Java . [1] Se pueden anotar clases , métodos , variables , parámetros y paquetes Java . Al igual que las etiquetas Javadoc , las anotaciones Java se pueden leer desde los archivos fuente. A diferencia de las etiquetas Javadoc , las anotaciones Java también se pueden incrustar y leer en archivos de clase Java generados por el compilador de Java . Esto permite que las anotaciones sean retenidas por la máquina virtual Java entiempo de ejecución y lectura mediante reflexión . [2] Es posible crear meta-anotaciones a partir de las existentes en Java. [3]
Historia
La plataforma Java tiene varios mecanismos de anotación ad-hoc , por ejemplo, el transient
modificador o la @deprecated
etiqueta javadoc. La solicitud de especificación de Java JSR-175 introdujo la función de anotación de propósito general (también conocida como metadatos ) en el Proceso de la comunidad de Java en 2002; obtuvo la aprobación en septiembre de 2004. [4] Las anotaciones estuvieron disponibles en el propio lenguaje a partir de la versión 1.5 del Java Development Kit (JDK). La apt
herramienta proporcionó una interfaz provisional para el procesamiento de anotaciones en tiempo de compilación en la versión 1.5 de JDK; JSR-269 formalizó esto y se integró en el compilador javac en la versión 1.6.
Anotaciones integradas
Java define un conjunto de anotaciones integradas en el lenguaje. De las siete anotaciones estándar, tres son parte de java.lang y las cuatro restantes se importan de java.lang.annotation. [5] [6]
Anotaciones aplicadas al código Java:
@Override
- Comprueba que el método sea anulado . Provoca un error de compilación si el método no se encuentra en una de las clases principales o interfaces implementadas .@Deprecated
- Marca el método como obsoleto. Provoca una advertencia de compilación si se utiliza el método.@SuppressWarnings
- Indica al compilador que suprima las advertencias de tiempo de compilación especificadas en los parámetros de anotación.
Anotaciones aplicadas a otras anotaciones (también conocidas como "Meta anotaciones"):
@Retention
- Especifica cómo se almacena la anotación marcada, ya sea solo en código, compilada en la clase o disponible en tiempo de ejecución a través de la reflexión.@Documented
- Marca otra anotación para su inclusión en la documentación.@Target
- Marca otra anotación para restringir a qué tipo de elementos Java se puede aplicar la anotación.@Inherited
- Marca otra anotación para ser heredada a subclases de clase anotada (por defecto, las anotaciones no son heredadas por subclases).
Desde Java 7, se han agregado tres anotaciones adicionales al lenguaje.
@SafeVarargs
- Suprime las advertencias para todas las personas que llaman a un método o constructor con un parámetro genérico varargs , desde Java 7.@FunctionalInterface
- Especifica que la declaración de tipo está destinada a ser una interfaz funcional , desde Java 8.@Repeatable
- Especifica que la anotación se puede aplicar más de una vez a la misma declaración, desde Java 8.
Ejemplo
Anotaciones integradas
Este ejemplo demuestra el uso de la @Override
anotación. Indica al compilador que compruebe las clases principales en busca de métodos coincidentes. En este caso, se genera un error porque el gettype()
método de la clase Cat no anula getType()
de hecho la clase Animal como se desea, debido al caso de discrepancia . Si la @Override
anotación estuviera ausente, gettype()
se crearía un nuevo método de nombre en la clase Cat.
animal de clase pública { public void speak () { } public String getType () { return "Animal genérico" ; } }public class Cat amplía Animal { @Override public void speak () { // Esta es una buena anulación. Sistema . fuera . println ( "Miau." ); } @Override public String gettype () { // Error en tiempo de compilación debido a un error tipográfico: debe ser getType () no gettype (). volver "Gato" ; } }
Anotaciones personalizadas
Las declaraciones de tipo de anotación son similares a las declaraciones de interfaz normales. Un signo de arroba (@) precede a la palabra clave de la interfaz . Cada declaración de método define un elemento del tipo de anotación. Las declaraciones de métodos no deben tener ningún parámetro o una cláusula throws. Los tipos de retorno están restringidos a primitivas , String , Class, enumeraciones , anotaciones y matrices de los tipos anteriores. Los métodos pueden tener valores predeterminados .
// @Twizzle es una anotación al método toggle (). @Twizzle public void toggle () { } // Declara la anotación Twizzle. public @interface Twizzle { }
Las anotaciones pueden incluir una lista opcional de pares clave-valor:
// Igual que: @Edible (value = true) @Edible ( true ) Item item = new Carrot (); public @interface Edible { valor booleano () predeterminado falso ; } @Author ( primero = "Oompah" , último = "Loompah" ) Libro libro = nuevo Libro (); public @interface Autor { String first (); String last (); }
Las propias anotaciones se pueden anotar para indicar dónde y cuándo se pueden utilizar:
@Retention ( RetentionPolicy . RUNTIME ) // Haga que esta anotación sea accesible en tiempo de ejecución mediante reflexión. @Target ({ ElementType . METHOD }) // Esta anotación solo se puede aplicar a métodos de clase. public @interface Tweezable { }
El compilador reserva un conjunto de anotaciones especiales (que incluyen @Deprecated
, @Override
y @SuppressWarnings
) con fines sintácticos.
Los marcos de trabajo suelen utilizar las anotaciones como una forma de aplicar de forma conveniente comportamientos a clases y métodos definidos por el usuario que, de lo contrario, deben declararse en una fuente externa (como un archivo de configuración XML) o mediante programación (con llamadas a la API). Lo siguiente, por ejemplo, es una clase de datos JPA anotada :
@Entity // Declara esto como un bean de entidad @Table ( name = "people" ) // Mapea el bean a la tabla SQL "people" clase pública Person implementa Serializable { @Id // Mapea esto a la columna de clave primaria. @GeneratedValue ( estrategia = GenerationType . AUTO ) // La base de datos generará nuevas claves primarias, no nosotros. ID entero privado ; @Column ( length = 32 ) // Truncar los valores de la columna a 32 caracteres. nombre de cadena privada ; public Integer getId () { id de retorno ; } public void setId ( Id. entero ) { this . id = id ; } public String getName () { nombre de retorno ; } setName public void ( nombre de cadena ) { this . nombre = nombre ; } }
Las anotaciones no son llamadas a métodos y, por sí mismas, no harán nada. Más bien, el objeto de clase se pasa a la implementación de JPA en tiempo de ejecución , que luego extrae las anotaciones para generar un mapeo relacional de objetos .
A continuación se ofrece un ejemplo completo:
package com.annotation ;import java.lang.annotation.Documented ; import java.lang.annotation.ElementType ; import java.lang.annotation.Inherited ; import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ; import java.lang.annotation.Target ;@Documented @Retention ( RetentionPolicy . DURACIÓN ) @Target ({ ElementType . TIPO , ElementType . MÉTODO , ElementType . CONSTRUCTOR , ElementType . ANNOTATION_TYPE , ElementType . PAQUETE , ElementType . CAMPO , ElementType . LOCAL_VARIABLE }) @Inheritedpública @interface inacabada { público enumeración Prioridad { BAJA , MEDIA , ALTA } de cadena de valor (); Cadena [] cambiado por () predeterminado "" ; String [] lastChangedBy () predeterminado "" ; Prioridad Prioridad () Prioridad predeterminada . MEDIO ; String createdBy () predeterminado "James Gosling" ; String lastChanged () predeterminado "2011-07-08" ; }
package com.annotation ;public @interface UnderConstruction { String propietario () predeterminado "Patrick Naughton" ; Valor de cadena () predeterminado "El objeto está en construcción". ; String createdBy () predeterminado "Mike Sheridan" ; String lastChanged () predeterminado "2011-07-08" ; }
paquete com.validators ;import javax.faces.application.FacesMessage ; import javax.faces.component.UIComponent ; import javax.faces.context.FacesContext ; import javax.faces.validator.Validator ; import javax.faces.validator.ValidatorException ;import com.annotation.UnderConstruction ; import com.annotation.Unfinished ; import com.annotation.Unfinished.Priority ; import com.util.Util ;@UnderConstruction ( owner = "Jon Doe" ) clase pública DateValidator implementa Validator { public void validate ( contexto FacesContext , componente UIComponent , valor del objeto ) arroja ValidatorException { String date = ( String ) valor ; String errorLabel = "Ingrese una fecha válida". ; if ( ! component . getAttributes (). isEmpty ()) { errorLabel = ( String ) componente . getAttributes (). get ( "errordisplayval" ); } if ( ! Util . validateAGivenDate ( fecha )) { @Unfinished ( modifiedBy = "Steve" , value = "si agregar mensaje al contexto o no, confirmar" , prioridad = Prioridad . ALTA ) FacesMessage message = new FacesMessage (); mensaje . setSeverity ( FacesMessage . SEVERITY_ERROR ); mensaje . setSummary ( errorLabel ); mensaje . setDetail ( errorLabel ); lanzar nueva ValidatorException ( mensaje ); } } }
Procesando
Cuando se compila el código fuente de Java, las anotaciones pueden ser procesadas por complementos del compilador llamados procesadores de anotaciones. Los procesadores pueden producir mensajes informativos o crear recursos o archivos fuente Java adicionales, que a su vez pueden compilarse y procesarse. Sin embargo, los procesadores de anotaciones no pueden modificar el código anotado en sí. (Las modificaciones de código se pueden implementar utilizando métodos más allá de la Especificación del lenguaje Java). El compilador de Java almacena condicionalmente metadatos de anotaciones en los archivos de clases, si la anotación tiene una RetentionPolicy
de CLASS
o RUNTIME
. Posteriormente, la JVM u otros programas pueden buscar los metadatos para determinar cómo interactuar con los elementos del programa o cambiar su comportamiento.
Además de procesar una anotación mediante un procesador de anotaciones, un programador de Java puede escribir su propio código que utiliza reflejos para procesar la anotación. Java SE 5 admite una nueva interfaz definida en el java.lang.reflect
paquete. Este paquete contiene la interfaz llamada AnnotatedElement
que se implementa por las clases de reflexión de Java, incluyendo Class
, Constructor
, Field
, Method
, y Package
. Las implementaciones de esta interfaz se utilizan para representar un elemento anotado del programa que se ejecuta actualmente en la máquina virtual Java. Esta interfaz permite que las anotaciones se lean de forma reflexiva.
La AnnotatedElement
interfaz proporciona acceso a anotaciones que tienen RUNTIME
retención. Este acceso es proporcionado por los getAnnotation
, getAnnotations
y isAnnotationPresent
métodos. Debido a que los tipos de anotaciones se compilan y almacenan en archivos de código de bytes al igual que las clases, las anotaciones devueltas por estos métodos se pueden consultar como cualquier objeto Java normal. A continuación, se proporciona un ejemplo completo de cómo procesar una anotación:
import java.lang.annotation.Retention ; import java.lang.annotation.RetentionPolicy ;// Esta es la anotación que se procesará // El valor predeterminado para Target son todos los elementos Java // Cambiar la política de retención a RUNTIME (el valor predeterminado es CLASS) @Retention ( RetentionPolicy . RUNTIME ) public @interface TypeHeader { // Valor predeterminado especificado para el atributo del desarrollador Cadena desarrollador () predeterminado "Desconocido" ; String lastModified (); String [] teamMembers (); int MeaningOfLife (); }
// Esta es la anotación que se aplica a una clase @TypeHeader ( developer = "Bob Bee" , lastModified = "2013-02-12" , teamMembers = { "Ann" , "Dan" , "Fran" }, meanOfLife = 42 )public class SetCustomAnnotation { // Los contenidos de la clase van aquí }
// Este es el código de ejemplo que procesa la anotación import java.lang.annotation.Annotation ; import java.lang.reflect.AnnotatedElement ;public class UseCustomAnnotation { public static void main ( String [] args ) { Class < SetCustomAnnotation > classObject = SetCustomAnnotation . clase ; readAnnotation ( classObject ); } static void readAnnotation ( elemento AnnotatedElement ) { try { System . fuera . println ( "Valores de elementos de anotación: \ n" ); if ( element . isAnnotationPresent ( TypeHeader . class )) { // getAnnotation devuelve Tipo de anotación Anotación singleAnnotation = elemento . getAnnotation ( TypeHeader . clase ); TypeHeader cabecera = ( TypeHeader ) singleAnnotation ; Sistema . fuera . println ( "Desarrollador:" + encabezado . desarrollador ()); Sistema . fuera . println ( "Última modificación:" + encabezado . lastModified ()); // TeamMembers devuelto como String [] System . fuera . print ( "Miembros del equipo:" ); para ( miembro de cadena : encabezado . teamMembers ()) System . fuera . imprimir ( miembro + "," ); Sistema . fuera . imprimir ( "\ n" ); Sistema . fuera . println ( "Significado de la vida:" + encabezado . significadoDeVida ()); } } catch ( excepción de excepción ) { excepción . printStackTrace (); } } }
Uso en la naturaleza
Los investigadores han estudiado el uso de anotaciones de Java en más de 1.094 proyectos notables de Java de código abierto alojados en GitHub. Descubrieron que las anotaciones se mantienen activamente, con muchas anotaciones que se agregan, pero también se modifican o eliminan debido a errores en el tipo o los valores de la anotación. En general, este estudio encuentra que existe una relación pequeña pero significativa entre el uso de anotaciones y la propensión a errores de código: el código Java con anotaciones tiende a ser menos propenso a errores. [7]
Ver también
- JSR 250: anotaciones comunes para la plataforma Java
- Atributos de CLI
- Programación Java
- Máquina virtual de Java
- Arquitectura basada en modelos
- Decoradores de Python , inspirados en las anotaciones de Java, que tienen una sintaxis similar.
Referencias
- ^ "Anotaciones" . Sun Microsystems . Archivado desde el original el 25 de septiembre de 2011 . Consultado el 30 de septiembre de 2011 ..
- ^ Sun Microsystems (2005). Especificación del lenguaje Java (TM) (3ª ed.). Prentice Hall . ISBN 0-321-24678-0..
- ^ Dare Obasanjo (2007). "UNA COMPARACIÓN DEL LENGUAJE DE PROGRAMACIÓN C # DE MICROSOFT CON EL LENGUAJE DE PROGRAMACIÓN JAVA DE SUN MICROSYSTEMS: Anotaciones de metadatos" . Atrévete Obasanjo. Archivado desde el original el 19 de septiembre de 2012 . Consultado el 20 de septiembre de 2012 .
- ^ Cobarde, Danny (2 de noviembre de 2006). "JSR 175: una función de metadatos para el lenguaje de programación JavaTM" . Proceso de la comunidad Java . Consultado el 5 de marzo de 2008 .
- ^ "Tipos de anotaciones predefinidos" . Oracle Corporation . Consultado el 17 de diciembre de 2016 .
- ^ "Las anotaciones integradas: anotaciones estándar" . Consultado el 17 de diciembre de 2016 .
- ^ Yu, Zhongxing; Bai, Chenggang; Seinturier, Lionel; Monperrus, Martín (2019). "Caracterización del uso, evolución e impacto de las anotaciones de Java en la práctica" . Transacciones IEEE sobre ingeniería de software . arXiv : 1805.01965 . doi : 10.1109 / TSE.2019.2910516 .
enlaces externos
- Introducción a las anotaciones de Java 6 en el sitio de Sun Developer Network
- Introducción a las anotaciones de Java por MM Islam Chisty
- Introducción a las anotaciones de Java 5.0 por Joy Christy
- De las anotaciones de Java de John Hunt
- Anotaciones personalizadas en Java
- Explicación de las anotaciones de Java
- Comprensión de las anotaciones en Java