JSF 2.0:对 selectOneMenu 使用枚举值 [重复]
Posted
技术标签:
【中文标题】JSF 2.0:对 selectOneMenu 使用枚举值 [重复]【英文标题】:JSF 2.0: use Enum values for selectOneMenu [duplicate] 【发布时间】:2011-02-21 13:32:56 【问题描述】:我正在使用 JSF 2.0 并希望用我的 Enum 的值填充 selectOneMenu。 一个简单的例子:
// Sample Enum
public enum Gender
MALE("Male"),
FEMALE("Female");
private final String label;
private Gender(String label)
this.label = label;
public String getLabel()
return this.label;
不幸的是,我不能在我当前的项目中使用 Seam,它有一个很好的 <s:convertEnum/>
标签来完成大部分工作。
在 Seam 中,要使用 Enum 的值,我必须编写以下标记(并创建一个提供 #genderValues
的工厂:
<!-- the Seam way -->
<h:selectOneMenu id="persongender" value="#person.gender">
<s:selectItems var="_gender" value="#genderValues"" label="#_gender.label"/>
<s:convertEnum/>
</h:selectOneMenu>
结果是我不必再在标记内显式声明枚举值。 我知道这在 JSF
或者我什至可以集成 Seam JSF 标签和相应的 Seam 类以在 JavaEE6-App 中获得相同的功能(没有 Seam 容器)?
【问题讨论】:
另见How to use enum in selectOneMenu和How to use enum in selectManyMenu 【参考方案1】:这是一个更简单的方法,它使用简单的 getter 和 setter 将字符串编组为枚举。
https://rogerkeays.com/blog/using-enums-in-el
【讨论】:
【参考方案2】:好的,这是最后的方法: - 在 faces-config.xml 中注册标准枚举转换器(可选):
<converter>
<converter-for-class>java.lang.Enum</converter-for-class>
<converter-class>javax.faces.convert.EnumConverter</converter-class>
</converter>
添加一个函数,例如将 Enum 值转换为 SelectItems 数组的托管 bean:
@ManagedBean
public class GenderBean
public SelectItem[] getGenderValues()
SelectItem[] items = new SelectItem[Gender.values().length];
int i = 0;
for(Gender g: Gender.values())
items[i++] = new SelectItem(g, g.getLabel());
return items;
然后将此函数绑定到JSF中的selectOneMenu:
<h:selectOneMenu id="gender" value="#person.gender">
<!-- use property name not method name -->
<f:selectItems value="#genderBean.genderValues" />
</h:selectOneMenu>
就是这样!不是网上对这个问题的第一个解释。但我认为这是最简单和最短的;)
【讨论】:
不需要转换器注册。【参考方案3】:看了我自己的 Seam 示例一分钟后,我在托管 bean 中创建了一个方法,如下所示:
@ManagedBean
public class MyManagedBean
public Gender[] getGenderValues()
return Gender.values;
在我的标记中我放了
<h:selectOneMenu id="gender" value="#person.gender">
<f:selectItems value="#myManagedBean.genderValues" var="g"
itemValue="#g" itemLabel="#g.label"/>
</h:selectOneMenu>
现在我必须查看发送表单时enum
是否正确保存在我的实体中。我会看看我自己能不能做到这一点 - 无论如何,我会很感激这方面的提示或最佳做法!
【讨论】:
【参考方案4】:我用这个简单的方法,还是比较乐观的,你可以根据自己的目的来定制。我将以下代码放在一个可重用的 bean 中,它可以随时从您的应用程序中调用,因此您可以使用包中声明的任何枚举。
public List<String> fromEnum(String cname)
List<String> names = new ArrayList<>();
try
Class c = Class.forName(cname);
Object[] r = c.getEnumConstants();
if (r != null)
for (Object o : r)
names.add(o.toString());
catch (ClassNotFoundException ex)
FaceUtil.ShowError(ex);
return names;
public static void ShowError(Exception ex)
FacesMessage msg=new FacesMessage(FacesMessage.SEVERITY_ERROR,ex.getMessage(),"Error Message");
FacesContext.getCurrentInstance().addMessage(null, msg);
现在在xhtml文件中使用如下:
<p:selectOneMenu value="#jobapp.aplicant.marital">
<f:selectItems value="#rtutil.fromEnum('com.company.package.enMarital')" var="m" itemLabel="#m" itemValue="#m"/>
</p:selectOneMenu>
【讨论】:
【参考方案5】:我前段时间遇到了这个问题,我像你一样解决了它,但后来我意识到我用那个解决方案我不能使用 i18n,因为字符串是在枚举类中硬编码的。所以我修改了我的 enumConverter 以使用messages
进行渲染。
此外,有时您可能希望将枚举呈现为某个唯一标识符,而不是用户可读的文本(供某些组件内部使用)。
这是我的转换器:
import java.util.ResourceBundle;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import com.eyeprevent.configuration.ConfigurationReader;
/**
* converts an enum in a way that makes the conversion reversible (sometimes)
* <ul>
* <li>input: uses its classname and ordinal, reversible<li>
* <li>else: uses its name, non reversible<li>
* </ul>
*/
public class EnumConverter implements Converter
@SuppressWarnings("unchecked")
public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException
if (value == null || value.length() < 1)
return null;
int pos = value.indexOf('@');
if (pos < 0)
throw new IllegalArgumentException(value + " do not point to an enum");
String className = value.substring(0, pos);
Class clazz;
int ordinal = Integer.parseInt(value.substring(pos+1), 10);
try
clazz = Class.forName( className, true, Thread.currentThread().getContextClassLoader() );
// if the clazz is not an enum it might be an enum which is inherited. In this case try to find the superclass.
while (clazz != null && !clazz.isEnum())
clazz = clazz.getSuperclass();
if (clazz == null)
throw new IllegalArgumentException("class " + className + " couldn't be treated as enum");
Enum[] enums = (Enum[]) clazz.getEnumConstants();
if (enums.length >= ordinal)
return enums[ordinal];
catch (ClassNotFoundException e1)
throw new RuntimeException(e1);
throw new IllegalArgumentException("ordinal " + ordinal + " not found in enum " + clazz);
public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException
if (value == null)
return "";
Enum<?> e = (Enum<?>) value;
if (component instanceof UIInput || UIInput.COMPONENT_FAMILY.equals(component.getFamily()))
return e.getClass().getName() + "@" + Integer.toString(e.ordinal(), 10);
ResourceBundle messages =ConfigurationReader.getMessages(context.getViewRoot().getLocale());
return messages.getString(e.name());
【讨论】:
以上是关于JSF 2.0:对 selectOneMenu 使用枚举值 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
JSF / PrimeFaces使用selectOneMenu将列表中的项目关联起来
在 SelectOnemenu 上重置 JSF Primefaces 输入值
在 JSF 中向 selectOneMenu 添加“未选择”选项的最佳方法