domingo, 14 de febrero de 2016

Como hacer un Comparador Genérico

El otro día necesitábamos realizar ordenaciones de forma manual de un listado. La ordenación que había que hacer era ordinaria, la normal que hace Java ya con los tipos primitivos. Así que tuve la feliz idea de realizar un único comparador que pudiese utlizarse con todos los campos de la lista.

!Atención: He cambiado la palabra 'Object' por 'Objeto' para evitar problemas con el editor de Blogger.

Para empezar creamos una clase que por supuesto extienda de Comparator y que tenga 3 atributos:

  • El nombre del atributo por el cual queremos ordenar, y del cual obtendremos el valor a través de reflexión
  • La clase de la instancia del objeto, la cual nos permitirá obtener el valor vía reflexión
  • Un booleano que nos permita indicar si queremos una ordenación ascendente u descendente.

public class ComparadorGenerico implements Comparator {
protected boolean descendente;
protected String field;
protected Class classInst;
public ComparadorGenerico( final String field, final Class classInst, final boolean descendente ) {
 this.field = field;
 this.classInst = classInst;
 this.descendente = descendente;
}
public int compare( final Object o1, final Object o2 ) {
 int ret = 0;
 try {
  if( descendente ) {
   ret = comparar( o2, o1 );
  } else {
   ret = comparar( o1, o2 );
  }
 } catch( Exception except ) {
  except.printStackTrace();
 }
 return ret;
}
}

La lógica principal se encuentra en el método privado. Los pasos a seguir son los siguientes:

  1. Obtenemos el método por reflexión que nos permita obtener los valores a comparar de ambos objetos. 
  2. Comprobamos que tipo de objeto es el valor a comparar. 
  3. En función del tipo de objeto utilizamos el comparador 'primitivo' para que realice la comparación. 
private int comparar( final Objeto o1, final Objeto o2 ) throws Exception {
 // casteo de los objetos
 Method method = classInst.getMethod( "get" + StringUtils.capitalize( field ) );
 Objeto retorno1 = method.invoke( o1 );
 Objeto retorno2 = method.invoke( o2 );
 if( retorno1 instanceof String ) {
  return ((String) retorno1).compareToIgnoreCase( (String) retorno2 );
 } else if( retorno1 instanceof Integer ) {
  return ((Integer) retorno1).compareTo( (Integer) retorno2 );
 } else if( retorno1 instanceof Date ) {
  return ((Date) retorno1).compareTo( (Date) retorno2 );
 } else if( retorno1 instanceof Double ) {
  return ((Double) retorno1).compareTo( (Double) retorno2 );
 }
 return 0;
}

No hay comentarios:

Publicar un comentario