Seleccionar página

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
        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
    •      <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
Share