这个问题与枚举没有特别的关系。List
对于 JSF 具有内置转换器的其他类型,例如List<Integer>
、等,您也会遇到同样的问题List<Double>
。
问题是 EL 在运行时运行,而泛型类型信息在运行时丢失。所以本质上,JSF/EL 对 的参数化类型一无所知,List
并且默认为,String
除非由显式指定Converter
。理论上,在 的帮助下使用令人讨厌的反射黑客是可能的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>
更通用(和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));
}
}
}
它可用于各种List<Enum>
使用转换器 ID genericEnumConverter
。对于List<Double>
, List<Integer>
, 等等 , 会使用内置的转换器javax.faces.Double
,javax.faces.Integer
等等。顺便说一下,内置的枚举转换器不适合,因为无法Class<Enum>
从视图侧指定目标枚举类型 (a)。JSF 实用程序库OmniFaces正好提供了这种开箱即用的转换器。
请注意,对于普通Enum
属性,内置函数EnumConverter
已经足够了。JSF 将使用正确的目标枚举类型自动实例化它。