Hoy vamos a realizar un ejemplo completo con el API Reflection de Java. Con este API podemos por ejemplo obtener el nombre y el valor de los atributos de cualquier clase, crear una instancia de ella utilizando cualquiera de sus constructores o ejecutar sus métodos.
 
El objetivo del artículo es crear un clase genérica que a partir de una lista genérica de items sea capaz de generar código JSON cuyo nombre sea el resultado de la ejecución de un método concreto y como parámetros sean los nombres y valores de de sus atributos.
 
Por tanto en el ejemplo aglutinamos varios conceptos que seguramente nos encontraremos a lo largo de nuestra trayectoria profesional como programadores:

 

  • API Reflection
  • Genericidad
  • JSON, muy utilizado para el intercambio de información entre aplicaciones. La implementación que se utiliza para realizar el mapping es la librería jackson.
Creamos una clase parametrizada por una clase. Dicha clase recibirá una lista de items de una clase determinada G. Definimos como constantes varios prefijos que seran los que utilizamos para dar nombre a cada nodo JSON para genera el código asociado:

 

  •  item, se utiliza a nivel global para cada elemento de la clase G de la lista de items (item1, item2, itemN)
  • name, representa el nombre de cada item. En este ejemplo se extraerá de llamar al método llamado getItemNameValue. Si la clase G no implementa este método, se devolverá la cadena vacia.
  • data, representa los parámetros del item. Dichos parámetros se extraen de los atributos de la clase G que tengan un método get publico asociado.
  • name, value, representan el nombre y el valor de cada atributo de la clase.

 

 

A continuación creamos un método que obtiene el valor del método getItemNamevalue. Es un método que obtiene una instancia de la clase java.lang.reflect.Method para invocar un determinado método de una clase genérica G. El método se obtiene con la operación getDeclaredMethod de la clase Class pasando como parámetro el nombre del método. Utilizando el método invoke de la clase Method ya tenemos el valor de cada item.

 

NOTA: Notad que se utiliza la nueva notación de Java 7  para la definición de excepcion con los separadores barra.

 

 

Tendremos un método para obtener los campos de la clase G. Este método devuelve un array de la clase del API Reflection java.lang.reflect.Field. Esta clase representa un atributo concreto de una clase y nos servirá como punto de partida para acceder al nombre como al valor del mismo. Observad que el método es recursivo, primero obtiene los atributos de la clase y posteriormente se llama a sí mismo para recuperar los atributos definidos en la superclase. Fijaos también que los atributos con el modificador static se evita añadirlos a la lista, sólo se recuperan los atributos sin el modificador static para evitar añadir constantes.

 

 

Una vez que tengamos todos los atributos de la instancia de una clase necesitaremos métodos para acceder a su nombre e invocar al método get asociado para obtener su valor. Estos dos métodos se definen a continuación:

 

 

Una vez que tenemos toda la información de la clase G únicamente nos queda generar el código JSON. Para ello vamos a utilizar la clase org.codehaus.jackson.node.ObjectNode, que representa un elemento JSON y la clase org.codehaus.jackson.node.JsonNodeFactory que se encargará de ir creando cada nodo JSON. Finalmente con la clase org.codehaus.jackson.map.ObjectMapper generaremos una cadena a partir de un nodo JSON raíz que representa el código JSON de la clase.

 

Y el método pegamento que utiliza todo lo anterior para generar el código JSON:

Para cada uno de los elementos de la lista de tipo G:

  • Se añade el nodo JSON simple con el nombre del item (instancia de clase G) al nodo JSON que representa al item.
  • Se añade el nodo JSON complejo para cada uno de los atributos del item (instancia de clase G) al nodo JSON que representa al item.
  • Se añade el nodo JSON que representa al item al nodo raiz.
Vamos a ejecutar la clase con una lista de 3 items de tres clases diferentes dentro de una jerarquía: Nivel1, Nivel2 y Nivel3. Nivel1 es padre de Nivel2 y Nivel2 es a su vez padre de Nivel. Cada una de ellas encapsula un atributo llamado campo1, campo2 y campo3 respectivamente.
 
 

 

La salida para este caso concreto sería:


El código del proyecto en Netbeans lo podéis descargar de aquí.

Saludos.