Introduccion Basica a Anotaciones en Java
Las anotaciones de Java, introducidas en Java 5, son un mecanismo que permite a los desarrolladores incrustar metadatos directamente en su código. Las anotaciones, que sirven como etiquetas informativas, mejoran la legibilidad del código y ofrecen un enfoque simplificado para transmitir detalles complementarios. Ya sea aprovechando las anotaciones integradas o creando anotaciones personalizadas, comprender los conceptos básicos de esta característica concisa pero poderosa puede mejorar su experiencia de programación Java. En esta exploración, navegaremos a través de los fundamentos, las aplicaciones y el impacto en el mundo real de las anotaciones de Java, liberando su potencial para un código más limpio y expresivo.
Las anotaciones de Java, introducidas en Java 5, son un mecanismo que permite a los desarrolladores incrustar metadatos directamente en su código. Las anotaciones, que sirven como etiquetas informativas, mejoran la legibilidad del código y ofrecen un enfoque simplificado para transmitir detalles complementarios. Ya sea aprovechando las anotaciones integradas o creando anotaciones personalizadas, comprender los conceptos básicos de esta característica concisa pero poderosa puede mejorar su experiencia de programación Java. En esta exploración, navegaremos a través de los fundamentos, las aplicaciones y el impacto en el mundo real de las anotaciones de Java, liberando su potencial para un código más limpio y expresivo.
Las anotaciones vienen en varias formas, desde anotaciones integradas como @Override y @Deprecated que transmiten significados específicos al compilador o a las herramientas, hasta anotaciones personalizadas creadas por desarrolladores para anotar su propio código con información específica del dominio.
En este articulo vamos a hacer varios tipos de anotaciones personalizadas.
Estructura de anotaciones.
Las anotaciones tienen esta estructura.
//Tipo de ejecucion.
//Alcance.
public @interface MiAnotacion{
//Cuerpo.
}
//Cuerpo.
}
Alcance de anotaciones y tipos de ejecución.
Los tipos de ejecución de anotaciones pueden ser definidos como:
@Retention(RetentionPolicy.SOURCE)
public @interface MiAnotacion{
//Cuerpo.
}
public @interface MiAnotacion{
//Cuerpo.
}
// En este caso la anotacion es accesible previo a la compilacion
y no puede ser utilizada en tiempo de ejecucion o compilación.
@Retention(RetentionPolicy.CLASS)
public @interface MiAnotacion{
//Cuerpo.
}
public @interface MiAnotacion{
//Cuerpo.
}
// En este caso la anotacion es accesible solo en tiempo de compilación
y no puede ser utilizada en tiempo de ejecucion.
@Retention(RetentionPolicy.RUNTIME)
public @interface MiAnotacion{
//Cuerpo.
}
public @interface MiAnotacion{
//Cuerpo.
}
// En este caso la anotacion existe en tiempo de ejecucion.
Los alcances de anotaciones pueden ser definidos como:
- Alcance de clase.
- Alcance de propiedado campo.
- Alcance de metodo.
- Alcance de constructor.
- Otros, por ahora solo cubriremos esos que son los mas usados.
1.Alcance de clase.
@Target(ElementType.TYPE)
// En este caso la anotacion puede ser insertada solo en la clase.
// Definimos una clase en ClaseAnotada.class.
@MiAnotacion
// No hay errores de compilación.
public class ClaseAnotada {
@MiAnotacion
// Error de compilación.
private String propiedad;
private String propiedad;
@MiAnotacion
// Error de compilación.
public void metodo(){
}
}
public void metodo(){
}
}
2.Alcance de propiedad o campo.
@Target(ElementType.FIELD)
// En este caso la anotacion puede ser insertada solo en una propiedad.
// Definimos una clase en ClaseAnotada.class.
@MiAnotacion
// Error de compilación.
public class ClaseAnotada {
@MiAnotacion
// No hay errores de compilación.
private String propiedad;
private String propiedad;
@MiAnotacion
// Error de compilación.
public void metodo(){
}
}
public void metodo(){
}
}
3.Alcance de metodo.
@Target(ElementType.METHOD)
// En este caso la anotacion puede ser insertada solo en un metodo.
// Definimos una clase en ClaseAnotada.class.
@MiAnotacion
// Error de compilación.
public class ClaseAnotada {
@MiAnotacion
// Error de compilación.
private String propiedad;
private String propiedad;
@MiAnotacion
// No hay errores de compilación.
public void metodo(){
}
}
public void metodo(){
}
}
4.Alcance de constructor.
@Target(ElementType.CONSTRUCTOR)
// En este caso la anotacion puede ser insertada solo en un constructor.
// Definimos una clase en ClaseAnotada.class.
@MiAnotacion
// Error de compilación.
public class ClaseAnotada {
@MiAnotacion
// Error de compilación.
private String propiedad;
private String propiedad;
@MiAnotacion
// Error de compilación.
public void metodo(){
}
}
@MiAnotacion
// No hay errores de compilación.
public ClaseAnotada(){
//Constructor
}
//Constructor
}
}
Ahora vamos a definir una anotacion de clase y procesarla.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiAnotacion {
@Retention(RetentionPolicy.RUNTIME)
public @interface MiAnotacion {
//Cuerpo.
}
}
// Definimos un par de clases en ClaseAnotada.class y ClaseNoAnotada.class.
@MiAnotacion
public class ClaseAnotada {
public class ClaseAnotada {
private String propiedad;
public void metodo(){
}
}
public class ClaseNoAnotada {
private String propiedad;
public void metodo(){
}
}
// Definimos una clase main para ejecutar el codigo en Aplicacion.class
public class Aplicacion {
public static void main(String[] args) {
validarClaseAnotada(ClaseAnotada.class);
validarClaseAnotada(ClaseNoAnotada.class);
}
private static void validarClaseAnotada(Class clase){
if(clase.isAnnotationPresent(MiAnotacion.class)){
System.out.println("Esta clase esta anotada con MiAnotacion");
}else{
System.out.println("Esta clase no tiene anotaciones");
}
}
}validarClaseAnotada(ClaseNoAnotada.class);
}
private static void validarClaseAnotada(Class clase){
if(clase.isAnnotationPresent(MiAnotacion.class)){
System.out.println("Esta clase esta anotada con MiAnotacion");
}else{
System.out.println("Esta clase no tiene anotaciones");
}
}
El resultado es:
Esta clase esta anotada con MiAnotacion
Esta clase no tiene anotaciones
Process finished with exit code 0
A simple vista no parece tener mucha utilidad pero puede ser utilzada por ejemplo en un metodo en una aplicacion web que requera permisos o autenticacion y un filtro que rechaze peticiones si el usuario no tiene permisos o no esta autenticado al invocar el metodo anotado (el ejemplo practico queda para un futuro post).
Ahora definamos una anotacion de alcance de codigo y con cuerpo.
Vamos a crear la siguiente anotacion de clase.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Creditos {
String autor() default "Mi Nombre";
String comentarios() default "Ninguno";
}
@Retention(RetentionPolicy.SOURCE)
public @interface Creditos {
String autor() default "Mi Nombre";
String comentarios() default "Ninguno";
}
Para agregar una propiedad al cuerpo se define:
- Tipo: String, int, boolean, etc.
- nombre()
- (Opcional) valor por default.
Y la utilizaremos en la clase no anotada.
@Creditos(autor = "Algun Nombre", comentarios = "Esta clase se llama
ClaseNoAnotada.")
public class ClaseNoAnotada {
private String propiedad;
public void metodo(){
}
}
private String propiedad;
public void metodo(){
}
}
Por ultimo definamos otro caso para realizar una validacion. Debe hacerse con un anotation processor pero es un tema entero asi hagamos algo simple y en otro post lo desarrollaremos.
Vamos a hacer una validacion de edad.
// Definimos una anotacion con una edad minima y un mensaje.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidarEdad {
int minimo() default 18;
String mensaje() default "La Persona debe ser mayor a 18";
}
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidarEdad {
int minimo() default 18;
String mensaje() default "La Persona debe ser mayor a 18";
}
// Definimos una clase Persona.class
public class Persona {
private String nombre;
@ValidarEdad
private int edad;
public void setEdad(Integer edad) { this.edad = edad; }
public void setNombre(String nombre) { this.nombre = nombre; }
public int getEdad() { return edad; }
public String getNombre() { return nombre; }
}
@ValidarEdad
private int edad;
public void setEdad(Integer edad) { this.edad = edad; }
public void setNombre(String nombre) { this.nombre = nombre; }
public int getEdad() { return edad; }
public String getNombre() { return nombre; }
}
// Definimos una clase ValidadorPersona.class que buscara campos
con anotaciones
public class ValidadorPersona {
public static void validar(final Persona persona)
public static void validar(final Persona persona)
throws IllegalAccessException {
//Lista todos los campos con la anotacion ValidarEdad.class.
Collection<Field> edades = Arrays.stream(persona.getClass().
getDeclaredFields()).filter(field ->
field.isAnnotationPresent(ValidarEdad.class)).
field.isAnnotationPresent(ValidarEdad.class)).
collect(Collectors.toList());
//Lista todos los campos que deben validar la edad.
for (Field campoEdad : edades) {
campoEdad.setAccessible(true);
int edad = campoEdad.getInt(persona);
ValidarEdad anotacion = campoEdad.
campoEdad.setAccessible(true);
int edad = campoEdad.getInt(persona);
ValidarEdad anotacion = campoEdad.
getAnnotation(ValidarEdad.class);
// Si la edad es menor al minimo lanza una excepcion con el
mensaje definido en la anotacion.
if(edad<anotacion.minimo()){
throw new NumberFormatException(anotacion.mensaje());
}
}
}
}
throw new NumberFormatException(anotacion.mensaje());
}
}
}
}
// Lo corremos en la clase main.
public class Aplicacion {
public static void main(String[] args) throws IllegalAccessException {
Persona persona = new Persona();
persona.setEdad(35);
ValidadorPersona.validar(persona);
public static void main(String[] args) throws IllegalAccessException {
Persona persona = new Persona();
persona.setEdad(35);
ValidadorPersona.validar(persona);
//Este llamado no debe fallar.
System.out.println("Persona validada.");
persona.setEdad(10);
System.out.println("Persona validada.");
persona.setEdad(10);
//Este llamado SI debe fallar.
ValidadorPersona.validar(persona);
System.out.println("Persona validada.");
}
}
ValidadorPersona.validar(persona);
System.out.println("Persona validada.");
}
}
El Resultado.
Persona validada. //El primero que es 35 es validado.
Exception in thread "main" java.lang.NumberFormatException:
La Persona debe ser mayor a 18
at ValidadorPersona.validar(ValidadorPersona.java:16)
at Aplicacion.main(Aplicacion.java:11)
//El segundo que es 10 falla.
Se puede expandir el validador y agregar mas anotaciones pero la mejor forma de hacerlo es con un procesador de Anotaciones pero como dije es una introduccion y queda para otro post.
Asi que hasta la proxima.
Comentarios
Publicar un comentario