使用枚举在H:selectManyCheckbox
-
26-09-2019 - |
题
我想在<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类型的列表,而不是枚举类型。有任何想法吗?谢谢!
解决方案
此问题并没有特别涉及到枚举。你将不得不与这些JSF已经内置转换器等List
类型,例如同样的问题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>
一个位更通用的(和哈克)的解决办法是存储枚举类型作为组分属性。
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 List<Enum>
各种genericEnumConverter
的可用。对于List<Double>
,List<Integer>
等人会使用内置的转换器javax.faces.Double
,javax.faces.Integer
等。内置的枚举转换器是由方式不适合,因为不能以指定从上观看侧目标枚举类型(一个Class<Enum>
)。 JSF的工具库 OmniFaces 提供的正是这种转换器的开箱。
注意,对于一个正常的Enum
属性,内建EnumConverter
已经足够了。 JSF将与正确的目标枚举类型自动地实例化。
其他提示
在某些情况下的列表强>也可以同样是阵列的 SOMETYPE [] 下,并且在这种情况下,不需要显式转换器。
通用擦除是把仿制药到语言没有打破旧的东西的一个聪明的办法,但现在我们该决定...
的后果永远活