JSF 2:在呈现的属性中使用枚举

The*_*heo 19 jsf enums el jsf-2

有没有办法以声明方式检查枚举是否具有指定值.例如:

<h:graphicImage name="error.png" library="images" 
  rendered="#{viewController.current.status == Status.ERROR}" />
Run Code Online (Sandbox Code Playgroud)

在托管beand中定义一个方法来检查每个枚举值,例如,有点单调乏味

public boolean isStateIsError() {
  return current.getStatus() == Status.ERROR;
}
Run Code Online (Sandbox Code Playgroud)

这样做有更短/更好的方法吗?

Bal*_*usC 35

在EL 3.0之前,无法在EL范围中导入枚举.然而,您可以像对待字符串一样对待和比较它们,即必须引用枚举常量值,如下所示.

<h:graphicImage name="error.png" library="images" 
  rendered="#{viewController.current.status eq 'ERROR'}" />
Run Code Online (Sandbox Code Playgroud)


小智 7

我知道这个问题现在有点老了,但是我遇到了同样的问题并找到了另一种解决方案,我想分享一下:

创建一个自定义EL解析器并使用枚举和java常量作为jsf el中的对象:

<h:graphicImage name="error.png" library="images"  
      rendered="#{viewController.current.status == Status.ERROR}" />
Run Code Online (Sandbox Code Playgroud)

但在你以这种方式使用枚举之前,你必须做3个步骤.

1.步骤 - 复制此类并通过enumClass替换"MY_ENUM"(在上面的例子中它将是"Status")

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

2.步骤 - 添加此EnumResolver - 此类将您的JSF表达式映射到缓存中的枚举(步骤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) {
    }
}
Run Code Online (Sandbox Code Playgroud)

3.步骤 - 在faces-config.xml中注册EnumResolver

<faces-config>
    <application>
        <el-resolver>com.asd.MyEnumResolver</el-resolver>
    </application>
</faces-config>
Run Code Online (Sandbox Code Playgroud)

注意:如果要以这种方式访问​​java常量,则只需扩展enumCache类的构造函数即可.这个(untestet)示例应该有效:

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) { }
}
Run Code Online (Sandbox Code Playgroud)

希望这减少但工作代码可以帮助任何人.


更新

我看到了这个好处:

  1. 如果你在jsf(viewController.current.status =='ERROR_abcdefg')中使用字符串,你可以拼错该值并且不会如此快地识别它.使用我的解决方案,您在加载jsf文件时会收到错误,因为无法解析枚举.

  2. 您可以在源代码中看到"ERROR"是枚举"STATUS"的值.

  3. 当您比较el中的两个值时,也将比较枚举的类.因此,例如PersonState.ACTIV与AccounState.ACTIV不同.

  4. 当我必须将我的枚举值从PersonState.ACTIV更改为PersonState.ACTIVATED时,我可以在源代码中搜索字符串"PersonState.ACTIV".搜索"ACTIV"会有更多匹配.

  • 这种方法给你带来了什么好处?在Java中,使用直接枚举引用的主要优点是有效值的编译时执行,但EL中不存在此优点,也不存在此解析器. (5认同)