Cuando desarrollamos aplicaciones en Java el uso de anotaciones es muy común, pero se han puesto a pensar ¿Cómo crear tus propias anotaciones y como utilizarlas en Java ?, en este post explicaremos como hacerlo con ejemplos prácticos.

Tipos de anotaciones

Existen 3 tipos de anotaciones:

  • Marker annotation
  • Single value annotation
  • Multi value annotation

Marker annotation

A continuación se presenta como hacer una anotación de tipo Marker annotation:

public @interface Example {
}

Single value annotation

A continuación se presenta como hacer una anotación de tipo Single value annotation:

public @interface Example {
	int value() default 100;
}

Como se puede ver se creó una anotación llamada example la cual tiene un atributo llamado value con un valor por defecto de 100, para utilizarla se hará del siguiente modo:

@Example(value=200)

Esto cambiará el valor de value de 100 a 200.

Multi value annotation

A continuación se presenta como hacer una anotación de tipo Multi value annotation:

public @interface Example {
	int value() default 100;
	int value2() default 200;
	int value3() ;
}

Una anotación puede tener multiples atributos, el ejemplo anterior muestra una anotación con 3 valores value, value2 y value3, para utilizarla haremos lo siguiente:

@Example(value=200, value2=300, value3=400)

@Taget

Es posible definir en que lugar es o no permitido utilizar una anotación, para esto utilizaremos la anotación @Target la cual recibe como parámetro un valor de la enumeración java.lang.annotation.ElementType, a continuación se presentan los posibles valores y su significado:

  • TYPE : A nivel de clase, interfaz o enumeración
  • FIELD: A nivel de campos
  • METHOD: A nivel de métodos
  • CONSTRUCTOR: A nivel de constructores
  • LOCAL_VARIABLE : A nivel de variables locales
  • ANNOTATION_TYPE: A nivel de anotaciones
  • PARAMETER: A nivel de parámetros

Ejemplo práctico

Un caso de ejemplo muy común para utilizar anotaciones es un ORM, en nuestro caso práctico crearemos algunas anotaciones para definirlo y veremos como leerlo.

Anotación @Table:

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

@Target(ElementType.TYPE)
public @interface Table {
	String name();
	String schema();
}

Ejemplo práctico

En este ejemplo mostraremos como crear algunas anotaciones y obtener el valor de las mismas para simular un pequeño ORM.

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

/**
 * @author raidentrance
 *
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	String name();

	String schema();
}

La anotación table se utilizará para determinar el nombre de la tabla y el esquema de la base de datos a utilizar.


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

/**
 * @author raidentrance
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	String name();

	String description();
}

La anotación @Column se utilizará para definir el nombre de una columna en una tabla de una base de datos.


import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;

import com.raidentrance.orm.annotations.Column;
import com.raidentrance.orm.annotations.Table;

/**
 * @author maagapi
 *
 */
public class CustomEntityManager {

	private static final CustomEntityManager manager = new CustomEntityManager();

	private static final Logger log = Logger.getLogger(CustomEntityManager.class.getName());

	private CustomEntityManager() {
	}

	public void persist(Object user) {
		Table table = user.getClass().getAnnotation(Table.class);
		log.info(String.format("Inserting in table %s", table.name()));
		Field[] fields = user.getClass().getDeclaredFields();
		for (Field field : fields) {
			Column annotation = field.getAnnotation(Column.class);
			if (annotation != null) {
				try {
					Object invoke = new PropertyDescriptor(field.getName(), user.getClass()).getReadMethod().invoke(user);
					log.info(String.format("Column %s = %s", annotation.name(), invoke));
				} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException | IntrospectionException e) {
					log.info(e.getMessage());
				}
			}
		}
	}

	public static CustomEntityManager getEntityManager() {
		return manager;
	}

}

La clase CustomEntityManager se utilizará para simular el EntityManagerFactory de JPA, como se puede ver tiene un constructor privado y una instancia static para hacerlo singleton.

A continuación se muestra como obtener el valor de las anotaciones aplicadas en la clase haciendo uso del objeto:

Table table = user.getClass().getAnnotation(Table.class);
log.info(String.format("Inserting in table %s", table.name()));

Probando todo junto

Para probar todo junto crearemos una clase que hará uso del CustomEntityManager:

import com.raidentrance.orm.persistence.CustomEntityManager;

/**
 * @author raidentrance
 *
 */
public class TestApplication {
	public static void main(String[] args) {
		CustomEntityManager entityManager = CustomEntityManager.getEntityManager();

		entityManager.persist(new User("raidentrance", "SuperSecret"));
	}
}

Como se puede entender el uso de las anotaciones simulando un pequeño ORM, si ejecutas el programa la salida será la siguiente:

ene 22, 2018 5:09:10 PM com.raidentrance.orm.persistence.CustomEntityManager persist
INFORMACIÓN: Inserting in table USER
ene 22, 2018 5:09:10 PM com.raidentrance.orm.persistence.CustomEntityManager persist
INFORMACIÓN: Column USERNAME = raidentrance
ene 22, 2018 5:09:10 PM com.raidentrance.orm.persistence.CustomEntityManager persist
INFORMACIÓN: Column PASSWORD = SuperSecret

Si te gustó este ejemplo coméntalo en la sección de comentarios o en nuestras redes sociales https://twitter.com/geeks_mx y https://www.facebook.com/geeksJavaMexico/, para agregar la integración de JDBC para hacer funcionar nuestro ORM.

 

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com