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 ответ

Решение

Ваша проблема вызвана следующими фактами:

  1. Обобщения Java являются синтаксическим сахаром времени компиляции и полностью отсутствуют во время выполнения.
  2. EL выражения выполняются во время выполнения, а не во время компиляции.
  3. Параметры 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[], Как создать такой конвертер, подробно описано в параметре "Ошибка преобразования" для "нулевого конвертера".

Другие вопросы по тегам