UISelectMany для списка<T> вызывает java.lang.ClassCastException: java.lang.String не может быть приведен к T
Я использую <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);
// ...
}
Тогда я получаю исключение приведения класса:
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 ответ
Ваша проблема вызвана следующими фактами:
- Обобщения Java являются синтаксическим сахаром времени компиляции и полностью отсутствуют во время выполнения.
- EL выражения выполняются во время выполнения, а не во время компиляции.
- Параметры HTTP-запроса получаются как
String
s.
Логическое следствие: EL не видит никакой информации общего типа. EL не видит List<Long>
, но List
, Таким образом, если вы не укажете явно конвертер, EL после получения отправленного значения будет String
установить его неизмененным в List
средствами отражения. Когда вы пытаетесь привести его к Long
впоследствии во время выполнения вы, очевидно, столкнетесь с ClassCastException
,
Решение простое: явно укажите конвертер для String
в Long
, Вы можете использовать встроенную JSF LongConverter
для этого, который имеет идентификатор конвертера javax.faces.Long
, Другие встроенные преобразователи перечислены здесь.
<p:selectCheckboxMenu ... converter="javax.faces.Long">
Другое решение без необходимости явно указывать конвертер - это изменить List<T>
введите в T[]
, Таким образом, EL увидит Long
типизированный массив и, таким образом, выполняет автоматическое преобразование Но это, возможно, требует изменений в других частях модели, что может быть нежелательным.
private Long[] selectedItems;
В случае, если вы используете сложный объект (javabean, entity, POJO и т. Д.) В качестве значения элемента select вместо стандартного типа, такого как Long
для которого JSF имеет встроенные конвертеры, то применяются те же правила. Вам нужно только создать кастом Converter
и явно указать его в компоненте ввода converter
атрибут или полагаться на forClass
если вы можете использовать T[]
, Как создать такой конвертер, подробно описано в параметре "Ошибка преобразования" для "нулевого конвертера".