列表<T>上的UISelectMany导致java.lang.ClassCastException:java.lang.String不能转换为T
我正在List<Long>
上使用<p:selectCheckboxMenu>
List<Long>
:
<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); // ... }
然后我得到一个类抛出exception:
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
属性上的所有其他单选组件中工作正常。
这是如何造成的,我该如何解决?
您的问题是由以下事实引起的:
- Javagenerics是编译时语法糖,在运行时完全不存在。
- ELexpression式在运行时运行,而不是在编译期间运行。
- HTTP请求参数是以
String
的forms获得的。
逻辑结果是:EL没有看到任何通用types信息。 EL没有看到一个List<Long>
,而是一个List
。 所以,当你没有明确地指定一个转换器时,EL将在获得提交的值之后以String
在List
通过reflection手段来修改它。 当您在运行时尝试将其强制转换为Long
时,您显然将面临ClassCastException
。
解决方法很简单:明确指定一个转换为String
到Long
。 您可以使用JSF内置的LongConverter
,它具有转换器ID javax.faces.Long
。 其他内置转换器在这里列出。
<p:selectCheckboxMenu ... converter="javax.faces.Long">
不需要明确指定转换器的另一个解决scheme是将List<T>
types更改为T[]
。 这样EL会看到Long
types的数组,从而执行自动转换。 但是这可能需要在模型的其他地方进行改变,这可能是不可取的。
private Long[] selectedItems;
如果你使用一个复杂的对象(javabean,entity,POJO等)作为select项目的值,而不是像JSF内置转换器那样的标准types,那么同样的规则也适用。 你只需要创build一个自定义的Converter
并在input组件的converter
属性中明确指定它,或者如果你可以使用T[]
,则依赖于forClass
。 “空转换器”的转换错误设置值详细说明了如何创build这样的转换器 。