The*_*heo 20 jsf enums jsf-2 selectmanycheckbox
我想在一个中使用枚举值<h:selectManyCheckbox>
.正确填充复选框,但是,在选择某些值并提交它们时,它们的运行时类型是String
,而不是枚举.我的代码:
<h:selectManyCheckbox value="#{userController.roles}" layout="pageDirection">
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
当JSF调用setRoles方法时,它包含String类型的列表,而不是枚举类型.有任何想法吗?谢谢!
Bal*_*usC 37
此问题与枚举无关.你将不得不与其他同样的问题List
类型,其JSF已经内置转换器,例如List<Integer>
,List<Double>
,等等.
问题是EL运行运行时,并且在运行时期间丢失泛型类型信息.所以从本质上讲,除非显式指定,否则JSF/EL对List
默认的参数化类型一无所知.从理论上讲,在使用过程中可能会使用令人讨厌的反射黑客,但JSF/EL开发人员可能有理由不这样做.String
Converter
ParameterizedType#getActualTypeArguments()
您确实需要为此明确定义转换器.由于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);
}
}
Run Code Online (Sandbox Code Playgroud)
并使用如下:
<h:selectManyCheckbox value="#{userController.roles}" converter="securityRoleConverter">
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>
Run Code Online (Sandbox Code Playgroud)
要么
<h:selectManyCheckbox value="#{userController.roles}">
<f:converter converterId="securityRoleConverter" />
<f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>
Run Code Online (Sandbox Code Playgroud)
更通用(和hacky)的解决方案是将枚举类型存储为组件属性.
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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
它可用于各种List<Enum>
使用转换器ID genericEnumConverter
.对于List<Double>
,List<Integer>
等等,人们会使用内置转换器javax.faces.Double
,javax.faces.Integer
依此类推.由于无法Class<Enum>
从视图侧指定目标枚举类型(a ),内置的Enum转换器不合适.JSF的工具库OmniFaces提供的正是这种转换器开箱.
请注意,对于普通Enum
属性,内置EnumConverter
已经足够了.JSF将使用正确的目标枚举类型自动实例化它.