El Expression Language de JSF nos permite acceder a propiedades de los objetos siempre que estas estén disponibles mediante getters.
Esto está muy bien, pero en ocasiones lo que queremos obtener es un objeto que solo está accesible a través de un método que no es un getter, como por ejemplo el tamaño de una java.util.Collection disponible a través de su método collection.size(), o los valores de un java.util.Map disponibles a través del método values().
Para ello podemos realizar nuestra propia implementación de la clase javax.el.ELResolver.
Esta clase es la encargada de evaluar las ELs (las expresiones que van entre #{}) y realizar las acciones correspondientes.
Sustituye a los antiguos PropertyResolver y VariableResolver, que están marcados como obsoletos (deprecated) en la especificación 1.2 de JSF (que es la usada en la versión 5 de Java EE).
Para usar nuestro propio ELResolver solo deboemos seguir tres sencillos pasos:
-
- 1) Implementar nuestra clase que extienda de javax.el.ELResolver
Puedes descargarla aquí: MyELResolver
Necesitarás añadir al classpath de compilación el archivo el-api.jar
- 1) Implementar nuestra clase que extienda de javax.el.ELResolver
package tes.jsf;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.el.ELContext;
public class MyELResolver extends javax.el.ELResolver {
@Override
public Class getCommonPropertyType(ELContext context, Object base) {
return null;
}
@Override
public Iterator getFeatureDescriptors(ELContext context, Object base) {
return null;
}
@Override
public Class getType(ELContext context, Object base, Object property) {
return null;
}
@Override
public Object getValue(ELContext context, Object base, Object property) {
if (base instanceof Collection) {
return resolveInCollection(context, (Collection)base, property);
} else if (base instanceof Map) {
return resolveInMap(context, (Map)base, property);
} else {
return null;
}
}
@Override
public boolean isReadOnly(ELContext arg0, Object arg1, Object arg2) {
return true;
}
@Override
public void setValue(ELContext arg0, Object arg1, Object arg2, Object arg3) {
}
private Object resolveInCollection(ELContext context, Collection base, Object property) {
if (property.equals(«size»)) {
context.setPropertyResolved(true);
return base.size();
} else if (property.equals(«toMap»)) {
context.setPropertyResolved(true);
return collectionToMap(base);
} else if (property.equals(«toList»)) {
context.setPropertyResolved(true);
return new ArrayList(base);
}else {
return null;
}
}
private Object resolveInMap(ELContext context, Map base, Object property) {
if (property.equals(«size»)) {
context.setPropertyResolved(true);
return base.size();
} else if (property.equals(«values»)) {
context.setPropertyResolved(true);
return base.values();
} else if (property.equals(«keySet»)) {
context.setPropertyResolved(true);
return base.keySet();
} else if (property.equals(«entrySet»)) {
context.setPropertyResolved(true);
return base.entrySet();
} else {
return null;
}
}
private Map collectionToMap(Collection col) {
Map map = new HashMap();
for (Object obj : col) {
map.put(obj, obj);
}
return map;
}
}
- 2) Declarar el ELResolver en el archivo faces-config.xml
La declaración debe hacerse dentro de la seccion <application>.
<el-resolver>tes.jsf.MyELResolver</el-resolver>
- 3) Usar las nuevas posibilidades del Language Expression
-
- El tamaño de mi Collection es: #{myCollection.size}
- Puedes usarlo para rellenar tus combos:
<h:selectOneMenu> <f:selectItems value="#{myCollection.toMap}" /> <h:selectOneMenu>
-
- Para asociar tu java.util.Set con un dataTable
<h:dataTable value="#{mySet.toList}" var="entry"> ... </h:dataTable>
- Para iterar sobre las entradas de un Map
- Para asociar tu java.util.Set con un dataTable
<ui:repeat value="#{myMap.entrySet.toList}" var="entry"> #{entry.key} : #{entry.value} <br /> </ui:repeat>
- Y para todo lo que se te ocurra añadir
-
0 comentarios