有没有办法以声明方式检查枚举是否具有指定值。例如:
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status == Status.ERROR}" />
在托管beand中定义一个方法,检查每个枚举值是否有点乏味,例如
public boolean isStateIsError() {
return current.getStatus() == Status.ERROR;
}
有更短/更好的方法吗?
答案 0 :(得分:35)
Until EL 3.0无法在EL范围内导入枚举。然而,您可以像对待字符串一样对待和比较它们,即必须引用枚举常量值,如下所示。
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status eq 'ERROR'}" />
答案 1 :(得分:7)
我知道这个问题现在有点老了,但我遇到了同样的问题并找到了另一个解决方案,我想分享一下:
创建自定义EL解析器,使用枚举和java常量作为jsf中的对象 el:
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status == Status.ERROR}" />
但在你以这种方式使用枚举之前,你必须做3个步骤。
<强> 1。步骤 - 复制此类并通过enumClass替换“MY_ENUM”(在上面的示例中,它将是“状态”)
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。步骤 - 添加此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) {
}
}
第3。步骤 - 在faces-config.xml中注册EnumResolver
<faces-config>
<application>
<el-resolver>com.asd.MyEnumResolver</el-resolver>
</application>
</faces-config>
注意: 如果要以这种方式访问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) { }
}
希望这种情况有所减少,但正常工作的代码可以帮助任何人。
<强>更新强>
我看到了这个好处:
如果你在jsf中使用字符串(viewController.current.status =='ERROR_abcdefg'),你可以拼错该值并且不会如此快地识别它。 使用我的解决方案,您在加载jsf文件时会收到错误,因为枚举无法解析。
您可以在源代码中看到“ERROR”是枚举“STATUS”的值。
比较el中的两个值时,也会比较枚举的类别。 例如,PersonState.ACTIV与AccounState.ACTIV不同。
当我必须将我的枚举值从PersonState.ACTIV更改为PersonState.ACTIVATED时,我可以在源代码中搜索字符串“PersonState.ACTIV”。搜索“ACTIV”会有更多的匹配。
答案 2 :(得分:1)
我通过statically
在地图中转储所有枚举键(在渲染的UI组件中使用)解决了类似的问题,然后我使用静态getByKey
方法转换来自UI到setter中的实际本机枚举,如果提供的值无效,则抛出异常:
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;
}
}
在UI层中,枚举键用作值,枚举标签用作标签:
<f:selectItems var="rptTypeItem" value="#{reportController.allReportTypes}"
itemLabel="#{rptTypeItem.label}" itemValue="#{rptTypeItem.key}"/>
在managed bean
中,我使用枚举中的getValueList()
将枚举转换为可渲染列表:
public List<ReportType> getAllReportTypes() {
return ReportType.getValueList();
}
最后,托管bean中的[g | s] etters如下所示:
public String getReportType() {
return this.crtRptType.getKey();
}
public void setReportType(String _val) {
this.crtRptType = ReportType.getByKey(_val);
}
答案 3 :(得分:1)
我认为可以通过以下方式完成:
在bean中创建一个返回枚举列表的方法,例如
public Status[] getStatuses() {
Status.values();
}
那么你可以像这样使用EL中的枚举
<h:graphicImage name="error.png" library="images"
rendered="#{viewController.current.status == someBean.statuses[0]}" />
假设枚举成员的顺序不会被更改(例如,此处状态[0]为ERROR)。但是,我会解决这样的立场:
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;
}
这仍然不是动态解决方案,但它比EL中的硬编码更好。当您使用本地化为您的状态(枚举值取决于区域设置/翻译)时,可能会特别有用。
答案 4 :(得分:-1)
我使用以下方法解决了类似问题:
<p:graphicImage name="images/close.png" rendered="#{i.unityEnum.name().equals('DAY')}" />