La simplicidad de Apache Jexl

Este artículo puede ser útil para todos aquellos que alguna vez tuvieron que hacer cientos o miles de líneas de código usando reflexión para poder acceder a atributos, navegar mapas y recorrer listas en Java. Ahora bien si le agregamos que esas listas o mapas pueden tener más de lo mismo o más complejo aún, objetos que contienen listas o mapas.

Aquí Apache Jexl hace bien su trabajo utilizando un lenguaje cómodo para poder acceder a esos recónditos lugares.

Apache Jexl (Java EXpresion Language) fue inspirado por Apache Velocity y por la definición de Expresion Language para JSTL y JSP 2.0. Ademas en la versión 2.0 se agregaron funcionalidades de Unified EL.

Un pequeño ejemplo para que lo véan en acción:

1
2
3
4
5
6
7
8
public class TestDTO {

private String _name;

private Map<String, Object> _dataBag;

/** Se omiten los setter y getter **/
}

Esta es la definición de un DTO que tiene dos atributos, uno de ellos es un String y otro un Map cuya clave siempre será String y su valor puede ser un Object.

La problemática es obtener un valor desde ese DTO mediante reflexión, es decir, el ente que ejecuta la extracción del parámetro no conoce la definición a priori de esa clase. Es aquí donde entra Jexl y mediante un simple lenguaje le podemos indicar hasta donde acceder. A ese cómo y qué le llamaremos Expresión.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class JexlEvaluator {

private static final JexlEngine jexl = new JexlEngine();

static {
jexl.setCache(512);
jexl.setLenient(false);
jexl.setSilent(false);
}

public Object getValue(String expresion, Object object) {
Expression e = jexl.createExpression(expresion);
JexlContext context = new MapContext();
context.set("fua", object);
return e.evaluate(context);
}
}

Esta simple clase en su bloque estático configura Apache Jexl para luego ser utilizado en el método getValue.

El método getValue recibe como parámetros, la expresión y el objeto a evaluar. Dentro del método se crea el contexto de Apache Jexl (muy similar a un HashMap) al cual se le pasa el Objeto a inspecionar y luego evalúa la expresión.

Aquí les dejo el test unitario y la salida:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class JexlEvaluatorTest {

private static Log logger = LogFactory.getLog(JexlEvaluatorTest.class);

@Test
public void testJexl() {
JexlEvaluator je = new JexlEvaluator();

/* Expresión a evaluar */
String expresion = "fua.dataBag.hola2";

Map<String, Object> map = new HashMap<String, Object>();
map.put("hola", "Hola 1 del MAP");

Map<String, Object> map2 = new HashMap<String, Object>();
map2.put("hola2", "Hola 2 del MAP");

map.put("hola2", map2);

TestDTO testDTO = new TestDTO();
testDTO.setDataBag(map2);
testDTO.setName("DTO Interesante");

Object result = je.getValue(expresion, testDTO);

logger.info(result.toString());
}
}

La ejecución de ese test debería retornar lo siguiente:

1
[29/08/11 09:08:16:016 CLT] [ INFO] [JexlEvaluatorTest:44] - Hola 2 del MAP

Más adelante espero poder escribir sobre Spring EL, otra solución para evaluación de expresiones para Java.