列表<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属性上的所有其他单选组件中工作正常。

这是如何造成的,我该如何解决?

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

  1. Javagenerics是编译时语法糖,在运行时完全不存在。
  2. ELexpression式在运行时运行,而不是在编译期间运行。
  3. HTTP请求参数是以String的forms获得的。

逻辑结果是:EL没有看到任何通用types信息。 EL没有看到一个List<Long> ,而是一个List 。 所以,当你没有明确地指定一个转换器时,EL将在获得提交的值之后以StringList通过reflection手段来修改它。 当您在运行时尝试将其强制转换为Long时,您显然将面临ClassCastException

解决方法很简单:明确指定一个转换为StringLong 。 您可以使用JSF内置的LongConverter ,它具有转换器ID javax.faces.Long 。 其他内置转换器在这里列出。

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

不需要明确指定转换器的另一个解决scheme是将List<T>types更改为T[] 。 这样EL会看到Longtypes的数组,从而执行自动转换。 但是这可能需要在模型的其他地方进行改变,这可能是不可取的。

 private Long[] selectedItems; 

如果你使用一个复杂的对象(javabean,entity,POJO等)作为select项目的值,而不是像JSF内置转换器那样的标准types,那么同样的规则也适用。 你只需要创build一个自定义的Converter并在input组件的converter属性中明确指定它,或者如果你可以使用T[] ,则依赖于forClass 。 “空转换器”的转换错误设置值详细说明了如何创build这样的转换器 。