当尝试像这样#{bean.entity.property}
在EL中引用托管Bean时,有时会抛出javax.el.PropertyNotFoundException: Target Unreachable
异常,通常是在设置bean属性或调用bean操作时。
似乎有五种不同类型的消息:
- 目标无法访问,标识符"bean"解析为空
- 目标无法访问,"实体"返回空 值
- 目标无法访问,"空"返回空
- 目标无法访问,"0"返回空 值
- 目标无法访问,"括号后缀"返回空 值
它们都意味着什么?它们是如何引起的,应该如何解决?
1. 目标不可达,标识符"bean"解析为空
这归结为,像#{bean}
一样,无法通过 EL 中的确切标识符(托管 Bean 名称)找到托管 Bean 实例本身。
确定原因可以分为三个步骤:
一个。谁在管理豆子?
b。(默认的)托管 Bean 名称是什么?
c。背豆类在哪里?
1a.谁在管理豆子?
第一步是检查哪个 Bean 管理框架负责管理 Bean 实例。是通过@Named
的CDI吗?还是通过@ManagedBean
的JSF?还是通过@Component
的春天?您能否确保不会在同一个支持 Bean 类上混合多个特定于 Bean 管理框架的注释?例如@Named @ManagedBean
、@Named @Component
或@ManagedBean @Component
。这是错误的。Bean 必须由最多一个 Bean 管理框架管理,并且必须正确配置该框架。如果您已经不知道该选择哪个,请前往背豆(@ManagedBean)或CDI豆(@Named)?和Spring JSF集成:如何在JSF管理的Bean中注入Spring组件/服务?
如果是CDI通过@Named
来管理豆子,那么您需要确保以下几点:
-
CDI 1.0 (Java EE 6) 需要一个
/WEB-INF/beans.xml
文件才能在 WAR 中启用 CDI。它可以为空,也可以只有以下内容:<?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>
-
没有任何
beans.xml
的 CDI 1.1 (Java EE 7) 或空的beans.xml
文件,或与上述 CDI 1.0 兼容beans.xml
的行为将与 CDI 1.0 相同。当有一个CDI 1.1兼容beans.xml
带有显式version="1.1"
时,那么默认情况下,它只会注册@Named
具有显式CDI作用域注释的bean,例如@RequestScoped
,@ViewScoped
,@SessionScoped
,@ApplicationScoped
等。如果您打算将所有 bean 注册为 CDI 管理的 bean,即使是那些没有显式 CDI 作用域的 bean,请使用以下 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
)而不是 CDI 作用域javax.enterprise.context.RequestScoped
。注意使用 IDE 自动完成功能。 -
当使用Mojarra 2.3.0-2.3.2和CDI 1.1+与
bean-discovery-mode="annotated"
(默认)时,由于错误,您需要将Mojarra升级到2.3.3或更高版本。如果你无法升级,那么你需要在beans.xml
中设置bean-discovery-mode="all"
,或者将JSF 2.3特定的@FacesConfig
注释放在WAR中的任意类上(通常是某种应用程序范围的启动类)。
在声明符合 Servlet 4.0 的 Servlet 4.0
web.xml
容器上使用 JSF 2.3 时,您需要将特定于 JSF 2.3 的@FacesConfig
注释显式放在 WAR 中的任意类(通常是某种应用程序范围的启动类)上。这在 Servlet 3.x 中不是必需的。使用 CDI 3.0 时,包的第一个版本从
javax.*
重命名为jakarta.*
,则需要确保所有部署描述符文件beans.xml
、web.xml
、faces-config.xml
都符合新的jakartaee
架构,因此不符合旧的javaee
方案。<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd" version="3.0" bean-discovery-mode="all"> </beans>
像Tomcat和Jetty这样的非JEE容器不附带CDI捆绑。您需要手动安装它。这比仅仅添加库 JAR 要多一些工作。对于 Tomcat,请确保按照此答案中的说明进行操作:如何在 Tomcat 上安装和使用 CDI?
运行时类路径是干净的,并且在与 CDI API 相关的 JAR 中没有重复项。确保你没有混合多个CDI实现(Weld,OpenWebBeans等)。当目标容器已经捆绑了开箱即用的 CDI API 时,请确保不要在 Web 应用中提供另一个 CDI 甚至 Java EE API JAR 文件。
如果要在 JAR 中为 JSF 视图打包 CDI 管理的 Bean,请确保 JAR 至少具有有效的
<小时 />/META-INF/beans.xml
(可以保留为空)。
如果是JSF通过 自 2.3 已弃用的@ManagedBean
来管理 Bean,并且您无法迁移到 CDI,那么您需要确保以下几点:
-
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 会自动将错误的项目建议为列表中的第一项。 -
您没有在
faces-config.xml
相同的支持Bean类以及不同的受管Bean名称上用JSF 1.x样式<managed-bean>
条目覆盖@ManagedBean
。这个将优先于@ManagedBean
.从 JSF 2.0 开始,不需要在faces-config.xml
中注册受管 Bean,只需将其删除即可。 -
运行时类路径是干净的,并且在与 JSF API 相关的 JAR 中没有重复项。确保你没有混合使用多个JSF实现(Mojarra和MyFaces)。确保当目标容器已经捆绑了开箱即用的 JSF API 时,不要在 Web 应用程序中提供另一个 JSF 甚至 Java EE API JAR 文件。另请参阅 JSF wiki 页面的"安装 JSF"部分,了解 JSF 安装说明。如果您打算从 WAR 而不是容器本身升级容器捆绑的 JSF,请确保您已指示目标容器使用 WAR 捆绑的 JSF API/impl。
-
如果要将 JSF 管理的 Bean 打包在 JAR 中,请确保 JAR 至少具有与 JSF 2.0 兼容的
/META-INF/faces-config.xml
。另请参阅如何引用 JAR 文件中提供的 JSF 受管 Bean? -
如果你实际上使用的是侏罗纪 JSF 1.x,并且无法升级,那么你需要在
<小时 />faces-config.xml
中通过<managed-bean>
而不是@ManagedBean
注册 bean。不要忘记修复您的项目构建路径,以便您不再拥有 JSF 2.x 库(这样@ManagedBean
注释就不会混淆地成功编译)。
如果是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配置相关的问题)
<小时 />
如果它是一个中继器组件,它通过其var
属性管理(嵌套的)bean(例如<h:dataTable var="item">
、<ui:repeat var="item">
、<p:tabView var="item">
等),并且您实际上得到了"目标无法访问,标识符'项目'解析为空",那么您需要确保以下内容:
-
<小时 />#{item}
不会在任何子组件的属性binding
引用。这是不正确的binding
因为属性在视图构建期间运行,而不是在视图呈现期间运行。此外,组件树中实际上只有一个组件,可以在每个迭代轮次中重复使用。换句话说,您实际上应该使用binding="#{bean.component}"
而不是binding="#{item.component}"
.但更好的办法是完全摆脱组件绑定到 bean,并针对您认为以这种方式解决的问题进行调查/询问正确的方法。参见 'binding' 属性在 JSF 中是如何工作的?何时以及如何使用它?
1b.(默认)托管 Bean 名称是什么?
第二步是检查已注册的受管 Bean 名称。JSF 和 Spring 使用约定符合 JavaBeans 规范,而 CDI 根据 CDI impl/version 有例外。
-
一个
FooBean
支持豆类,如下所示,@Named public class FooBean {}
在所有 Bean 管理框架中,根据 JavaBeans 规范,默认的托管 Bean 名称为
#{fooBean}
。 -
一个
FOOBean
支持豆类,如下所示,@Named public class FOOBean {}
其非限定类名以至少两个大写字母开头,在JSF和Spring中将具有与非限定类名
#{FOOBean}
完全相同的默认托管Bean名,也符合JavaBeans的特定要求。在 CDI 中,2015 年 6 月之前发布的 Weld 版本也是如此,但在 2015 年 6 月之后发布的 Weld 版本 (2.2.14/2.3.0.B1/3.0.0.A9) 和 OpenWebBeans 中也是如此,因为 CDI 规范存在疏忽。在这些 Weld 版本和所有 OWB 版本中,它仅使用第一个字符小写#{fOOBean}
。 -
如果您显式指定了受管 Bean 名称
foo
如下所示,@Named("foo") public class FooBean {}
或等效于
<小时 />@ManagedBean(name="foo")
或@Component("foo")
,那么它只能通过#{foo}
使用,因此不能通过#{fooBean}
使用。
1c.背豆类在哪里?
第三步是仔细检查后备 Bean 类是否位于构建和部署的 WAR 文件中的正确位置。确保您已正确执行项目和服务器的完全清理、重新生成、重新部署和重新启动,以防您实际上忙于编写代码并在浏览器中不耐烦地按 F5。如果仍然徒劳无功,请让构建系统生成一个 WAR 文件,然后使用 ZIP 工具提取和检查该文件。后备 Bean 类的编译.class
文件必须驻留在其/WEB-INF/classes
的包结构中。或者,当它被打包为 JAR 模块的一部分时,包含已编译.class
文件的 JAR 必须驻留在/WEB-INF/lib
中,因此不能驻留在 EAR 的/lib
或其他地方。
如果您使用的是 Eclipse,请确保后备 Bean 类处于src
中,因此不会WebContent
,并确保启用了Project> Build Image。如果您使用的是 Maven,请确保支持Bean类在src/main/java
中,因此不在src/main/resources
或src/main/webapp
中。
如果要使用 EJB+WAR 将 Web 应用程序打包为 EAR 的一部分,那么您需要确保后备 Bean 类位于 WAR 模块中,因此不在 EAR 模块或 EJB 模块中。业务层 (EJB) 必须没有任何与 Web 层 (WAR) 相关的工件,以便业务层可以跨多个不同的 Web 层(JSF、JAX-RS、JSP/SERVLET 等)重用。
2.目标无法访问,"实体"返回空
值这归结为嵌套属性entity
如返回#{bean.entity.property}
null
。这通常仅在 JSF 需要通过如下所示的输入组件设置property
值时公开,而#{bean.entity}
实际返回null
。
<h:inputText value="#{bean.entity.property}" />
您需要确保事先在@PostConstruct
或<f:viewAction>
方法中准备模型实体,或者如果您在同一视图上使用 CRUD 列表和/或对话框,则可能是add()
操作方法。
@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
挂接受管 Bean 实例初始化(并使用@PreDestroy
挂接受管 Bean 实例销毁)。此外,在构造函数中,您还无法访问任何注入的依赖项,另请参阅在尝试访问构造函数中的 Bean 时@Inject NullPointerException。
如果entityId
是通过<f:viewParam>
提供的,则需要使用<f:viewAction>
而不是@PostConstruct
。参见 何时使用 f:viewAction/preRenderView 与 PostConstruct?
还需要确保在回发期间保留非null
模型,以防仅在add()
操作方法中创建它。最简单的方法是将 Bean 放在视图范围内。参见 如何选择合适的 Bean 范围?
3.目标无法访问,"空"返回空
这实际上与#2具有相同的原因,只有正在使用的(较旧的)EL实现在保留要在异常消息中显示的属性名称方面有些错误,最终错误地显示为"null"。这只会使调试和修复变得更加困难,当您有相当多的嵌套属性时,例如#{bean.entity.subentity.subsubentity.property}
.
解决方案仍然相同:确保在所有级别中都没有null
有问题的嵌套实体。
4.目标无法访问,"0"返回空
值这也与#2具有相同的原因,只有正在使用的(较旧的)EL实现在制定异常消息时存在错误。仅当您在 EL 中使用大括号表示法[]
时,这才会公开,例如在#{bean.collection[index]}
中,#{bean.collection}
本身为非 null,但指定索引处的项不存在。然后,必须将此类消息解释为:
目标无法访问,"集合[0]"返回空
值
解决方案也与#2相同:确保收集项可用。
5.目标无法访问,"括号后缀"返回空
值这实际上与#4的原因相同,只有正在使用的(较旧的)EL实现在保留迭代索引以显示在异常消息中时有些错误,最终错误地暴露为"Bracket后缀",这实际上是字符]
。这只会使集合中有多个项时的调试和修复变得更加困难。
其他可能的原因javax.el.PropertyNotFoundException
:
- javax.el.ELException:在 com.example.Bean 类型上读取"foo"时出错
- javax.el.ELException: 找不到属性操作方法 in class com.example.Bean
- javax.el.PropertyNotFoundException: 在 com.example.Bean 类型上找不到属性 'foo'
- 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}上
对于那些仍然卡住的人...
将 NetBeans 8.1 和 GlassFish 4.1 与 CDI 配合使用,出于某种原因,我仅在本地遇到此问题,而不是在远程服务器上。有什么诀窍:
->使用 javaee-web-api7.0 而不是 NetBeans 提供的默认 pom 版本,即 javaee-web-api 6.0,因此:
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
<type>jar</type>
</dependency>
->将此javaee-web-api-7.0.jar作为库上传到服务器上(domain1文件夹中的lib文件夹),然后重新启动服务器。
我决定在自己解决此错误后分享我对此错误的发现。
首先,应该认真对待BalusC解决方案,但是Netbeans中还有另一个可能的问题需要注意,尤其是在使用Maven构建企业应用程序项目(EAR)时。
Netbeans 生成一个父 POM 文件、一个EAR项目、一个EJB项目和一个WAR 项目。 我的项目中的其他一切都很好,我几乎认为问题可能是 GlassFish 4.0 中的一个错误(我必须安装并将其插入 Netbeans),因为 GlassFish 4.1 有一个 Weld CDI 错误,这使得嵌入的 Netbeans 8.0.2 中的 GlassFish 4.1 无法使用,除非通过补丁。
溶液:
要解决"目标无法访问,标识符'bean'解析为空">错误
-右键单击父 POM 项目,然后选择"属性"。出现一个项目属性对话框,单击"源",您会惊讶地看到">源/二进制格式"设置为1.5,">编码"设置为Windows 1250。 将">源/二进制格式"更改为 1.6 0r 1.7,无论您希望使项目符合 CDI 标准,请将">编码"更改为 UTF-8。
对所有其他子项目(EAR,EJB,WAR)执行相同的操作,如果它们尚未组合。 运行您的项目,您将不会再次收到该错误。
我希望这有助于有类似错误的人。
我决定分享我的解决方案,因为尽管这里提供的许多答案很有帮助,但我仍然有这个问题。就我而言,我正在为我的新项目使用 JSF 2.3、jdk10、jee8、cdi 2.0,我确实在 wildfly 12 上运行了我的应用程序,按照 wildfly 网站上的建议使用参数 standalone.sh -Dee8.preview.mode=true 启动服务器。下载野蝇 13 后,"bean 解析为空"的问题消失了。将完全相同的战争上传到野蝇 13 使一切顺利。
我卡在此错误上,因为在具有@SpringBootApplication
的类中,我忘记指定控制器的包名称。
这次我想更具体地指出Spring必须扫描哪些组件,而不是配置基本包。
是这样的:
@ComponentScan(basePackages = {"br.com.company.project.repository", "br.com.company.project.service"})
但正确的形式是其中之一:
@ComponentScan(basePackages = {"br.com.company.project.repository", "br.com.company.project.service", "br.com.company.project.controller"})
@ComponentScan(basePackages = {"br.com.company.project")
我决定分享我的解决方案,因为尽管正确答案非常全面,但它并没有涵盖这个(愚蠢的)错误:)
它也可能是Mojarra 2.3中的错误 https://github.com/eclipse-ee4j/mojarra/issues/4734
就我而言,我在@Named("beanName")中犯了一个拼写错误,它应该是"beanName",但我写了"beanNam",例如。
我正在使用 wildfly 10 作为 javaee 容器。我遇到了"目标无法访问,'实体'返回空"问题。感谢您的建议 BalusC 但解释了我的问题。 意外使用"import com.sun.istack.logging.Logger;"而不是"import org.jboss.logging.Logger;"导致CDI实现了JSF EL。 希望它有助于改善解决方案。
我遇到了同样的问题。事实证明,解决方案要简单得多。看起来数据表想要getter形式的方法,即getSomeMethod(),而不仅仅是someMethod()。在我的数据表中,我调用了findResults。我将支持bean中的方法更改为getFindResults(),它起作用了。
命令按钮在没有获取的情况下工作,这只会使其更加混乱。
至于#2,就我而言,它在替换后神奇地复活了
<body>
标记
<h:body>
在完成了几个(说实话更简单的)JSF项目之后,我不记得现在做了任何不同的设置,而且我第一次遇到这种错误。我正在制作一个非常基本的登录页面(用户名,密码,用户Bean...)并像往常一样设置所有内容。我发现的唯一区别是上述标签。也许有人觉得这很有用。
在我的情况下,问题是我包含一个接受参数的构造函数,但没有一个带有注入注释的空构造函数,就像这样。
@Inject public VisitorBean() {}
我刚刚在没有任何构造函数的情况下对其进行了测试,这似乎也可以工作。
对于 1. 主题(目标无法访问,标识符"bean"解析为空);
我检查了@BalusC和其他共享者的宝贵答案,但我在我的场景中超越了这个问题。 在创建一个具有不同名称的新 xhtml 并创建具有不同名称的 bean 类之后,我逐步编写(而不是复制粘贴)代码到新的 bean 类和新的 xhtml 文件中。
当我从 web.xml 文件中删除 AnnotationConfigWebApplicationContext 上下文参数时 这是工作
如果你有像参数,如下所示,你必须从web.xml文件中删除它
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
首先,我使用:Eclipse,Weblogic,CDI,JSF,PrimeFaces。如果你也是,也许我的解决方案可以帮助你。
就我而言,错误的原因是"Eclipse"上的一个小设置。
检查这个:
- 右键单击"服务器"选项卡上的Weblogic服务器
- 选择"属性">
- 在属性的新小窗口中,展开"Weblogic"菜单
- 在"Weblogic"菜单中,点击"发布"选项
- 现在,在右侧,确保选中"发布为松散存档"选项。
就我而言,我选中了"发布为虚拟应用程序",因此,更改它我解决了"目标无法访问"错误。
在旧样式中使用 JSF 您必须在beans-config.xml文件(位于 WEB-INF 文件夹中)并在web.xml文件中引用它,如下所示:
豆子配置.xml
<managed-bean>
<managed-bean-name>"the name by wich your backing bean will be referenced"</managed-bean-name>
<managed-bean-class>"your backing bean fully qualified class name"</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
(我尝试使用其他范围,但是...
网络.xml
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>"/WEB-INF/beans-config.xml</param-value>
</context-param>
另一个线索: 我正在使用 JSF,并添加了 mvn 依赖项: 康日报面孔 JSF-API 2.2.11
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.11</version>
</dependency>
然后,我尝试更改为Primefaces,并添加primefaces依赖项:
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>6.0</version>
</dependency>
我将 xhtml 从 h: 更改为 p:,将 xmlns:p="http://primefaces.org/ui 添加到模板中。 只有使用 JSF,项目运行正常,并且托管Bean运行正常。当我添加Primefaces时,我得到了无法访问的对象(javax.el.propertynotfoundexception)。问题是JSF正在生成ManagedBean,而不是Primefaces,我正在为对象询问primefaces。我不得不从我的 .pom 中删除 jsf-impl,清理并安装程序。 从这一点开始,一切都很顺利。 希望有帮助。
EL 按照所述解释 ${bean.propretyName} - 属性名称变为 getPropertyName() 假设您使用显式或隐式方法来生成 getter/setters
您可以通过将名称显式标识为函数来覆盖此行为:${bean.methodName()} 这将直接调用函数方法 Name(),而无需修改。
您的访问器并不总是被命名为"get..."。
在我的情况下,"el-ri-1.0.jar"丢失了。