UISelectMany su un elenco causa java.lang.ClassCastException: java.lang.String non può essere lanciato su T

Sto usando

su una List :

 

 private List selectedItems; private Map availableItems; 

Quando si invia il modulo e si scorre sopra gli elementi selezionati come di seguito,

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

Quindi ottengo un’eccezione di class:

 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 

Lo stesso problema si verifica con

,

, , ecc. Tutti i componenti di selezione multipla fondamentalmente. Funziona bene in

e tutti gli altri componenti di selezione singola su una proprietà Long value singolo.

Come è causato e come posso risolverlo?

Il tuo problema è causato dai seguenti fatti:

  1. I generici Java sono composti da zucchero sintattico e completamente assenti durante il runtime.
  2. Le espressioni EL vengono eseguite durante il runtime e non durante il compiletime.
  3. I parametri di richiesta HTTP sono ottenuti come String s.

La conseguenza logica è: EL non vede alcuna informazione di tipo generico. EL non vede una List , ma una List . Quindi, quando non si specifica esplicitamente un convertitore, EL eseguirà il valore inviato dopo che String impostato non modificato nella List per mezzo di riflessione . Quando provi a lanciarlo su Long seguito durante il runtime, dovrai ovviamente affrontare ClassCastException .

La soluzione è semplice: specificare esplicitamente un convertitore per String to Long . È ansible utilizzare il LongConverter JSF per questo che ha l’ID del convertitore javax.faces.Long . Altri convertitori incorporati sono elencati qui .

  

Un’altra soluzione senza la necessità di specificare esplicitamente il convertitore è di cambiare il tipo di List in un T[] . In questo modo l’EL vedrà la matrice Long tipizzata e quindi eseguirà la conversione automatica. Ma questo forse richiede cambiamenti altrove nel modello che potrebbero non essere desiderabili.

 private Long[] selectedItems; 

Nel caso tu stia utilizzando un object complesso (javabean, quadro, POJO, ecc.) Come valore di elemento selezionato invece di un tipo standard come Long per cui JSF ha convertitori incorporati, si applicano anche le stesse regole. È sufficiente creare un Converter personalizzato e specificarlo esplicitamente nell’attributo del converter del componente di input, oppure fare affidamento su forClass se è ansible utilizzare T[] . Come creare un tale convertitore viene elaborato nel valore di impostazione Errore conversione per “Convertitore nullo” .