列表<t>上的UISelectMany导致java.lang.ClassCastException:java.lang.String无法强制转换为T </t>

时间:2013-11-09 05:18:48

标签: jsf jsf-2 primefaces classcastexception selectmanycheckbox

我在List<Long>上使用<p:selectCheckboxMenu>

<p:selectCheckboxMenu value="#{bean.selectedItems}">
    <f:selectItems value="#{bean.availableItems}" />
</p:selectCheckboxMenu>
private List<Long> selectedItems;
private Map<String, Long> availableItems;

提交表单并循环显示所选项目时,

for (int i = 0; i < selectedItems.size(); i++) {
    Long id = selectedItems.get(i);
    // ...
}

然后我得到一个类强制转换异常:

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
    at com.example.Bean.submit(Bean.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.el.parser.AstValue.invoke(AstValue.java:278)
    at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:274)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
    ... 27 more

<p:selectManyCheckbox><p:selectManyMenu><h:selectManyMenu>等出现同样的问题。基本上都是所有多选组件。它在<p:selectOneMenu>以及单个值Long属性上的所有其他单选组件中工作正常。

这是如何引起的?如何解决?

1 个答案:

答案 0 :(得分:8)

您的问题是由以下事实引起的:

  1. Java泛型是编译时语法糖,在运行时完全不存在。
  2. EL表达式在运行时运行,而不是在编译期间运行。
  3. HTTP请求参数obtainedString s。
  4. 逻辑后果是:EL没有看到任何泛型类型信息。 EL看不到List<Long>,而是List。因此,当您未明确指定转换器时,EL将在获取提交的值后String将其设置为List reflection表示未修改。当您在运行时尝试将其强制转换为Long时,您显然会遇到ClassCastException

    解决方案很简单:明确指定StringLong的转换器。您可以将JSF内置LongConverter用于具有转换器标识javax.faces.Long的内容。列出了其他内置转换器here

    <p:selectCheckboxMenu ... converter="javax.faces.Long">
    

    无需明确指定转换器的另一种解决方案是将List<T>类型更改为T[]。这样,EL将看到Long类型的数组,从而执行自动转换。但这可能需要模型中其他地方的变化,这可能是不可取的。

    private Long[] selectedItems;
    

    如果您使用复杂对象(javabean,entity,POJO等)作为选择项值而不是JSF具有内置转换器的标准类型(如Long),则同样的规则也适用。您只需要创建自定义Converter并在输入组件的converter属性中明确指定它,或者如果您可以使用forClass则依赖T[]。如何创建这样的转换器在Conversion Error setting value for 'null Converter'中详细说明。