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

Posted

技术标签:

【中文标题】List<T> 上的 UISelectMany 导致 java.lang.ClassCastException:java.lang.String 无法强制转换为 T【英文标题】:UISelectMany on a List<T> causes java.lang.ClassCastException: java.lang.String cannot be cast to T 【发布时间】:2013-11-09 05:18:47 【问题描述】:

我在List&lt;Long&gt; 上使用&lt;p:selectCheckboxMenu&gt;

<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

&lt;p:selectManyCheckbox&gt;&lt;p:selectManyMenu&gt;&lt;h:selectManyMenu&gt;等也会出现同样的问题,基本上都是多选组件。它在 &lt;p:selectOneMenu&gt; 和单个值 Long 属性上的所有其他单选组件中运行良好。

这是怎么引起的,我该如何解决?

【问题讨论】:

你能分享一下你的列表内容吗,因为这段代码似乎不太容易出现这个异常 @ankit 看到我的帖子。我编辑并添加图片 【参考方案1】:

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

    Java 泛型是编译时语法糖,在运行时完全不存在。 EL 表达式在运行时而不是在编译时运行。 HTTP 请求参数为obtained 为Strings。

逻辑结果是:EL 看不到任何通用类型信息。 EL 没有看到List&lt;Long&gt;,而是看到List。因此,当您没有明确指定转换器时,EL 将在获得提交的值作为String 后将其设置为未修改在List 通过reflection 手段。当您尝试在运行时之后将其转换为 Long 时,您显然会遇到 ClassCastException

解决方案很简单:明确指定StringLong 的转换器。您可以为此使用 JSF 内置 LongConverter,它的转换器 ID 为 javax.faces.Long。其他内置转换器列在here。

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

另一个不需要明确指定转换器的解决方案是将List&lt;T&gt; 类型更改为T[]。这样,EL 将看到Long 类型的数组,从而执行自动转换。但这可能需要在模型的其他地方进行更改,这可能是不可取的。

private Long[] selectedItems;

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

【讨论】:

命中 ...我正在寻找答案..我不知道我们可以在 JSF 本身中做到这一点。 遗憾的是,只有第一个解决方法效果很好,看起来 primefaces 创建了一个 List 并且无法转换为 array,因为抛出了 Value not valid 验证错误 这里详述Validation Error: Value is not valid:***.com/q/9069379

以上是关于List<T> 上的 UISelectMany 导致 java.lang.ClassCastException:java.lang.String 无法强制转换为 T的主要内容,如果未能解决你的问题,请参考以下文章

C#如何把List of Object转换成List of T具体类型

Java泛型中<?>和<T>的区别

根据键将 List<List<List<T>>> 转换为 List<List<T>>

Java 流:将 List<T> 转换为 List<List<T>>

为啥我在 List<List<T>> 中复制 List<T> 时存在依赖关系? [复制]

在 C# 中将 List<List<T>> 转换为 List<T>