我想在<h:selectManyCheckbox>中使用枚举值。复选框被正确填充,但是,当选择一些值并提交它们时,它们的运行时类型是String,而不是枚举。我的代码:
<h:selectManyCheckbox value="#{userController.roles}" layout="pageDirection">
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>UserController类(SecurityRole是枚举类型):
public SelectItem[] getRolesSelectMany() {
SelectItem[] items = new SelectItem[SecurityRole.values().length];
int i = 0;
for (SecurityRole role : SecurityRole.values()) {
items[i++] = new SelectItem(role, role.toString());
}
return items;
}
public List<SecurityRole> getRoles() {
getCurrent().getRoles();
}
public void setRoles(List<SecurityRole> roles) {
getCurrent().setRoles(roles);
}当JSF调用setRoles方法时,它包含一个String类型的列表,而不是枚举类型。有什么想法吗?谢谢!
发布于 2010-09-30 00:36:57
这个问题与枚举没有特别的关系。对于其他具有内置转换器的List类型,例如List<Integer>、List<Double>等,你也会遇到同样的问题。
问题是EL在运行时运行,而泛型类型信息在运行时丢失。因此,本质上,JSF/EL对List的参数化类型一无所知,除非由显式Converter指定,否则缺省为String。从理论上讲,在ParameterizedType#getActualTypeArguments()的帮助下可以使用讨厌的反射黑客,但是JSF/EL开发人员可能有他们不这样做的理由。
为此,您确实需要显式定义一个转换器。由于JSF已经附带了一个内置的EnumConverter (在这种特殊情况下,它不能单独使用,因为您必须在运行时指定枚举类型),所以您可以按如下方式扩展它:
package com.example;
import javax.faces.convert.EnumConverter;
import javax.faces.convert.FacesConverter;
@FacesConverter(value="securityRoleConverter")
public class SecurityRoleConverter extends EnumConverter {
public SecurityRoleConverter() {
super(SecurityRole.class);
}
}并按如下方式使用它:
<h:selectManyCheckbox value="#{userController.roles}" converter="securityRoleConverter">
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>或
<h:selectManyCheckbox value="#{userController.roles}">
<f:converter converterId="securityRoleConverter" />
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>一种更通用(也更老套)的解决方案是将枚举类型存储为组件属性。
package com.example;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
@FacesConverter(value="genericEnumConverter")
public class GenericEnumConverter implements Converter {
private static final String ATTRIBUTE_ENUM_TYPE = "GenericEnumConverter.enumType";
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value instanceof Enum) {
component.getAttributes().put(ATTRIBUTE_ENUM_TYPE, value.getClass());
return ((Enum<?>) value).name();
} else {
throw new ConverterException(new FacesMessage("Value is not an enum: " + value.getClass()));
}
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Class<Enum> enumType = (Class<Enum>) component.getAttributes().get(ATTRIBUTE_ENUM_TYPE);
try {
return Enum.valueOf(enumType, value);
} catch (IllegalArgumentException e) {
throw new ConverterException(new FacesMessage("Value is not an enum of type: " + enumType));
}
}
}它适用于所有使用转换器ID genericEnumConverter的List<Enum>。对于List<Double>、List<Integer>等,可以使用内置的转换器javax.faces.Double、javax.faces.Integer等。顺便说一句,内置枚举转换器是不合适的,因为无法从视图端指定目标枚举类型( Class<Enum>)。JSF实用程序库OmniFaces就提供了这个转换器out the box。
注意,对于一个普通的Enum属性,内置的EnumConverter已经足够了。JSF将使用正确的目标枚举类型自动实例化它。
发布于 2012-08-14 02:15:38
在某些情况下,数组列表也可以是一个数组SomeType[],在这种情况下,不需要显式转换器。
泛型擦除是一种巧妙的方式,可以在不破坏旧东西的情况下将泛型放入语言中,但现在我们永远生活在这个决定的后果中……
https://stackoverflow.com/questions/3822058
复制相似问题