UISelectMany en una lista causa java.lang.ClassCastException: java.lang.String no se puede convertir a T

Estoy usando

en una List :

 

 private List selectedItems; private Map availableItems; 

Al enviar el formulario y colocar los elementos seleccionados como se muestra a continuación,

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

Luego recibo una excepción de lanzamiento de clase:

 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 

El mismo problema ocurre con

,

, , etc. Todos los componentes de selección múltiple básicamente. Funciona bien en

y todos los demás componentes de selección única en un solo valor Propiedad Long .

¿Cómo es esto causado y cómo puedo resolverlo?

Su problema es causado por los siguientes hechos:

  1. Los generics de Java son azúcar sintáctico en tiempo de comstackción y completamente ausentes durante el tiempo de ejecución.
  2. Las expresiones EL se ejecutan durante el tiempo de ejecución y no durante el tiempo de comstackción.
  3. Los parámetros de solicitud HTTP se obtienen como String s.

La consecuencia lógica es que EL no ve ningún tipo de información genérica. EL no ve una List , sino una List . Entonces, cuando usted no especifica explícitamente un convertidor, EL luego de obtener el valor presentado como String configurará sin modificaciones en la List por medios de reflexión . Cuando intenta lanzarlo a Long luego durante el tiempo de ejecución, obviamente se enfrentará a una ClassCastException .

La solución es simple: especifique explícitamente un convertidor para String a Long . Puede usar el LongConverter incorporado JSF para esto que tiene el ID de convertidor javax.faces.Long . Otros convertidores integrados se enumeran aquí .

  

Otra solución sin la necesidad de especificar explícitamente el convertidor es cambiar el tipo de List a T[] . De esta forma, el EL verá la matriz de tipo Long y, por lo tanto, realizará la conversión automática. Pero esto posiblemente requiera cambios en otras partes del modelo que pueden no ser deseables.

 private Long[] selectedItems; 

En caso de que esté utilizando un objeto complejo (javabean, entidad, POJO, etc.) como valor de elemento seleccionado en lugar de un tipo estándar como Long para el cual JSF tiene convertidores incorporados, también se aplican las mismas reglas. Solo necesita crear un Converter personalizado y especificarlo explícitamente en el atributo converter del componente de entrada, o confiar en forClass si puede usar T[] . Cómo crear un convertidor de este tipo se elabora en el valor de configuración de Error de Conversión para ‘Convertidor nulo’ .