在h中使用枚举:selectManyCheckbox [英] Use enum in h:selectManyCheckbox

查看:126
本文介绍了在h中使用枚举:selectManyCheckbox的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在< 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());
}
返回项目;
}

public List< SecurityRole> getRoles(){
getCurrent()。getRoles();
}

public void setRoles(List< SecurityRole> roles){
getCurrent()。setRoles(roles);
}

当JSF调用setRoles方法时,它包含一个String类型的列表,不是枚举类型。有任何想法吗?谢谢!

解决方案

此问题与枚举无关。您将遇到与JSF内置转换器的其他 List 类型相同的问题。 列表<整数> 列表< Double> 等等。



问题是EL运行时运行时间,通用类型信息在运行时丢失。所以在本质上,JSF / EL不知道关于 List 的参数化类型的任何内容,默认为 String ,除非否则由显式的转换器指定。在理论上,这可能是使用恶意的反思黑客在 ParameterizedType#getActualTypeArguments() ,但是JSF / EL开发人员可能有理由不这样做。 p>

您真的需要为此定义一个转换器。由于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) ;
}

}

使用如下: / p>

 < 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<?>)值).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 的各种列表<枚举> 对于列表< Double> 列表<整数> 等,会使用内置转换器 javax.faces.Double javax.faces.Integer 等等。由于无法从视图侧指定目标枚举类型(一个类< Enum> ),因此内置的枚举转换器是不合适的。 JSF实用程序库 OmniFaces 提供了这个转换器 out the box



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


I want to use enum values in a <h:selectManyCheckbox>. The checkboxes get populated correctly, however, when selecting some values and submitting them, their runtime type is String, and not enum. My code:

<h:selectManyCheckbox value="#{userController.roles}" layout="pageDirection">
     <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>

UserController class (SecurityRole is an enum type):

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);
}

When JSF calls the setRoles method, it contains a list of type String, and not the enum type. Any ideas? Thanks!

解决方案

This problem is not specifically related to enums. You would have the same problem with other List types for which JSF has builtin converters, e.g. List<Integer>, List<Double>, etcetera.

The problem is that EL operates runtime and that generic type information is lost during runtime. So in essence, JSF/EL doesn't know anything about the parameterized type of the List and defaults to String unless otherwise specified by an explicit Converter. In theory, it would have been possible using nasty reflection hacks with help of ParameterizedType#getActualTypeArguments(), but the JSF/EL developers may have their reasons for not doing this.

You really need to explicitly define a converter for this. Since JSF already ships with a builtin EnumConverter (which isn't useable standalone in this particular case because you have to specify the enum type during runtime), you could just extend it as follows:

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);
    }

}

And use it as follows:

<h:selectManyCheckbox value="#{userController.roles}" converter="securityRoleConverter">
    <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>

or

<h:selectManyCheckbox value="#{userController.roles}">
    <f:converter converterId="securityRoleConverter" />
    <f:selectItems value="#{userController.rolesSelectMany}" />
</h:selectManyCheckbox>


A bit more generic (and hacky) solution would be to storing the enum type as component attribute.

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));
        }
    }

}

It's useable on all kinds of List<Enum> using converter ID genericEnumConverter. For List<Double>, List<Integer>, etc one would have used the builtin converters javax.faces.Double, javax.faces.Integer and so on. The builtin Enum converter is by the way unsuitable due to the inability to specify the target enum type (a Class<Enum>) from the view side on. The JSF utility library OmniFaces offers exactly this converter out the box.

Note that for a normal Enum property, the builtin EnumConverter already suffices. JSF will instantiate it automagically with the right target enum type.

这篇关于在h中使用枚举:selectManyCheckbox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆