Una JSF universal

Un ejemplo de cómo simplificarnos la vida usando nuestras propias annotations.

Por la razón que fuese teníamos que crearnos un numero considerable pero finito de VOs con un numero tendiente a infinito de propiedades. Estos VOs a los que llamaremos FooData1VO, FooData2VO, … FooDataNVO; estos VOs , digo, iban a ser usados en JSFs en los que una lista del mismo FooDataXVO se representaría como una tabla, una tabla que a su vez seria exportable a excel.

Bien, tenemos dos formas de hacerlo. La normal o infernal, y la anotada o elegante y fácil.
En la normal, nos creamos N VOs, N Controllers, y N JSFs.
En la version anotada que proponemos aqui necesitamos: N+1 VOs, 1 Controller universal, 1 JSF universal y 1 Annotation.

Lo primero que hacemos es crearnos nuestra anotación java (annotation).


package com.viavansi.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
/**
* @author dbejar
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface WiseName{
String alias();
}

Este es un caso muy sencillito en el que únicamente le damos un nombre en lenguaje natural a una propiedad. Podríamos como en el caso real en el que desarrollamos esto, añadirle un booleano para distinguir entre propiedades exportables a excel, o un enum para hacer subconjuntos dentro del mismo VO. Pero estoy adelantando cosas…

A continuación nos creamos una clase padre de nuestros VOs:

package com.viavansi.VO;


import java.lang.reflect.Field;
import com.viavansi.annotation.WiseName;

public abstract class FooDataSuperVO{
/**
* Devuelve una lista ordenada con todos los labels de los atributos marcados
* con la annotation WiseName
* @return
*/
public List<String>getWiseNamedLabels(){
List<String>aliases=new LinkedList<String>();
for (Field field : this.getClass().getDeclaredFields()){
WiseName nombreBonito=field.getAnnotation(WiseName.class);
if (nombreBonito==null) continue;
aliases.add(nombreBonito.alias());
}
return aliases;
}
/**
* Devuelve una lista ordenada con todos los nombres de los atributos marcados
* con la annotation WiseName
* @return
*/
public List<String> getWiseNamedProperties(){
List<String>propNames=new LinkedList<String>();
for (Field field : this.getClass().getDeclaredFields()){
WiseName nombreBonito=field.getAnnotation(WiseName.class);
if (nombreBonito==null) continue;
propNames.add(field.getName());
}
return propNames;
}

No requiere mucha explicación, si se han leído y entendido mis artículos sobre Annotation. Básicamente con esas dos funciones por reflection obtenemos en una todas las propiedades anotadas, y en la otra el valor de la propiedad alias en esas anotaciones.

Ahora un ejemplo muy muy simple de uno de los VOs anotados:

package com.viavansi.VO;
public class FooData1VO extends FooDataSuperVO{
@NombreBonito(alias="1. Terrenos y bienes naturales")
private Double balActInmInvTerrYBienNat;
@NombreBonito(alias="2. Infraestructuras y bienes destinados al uso general")
private Double balActInmInvInfYVBienUsoGral;
//etc..


//Con sus geterts y setters
}

Ya estamos terminando.

Con estas anotaciones solo necesitamos una JSF. Una para todos los VOs. Y un único controller también.

En el Controller introducimos un par de getters de la siguiente pinta:

/**
* Devuelve una lista ordenada con todos los nombres de los atributos marcados
* con la annotation WiseName
* @author cvillar,dbejar
*@return
*/
public List<String> getListNombresBonitosProperties(){
if (listaPaginas.getRegistros().get(0) instanceof FooData1VO){
return new FooData1VO().getWiseNamedProperties();
}else if (listaPaginas.getRegistros().get(0) instanceof FooData2VO){
return new FooData2VO().getWiseNamedProperties();
}//else if [....]
//N veces
}else if (listaPaginas.getRegistros().get(0) instanceof FooDataNVO){
return new FooDataNVO().getWiseNamedProperties();
}else{
log.error("Primer registro de listaPaginas no es de un tipo VO implementado");
return new LinkedList<String>();
}
}
/**
* Devuelve una lista ordenada con todos los labels de los atributos marcados
* con la annotation WiseNamed
* @author cvillar,dbejar
*@return
*/
public List<String> getListWiseNamedLabels(){
//Trivial. La misma idea que el metodo anterior.
}

Y finalmente nuestra JSF universal y super simplificada:

<v:dataTable id="data" var="fila" styleClass="display_table" controller="#{FooDataController}">
<c:forEach var="propiedad" items="#{FooDataController.listWiseNamedProperties}" varStatus="rowCounter">
<v:column property="#{propiedad}" label="${FooDataController.listWiseNamedLabels [rowCounter.index]} "/>
</c:forEach>
</v:dataTable>

Comentarios

  1. Hola!

    estoy recién salido como quien dice de la universidad y me ha asaltado una duda al leer el artículo, referente al uso de reflection: igual me han estado enseñando algo muy desfasado, pero cuánto es de aconsejable hacer uso de la reflection??

    La impresión que recibí es que hay que usarla lo menos posible, sobretodo debido a temas de rendimiento (aunque haya ocasiones en que no te quede otra), pero estoy viendo como se usa en ya varios sitios y empiezo a sospechar… es otro mito que se (me) cae?

    muchas gracias y un saludo!

  2. Quizas mi compañero Felix podria entrar en discusiones mas filosoficas. O corregirme.
    Yo le veo bastante simple.
    En muchos casos, y probablemente en el 100% de los casos que se dan en esta empresa, el ‘time-to-market’, es decir el tiempo que se tarda desde que se cierra el contrato hasta que el producto esta listo, es mas critico tanto para los clientes, como para mi empresa, que los posibles efectos que pueda tener en el rendimiento un uso intensivo de reflection.

    Es una pura cuestion pragmatica.

    Si con este metodo nos hemos ahorrado 3 semanas de desarrollo, poco nos importa a nosotros y al cliente, que el rendimiento se resienta -si es que lo hace- en porcentajes insignificantes, incluso en escenarios de stress.

    Otra cosa sería si estuviesemos hablando de sistemas críticos, o sistemas batch de varias horas de procesamiento… o quizas incluso si se tratase de sistemas con un nivel exageradamente alto de stress; quizas en estos casos si que convendria pensar en la eficiencia del uso de annotations. Y aun asi, me pregunto si no seria mas eficaz hacer un buen ‘fine tunning’ de la maquina virtual, en lugar de eliminar la reflexion…

Comments are closed.