gpt4 book ai didi

jsf - 在h:selectManyCheckbox中使用枚举

转载 作者:行者123 更新时间:2023-12-03 12:08:02 25 4
gpt4 key购买 nike

我想在<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类型的列表,而不是enum类型的列表。有任何想法吗?谢谢!

最佳答案

此问题与枚举无关。对于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.Doublejavax.faces.Integer等。由于无法从 View 侧指定目标枚举类型( Class<Enum>),因此内置的Enum转换器不合适。 JSF实用程序库 OmniFaces正是提供了此转换器 out the box

注意,对于普通的 Enum属性,内置的 EnumConverter已经足够了。 JSF将使用正确的目标枚举类型自动实例化它。

关于jsf - 在h:selectManyCheckbox中使用枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3822058/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com