Ответ 1
1. Цель недостижима, идентификатор "bean" преобразован в ноль
Это сводится к тому, что сам экземпляр управляемого компонента не может быть найден именно этим идентификатором (именем управляемого компонента) в EL, как, например, #{bean}
.
Выявление причины можно разбить на три этапа:
а. Кто управляет бобом?
б. Какое имя (по умолчанию) управляемого бина?
с. Где класс бобов?
1a. Кто управляет бобом?
Первым шагом будет проверка того, какая структура управления компонентом отвечает за управление экземпляром компонента. Это JSF через @ManagedBean
? Или это CDI через @Named
? Или это spring через @Component
? Можете ли вы убедиться, что вы не смешиваете несколько аннотаций, специфичных для структуры управления компонентами, в одном и том же классе базовых компонентов? Например, @Named @Component
или @Named @ManagedBean
или @ManagedBean @Component
. Это не верно. Бин должен управляться не более чем одной структурой управления бином, и эта структура должна быть правильно настроена. Если вы уже не знаете, какой из них выбрать, перейдите к разделу "Бэк-бины" (@ManagedBean) или CDI-бины (@Named)? и интеграция Spring JSF: как внедрить компонент/сервис Spring в управляемый компонент JSF?
В случае если JSF управлял компонентом через @ManagedBean
, вам необходимо убедиться в следующем:
-
Корневая декларация
faces-config.xml
совместима с JSF 2.0. Таким образом, XSD файл иversion
должны как минимум указывать JSF 2.0 или выше, а не 1.x.<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0">
Для JSF 2.1 просто замените
2_0
и2.0
на2_1
и2.1
соответственно.Если вы используете JSF 2.2 или выше, убедитесь, что вы используете пространства имен
xmlns.jcp.org
вместоjava.sun.com
во всех местах.<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2">
Для JSF 2.3 просто замените
2_2
и2.2
на2_3
и2.3
соответственно. -
Вы случайно не импортировали
javax.annotation.ManagedBean
вместоjavax.faces.bean.ManagedBean
. Будьте осторожны с автозаполнением IDE, Eclipse, как известно, автоматически предлагает неправильный в качестве первого элемента в списке. - Вы не
@ManagedBean
<managed-bean>
в стиле JSF 1.x в@ManagedBean
faces-config.xml
в том же классе@ManagedBean
компонента вместе с другим именем управляемого компонента. Этот будет иметь приоритет над@ManagedBean
.faces-config.xml
с JSF 2.0, регистрация управляемого bean-компонентаfaces-config.xml
не требуется, просто удалите его. - Ваш путь к классу во время выполнения является чистым и не содержит дубликатов в JAR файлах, связанных с JSF API. Убедитесь, что вы не смешиваете несколько реализаций JSF (Mojarra и MyFaces). Убедитесь, что вы не предоставляете другой JSF файл или даже JAR файл Java EE API вместе с веб-приложением, когда целевой контейнер уже включает JSF API из коробки. См. Также раздел "Установка JSF" нашей вики-страницы JSF для получения инструкций по установке JSF. В случае, если вы собираетесь обновить JSF, включенную в контейнер, с WAR, а не в самом контейнере, убедитесь, что вы указали целевому контейнеру использовать JSF API в комплекте с WAR/impl.
- Если вы упаковываете управляемые компоненты JSF в JAR файл, убедитесь, что JAR-
/META-INF/faces-config.xml
имеет по крайней мере совместимый с JSF 2.0/META-INF/faces-config.xml
. См. Также Как ссылаться на управляемые bean-компоненты JSF, которые представлены в файле JAR? -
Если вы на самом деле используете Jurassic JSF 1.x и не можете выполнить обновление, тогда вам нужно зарегистрировать bean-компонент с помощью
<managed-bean>
в@ManagedBean
faces-config.xml
вместо@ManagedBean
. Не забудьте исправить путь сборки проекта таким образом, чтобы у вас больше не было библиотек JSF 2.x (чтобы аннотация@ManagedBean
не@ManagedBean
путаницы при компиляции).
В случае, если это CDI, управляющий компонентом через @Named
, вам необходимо убедиться в следующем:
-
Для CDI 1.0 (Java EE 6) требуется файл
/WEB-INF/beans.xml
, чтобы включить CDI в WAR. Он может быть пустым или иметь только следующее содержимое:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> </beans>
-
CDI 1.1 (Java EE 7) без
beans.xml
, пустого файлаbeans.xml
или с указанным выше совместимым с CDI 1.0beans.xml
будет работать так же, как CDI 1.0. Если существуетbeans.xml
совместимый с CDI 1.1, с явнойversion="1.1"
, то по умолчанию он будет регистрировать только@Named
с явной аннотацией области действия CDI, такой как@RequestScoped
,@ViewScoped
,@SessionScoped
,@ApplicationScoped
и т.д. Если вы собираетесь зарегистрировать все bean-компоненты как управляемые CDI-компоненты, даже те, которые не имеют явной области действия CDI, используйте приведенный ниже CDI 1.1, совместимый/WEB-INF/beans.xml
с установленнымbean-discovery-mode="all"
(по умолчаниюbean-discovery-mode="annotated"
).<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> </beans>
-
При использовании CDI 1. 1+ с
bean-discovery-mode="annotated"
(по умолчанию) убедитесь, что вы случайно не импортировали область JSF, такую какjavax.faces.bean.RequestScoped
вместо области CDIjavax.enterprise.context.RequestScoped
. Остерегайтесь с автозаполнением IDE. - При использовании Mojarra 2.3.0-2.3.2 и CDI 1. 1+ с
bean-discovery-mode="annotated"
(по умолчанию), вам нужно обновить Mojarra до 2.3.3 или новее из-за ошибки. Если вы не можете выполнить обновление, то вам нужно либо установитьbean-discovery-mode="all"
вbeans.xml
, либо поместить специальную аннотацию@FacesConfig
JSF 2.3 в произвольный класс в WAR (обычно это какой-то класс запуска приложения. - non- Контейнеры Java EE, такие как Tomcat и Jetty, не поставляются в комплекте с CDI. Вам необходимо установить его вручную. Это немного больше работы, чем просто добавление библиотеки JAR. Для Tomcat обязательно следуйте инструкциям в этом ответе: Как установить и использовать CDI на Tomcat?
- Ваш путь к классу во время выполнения является чистым и не содержит дубликатов в JAR файлах, связанных с API CDI. Убедитесь, что вы не смешиваете несколько реализаций CDI (Weld, OpenWebBeans и т.д.). Убедитесь, что вы не предоставили другой веб-приложение CDI или даже JAR файл API Java EE, когда целевой контейнер уже связывает CDI API из коробки.
-
Если вы упаковываете управляемые компоненты CDI для представлений JSF в JAR, убедитесь, что в JAR есть как минимум действительный
/META-INF/beans.xml
(который можно оставить пустым).
В случае если Spring управляет компонентом через @Component
, вам необходимо убедиться в следующем:
-
Spring устанавливается и интегрируется в соответствии с его документацией. Важно отметить, что вы должны по крайней мере иметь это в
web.xml
:<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
И это в
faces-config.xml
:<application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application>
-
(выше все, что я знаю в отношении Spring - я не делаю Spring - не стесняйтесь редактировать/комментировать другие возможные причины, связанные с Spring; например, некоторые проблемы, связанные с конфигурацией XML)
В случае, если это компонент ретранслятора, который управляет (вложенным) bean-компонентом через его атрибут var
(например, <h:dataTable var="item">
, <ui:repeat var="item">
, <p:tabView var="item">
и т.д.) и вы фактически получили "Target Unreachable, идентификатор" item "разрешен до нуля", тогда вам необходимо убедиться в следующем:
-
#{item}
Item#{item}
не упоминается вbinding
атрибута любого дочернего компонента. Это неверно, поскольку атрибутbinding
выполняется во время построения представления, а не во время отображения представления. Более того, физически в дереве компонентов есть только один компонент, который просто повторно используется во время каждого цикла итерации. Другими словами, вы должны использоватьbinding="#{bean.component}"
вместоbinding="#{item.component}"
. Но гораздо лучше избавиться от объединения компонентов в бин и исследовать/задать правильный подход к проблеме, которую вы решили решить таким образом. Смотрите также Как работает атрибут 'binding' в JSF? Когда и как его следует использовать?
1б. Какое имя (по умолчанию) управляемого бина?
Вторым шагом будет проверка зарегистрированного имени управляемого бина. Соглашения об использовании JSF и Spring соответствуют спецификации JavaBeans, в то время как CDI имеет исключения в зависимости от impl/версии CDI.
-
FooBean
бобовFooBean
ниже,@Named public class FooBean {}
будет во всех средах управления bean-компонентами иметь имя управляемого bean-компонента по умолчанию
#{fooBean}
согласно спецификации JavaBeans. -
FooBean
бобовFooBean
ниже,@Named public class FOOBean {}
чье неквалифицированное имя класса начинается как минимум с двух прописных в JSF, и Spring будет иметь имя управляемого бина по умолчанию с точно неквалифицированным именем класса
#{FOOBean}
, также соответствуют спецификациям JavaBeans. В CDI это также имеет место в версиях Weld, выпущенных до июня 2015 года, но не в версиях Weld, выпущенных после июня 2015 года (2.2.14/2.3.0.B1/3.0.0.A9), ни в OpenWebBeans из-за недосмотра в CDI спец. В этих версиях Weld и во всех версиях OWB это только первый символ в нижнем регистре#{fOOBean}
. -
Если вы явно указали имя управляемого компонента
foo
какfoo
ниже,@Named("foo") public class FooBean {}
или эквивалентно с
@ManagedBean(name="foo")
или@Component("foo")
, тогда он будет доступен только#{foo}
и, следовательно, не#{fooBean}
.
1c. Где класс бобов?
Третий шаг - двойная проверка, если класс компонента поддержки находится в нужном месте во встроенном и развернутом файле WAR. Убедитесь, что вы правильно выполнили полную очистку, перестроение, повторное развертывание и перезапуск проекта и сервера, если вы действительно заняты написанием кода и нетерпеливым нажатием клавиши F5 в браузере. Если все еще напрасно, позвольте системе сборки создать файл WAR, который вы затем извлекаете и проверяете с помощью инструмента ZIP. Скомпилированный файл .class
класса базового компонента должен находиться в его структуре пакета в /WEB-INF/classes
. Или, когда он упакован как часть модуля JAR, JAR, содержащий скомпилированный файл .class
должен находиться в /WEB-INF/lib
и, следовательно, не может быть, например, EAR /lib
или где-либо еще.
Если вы используете Eclipse, убедитесь, что класс bean-компонента находится в src
а не в WebContent
, и убедитесь, что Project> Build Automatics включен. Если вы используете Maven, убедитесь, что класс bean-компонента находится в src/main/java
и, следовательно, не в src/main/resources
или src/main/webapp
.
Если вы упаковываете веб-приложение как часть EAR с EJB + WAR, вам необходимо убедиться, что классы компонентов поддержки находятся в модуле WAR и, следовательно, не в модуле EAR или модуле EJB. Бизнес-уровень (EJB) должен быть свободен от любых артефактов, связанных с веб-уровнем (WAR), чтобы бизнес-уровень можно было повторно использовать для нескольких различных веб-уровней (JSF, JAX-RS, JSP/Servlet и т.д.).
2. Цель недостижима, "сущность" вернула ноль
Это сводится к тому, что вложенная entity
свойства, как в #{bean.entity.property}
возвратила null
. Как правило, это только выставляет, когда JSF необходимо установить значение для property
через входной компонент, как показано ниже, в то время как #{bean.entity}
фактически возвращается null
.
<h:inputText value="#{bean.entity.property}" />
Необходимо убедиться, что вы заранее подготовили объект модели в @PostConstruct
, @PostConstruct
<f:viewAction>
или, возможно, методе действия add()
если вы работаете со списками CRUD и/или диалоговыми окнами в одном представлении.,
@Named
@ViewScoped
public class Bean {
private Entity entity; // +getter (setter is not necessary).
@Inject
private EntityService entityService;
@PostConstruct
public void init() {
// In case you're updating an existing entity.
entity = entityService.getById(entityId);
// Or in case you want to create a new entity.
entity = new Entity();
}
// ...
}
Что касается важности @PostConstruct
; Выполнение этого в обычном конструкторе не удастся, если вы используете инфраструктуру управления bean-компонентами, которая использует прокси, такие как CDI. Всегда используйте @PostConstruct
для подключения инициализации экземпляра управляемого компонента (и используйте @PreDestroy
для @PreDestroy
к уничтожению экземпляра управляемого компонента). Кроме того, в конструкторе у вас еще не будет доступа ни к каким внедренным зависимостям, смотрите также NullPointerException при попытке получить доступ к компоненту @Inject в конструкторе.
В случае, если entityId
предоставляется через <f:viewParam>
, вам нужно будет использовать <f:viewAction>
вместо @PostConstruct
. См. Также Когда использовать f: viewAction/preRenderView по сравнению с PostConstruct?
Вам также необходимо убедиться, что вы сохраняете null
модель non- во время обратной передачи на случай, если вы создадите ее только с помощью метода действия add()
. Проще всего было бы поместить боб в область видимости. Смотрите также Как правильно выбрать сферу применения бобов?
3. Цель недостижима, "ноль" вернул ноль
Фактически это имеет ту же причину, что и # 2, только используемая (более старая) реализация EL несколько ошибочна в сохранении имени свойства для отображения в сообщении об исключении, которое в конечном итоге неверно отображается как 'null'. Это только усложняет отладку и исправление, когда у вас есть несколько вложенных свойств, таких как #{bean.entity.subentity.subsubentity.property}
.
Решение остается тем же: убедитесь, что рассматриваемая вложенная сущность не равна null
на всех уровнях.
4. Цель недостижима, '' 0 '' вернул ноль
Это также имеет ту же причину, что и # 2, только используемая (более старая) реализация EL содержит ошибки при формулировании сообщения об исключении. Это доступно только в том случае, если вы используете скобочную нотацию []
в EL, как в #{bean.collection[index]}
где сама #{bean.collection}
равна non- null, но элемент по указанному индексу не существует, Такое сообщение должно быть интерпретировано как:
Цель недостижима, 'collection [0]' возвратила ноль
Решение также совпадает С# 2: убедитесь, что элемент коллекции доступен.
5. Цель недостижима, "BracketSuffix" вернул ноль
Фактически это имеет ту же причину, что и # 4, только используемая (более старая) реализация EL несколько ошибочна при сохранении индекса итерации для отображения в сообщении об исключении, которое в конечном итоге неверно отображается как "BracketSuffix", который на самом деле является символом ]
. Это только усложняет отладку и исправление, когда в коллекции несколько элементов.
Другие возможные причины javax.el.PropertyNotFoundException
:
- javax.el.ELException: Ошибка чтения 'foo' для типа com.example.Bean
- javax.el.ELException: не удалось найти свойство actionMethod в классе com.example.Bean
- javax.el.PropertyNotFoundException: свойство 'foo' не найдено для типа com.example.Bean
- javax.el.PropertyNotFoundException: свойство 'foo' недоступно для чтения по типу java.lang.Boolean
- javax.el.PropertyNotFoundException: свойство не найдено для типа org.hibernate.collection.internal.PersistentSet
- Код Outcommented Facelets по-прежнему вызывает выражения EL, такие как # {bean.action()} и вызывает исключение javax.el.PropertyNotFoundException для # {bean.action}