El Expression Language de JSF nos permite acceder a propiedades de los objetos siempre que estas esten 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.
Sustiye 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
-
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
-
-
-
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
-
-
}
-
-
-
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);
-
-
}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<object> collectionToMap
(Collection col
) {
-
Map</object><object> map = new HashMap</object><object>();
-
-
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>
<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