jsf enums jsf-2 el

templates jsf primefaces



JSF 2: Usar enumeraciones en el atributo representado (4)

Sé que esta pregunta es un poco más antigua ahora, pero tuve el mismo problema y encontré otra solución, que quiero compartir:

Cree un EL-Resolver personalizado y use enumeraciones y constantes de Java como objetos en jsf el:

<h:graphicImage name="error.png" library="images" rendered="#{viewController.current.status == Status.ERROR}" />

Pero antes de que pueda usar enumeraciones de esta manera, debe hacer 3 pasos.

1. paso - Copia esta clase y reemplaza "MY_ENUM" a través de tu enumClass (en el ejemplo de arriba sería "Estado")

public class EnumCache { private Map<String, Object> propertCache = new HashMap<String, Object>(); private Map<String, Class> baseCache = new HashMap<String, Class>(); private static EnumCache staticEnumCache = null; public static EnumCache instance() { if (staticEnumCache == null) { staticEnumCache = new EnumCache(); } return staticEnumCache; } private EnumCache() { List<Class<?>> classes = new ArrayList<Class<?>>(); classes.add(MY_ENUM.class); for(Class clazz : classes) { try { baseCache.put(clazz.getSimpleName(), clazz); Method m = clazz.getMethod("values", (Class[]) null); Enum<?>[] valueList = (Enum[]) m.invoke(null, (Object[]) null); for (Enum<?> en : valueList) { propertCache.put(clazz.getSimpleName() + "." + en.name(), en); } } catch (Exception e) { System.err.println(clazz.getSimpleName(), e); } } } public Object getValueForKey(String key) { return propertCache.get(key); } public Class getClassForKey(String key) { return baseCache.get(key); } }

2. paso: agrega este EnumResolver: esta clase asignará tu expresión JSF a la enumeración en caché (paso 1)

public class MyEnumResolver extends ELResolver { public Object getValue(ELContext context, Object base, Object property) { Object result = null; if (base == null) { result = EnumCache.instance().getClassForKey(property + ""); } else if (base instanceof Class) { result = EnumCache.instance().getValueForKey(((Class) base).getSimpleName() + "." + property); } if (result != null) { context.setPropertyResolved(true); } return result; } public Class<?> getCommonPropertyType(ELContext context, Object base) { return null; } public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) { return null; } public Class<?> getType(ELContext context, Object base, Object property) { return null; } public boolean isReadOnly(ELContext context, Object base, Object property) { return false; } public void setValue(ELContext context, Object base, Object property, Object arg3) { } }

3. paso: registra EnumResolver en faces-config.xml

<faces-config> <application> <el-resolver>com.asd.MyEnumResolver</el-resolver> </application> </faces-config>

NOTA: si desea acceder a las constantes de Java de esta manera, solo tiene que extender el constructor de la clase enumCache. Este (untestet) ejemplo debería funcionar:

baseCache.put(CLASS_WITH_CONSTANTS.getSimpleName(), clazz); for (Field field : CLASS_WITH_CONSTANTS.getDeclaredFields()) { try { propertCache.put(CLASS_WITH_CONSTANTS.getSimpleName() + "." + field.getName(), field.get(null)); } catch (Exception e) { } }

Espero que este código reducido pero funcional pueda ayudar a cualquiera.

Actualizar

Veo estos beneficios:

  1. Si utiliza cadenas en jsf (viewController.current.status == ''ERROR_abcdefg''), puede escribir mal el valor y no lo reconocerá tan rápido. Con mi solución obtendría un error al cargar el archivo jsf, porque la enumeración no se pudo resolver.

  2. Puede ver en el código fuente que "ERROR" es el valor de la enumeración "ESTADO".

  3. Cuando compare dos valores en el, la clase de las enumeraciones también se comparará. Entonces, por ejemplo, PersonState.ACTIV no es lo mismo que AccounState.ACTIV.

  4. Cuando tengo que cambiar mi valor enum de PersonState.ACTIV a PersonState.ACTIVATED, puedo buscar la cadena "PersonState.ACTIV" en mi código fuente. buscar "ACTIV" tendría muchas más coincidencias.

¿Hay alguna manera de verificar declarativamente si una enumeración tiene un valor específico? Por ejemplo:

<h:graphicImage name="error.png" library="images" rendered="#{viewController.current.status == Status.ERROR}" />

Es un poco tedioso definir un método en el servidor administrado y que verifica esto para cada valor enum, por ejemplo

public boolean isStateIsError() { return current.getStatus() == Status.ERROR; }

¿Hay una manera más corta / mejor de hacer esto?


Resolví un problema similar descargando statically todas las claves enumeradas (que se utilizan en los componentes de UI renderizados) en un mapa y luego utilizo un método getByKey estático para convertir el valor de la UI en una enumeración nativa real en el colocador, lanzando una excepción si el valor proporcionado no es válido:

public enum ReportType { FILING("F", "Filings"), RESOLUTION("R", "Resolutions"), BASIS("B", "Bases"), STAFF("T", "Staff Counts"), COUNTS("I", "Counts"); private String key; private String label; private static Map<String, ReportType> keyMap = new HashMap<String, ReportType>(); static { for(ReportType type : ReportType.values()) { keyMap.put(type.getKey(), type); } } private ReportType(String _key, String _label) { this.key = _key; this.label = _label; } public String getKey() { return this.key; } public String getLabel() { return this.label; } public static List<ReportType> getValueList() { return Arrays.asList(ReportType.values()); } public static ReportType getByKey(String _key) { ReportType result = keyMap.get(_key); if(result == null) { throw new IllegalArgumentException("Invalid report type key: " + _key); } return result; } }

En el nivel UI, la clave de enumeración se utiliza como valor y la etiqueta de enumeración se utiliza como etiqueta:

<f:selectItems var="rptTypeItem" value="#{reportController.allReportTypes}" itemLabel="#{rptTypeItem.label}" itemValue="#{rptTypeItem.key}"/>

En el managed bean , convierto la enumeración en una lista que se puede volver a presentar, usando getValueList() de la enumeración:

public List<ReportType> getAllReportTypes() { return ReportType.getValueList(); }

Finalmente, los [g | s] etters en el bean gestionado se ven de la siguiente manera:

public String getReportType() { return this.crtRptType.getKey(); } public void setReportType(String _val) { this.crtRptType = ReportType.getByKey(_val); }


Creo que se podría hacer de la siguiente manera:

Crea un método en you bean que devuelva la lista de enumeraciones, por ejemplo

public Status[] getStatuses() { Status.values(); }

entonces puedes usar la enumeración en EL como esta

<h:graphicImage name="error.png" library="images" rendered="#{viewController.current.status == someBean.statuses[0]}" />

asumiendo que el orden de los miembros enum no va a ser cambiado (por ejemplo, aquí los estados [0] son ​​ERROR). Sin embargo, arreglaría las posiciones de esta manera:

public Status[] getStatuses() { Status myStatuses = new Status [2]; // or whatever number of statuses you are going to use in UI myStatuses [0] = Status.ERROR; myStatuses [1] = Status.RUNNING; return myStatuses; }

Esta aún no es una solución dinámica, pero es mejor que una codificación difícil en EL. Puede ser especialmente útil cuando usa la localización para sus estados (valores enum dependiendo de la localización / traducción).


Hasta EL 3.0 no es posible importar enumeraciones en el alcance EL. Sin embargo, solo puede tratarlos y compararlos como cadenas, es decir, el valor de la constante enum debe citarse a continuación.

<h:graphicImage name="error.png" library="images" rendered="#{viewController.current.status eq ''ERROR''}" />