识别和解决 javax.el.PropertyNotFoundException: Target Unreachable



当尝试像这样#{bean.entity.property}在EL中引用托管Bean时,有时会抛出javax.el.PropertyNotFoundException: Target Unreachable异常,通常是在设置bean属性或调用bean操作时。

似乎有五种不同类型的消息:

  1. 目标无法访问,标识符"bean"解析为空
  2. 目标无法访问,"实体"返回空
  3. 目标无法访问,"空"返回空
  4. 目标无法访问,"0"返回空
  5. 目标无法访问,"括号后缀"返回空

它们都意味着什么?它们是如何引起的,应该如何解决?

1. 目标不可达,标识符"bean"解析为空

这归结为,像#{bean}一样,无法通过 EL 中的确切标识符(托管 Bean 名称)找到托管 Bean 实例本身。

确定原因可以分为三个步骤:

一个。谁在管理豆子?
b。(默认的)托管 Bean 名称是什么?
c。背豆类在哪里?

1a.谁在管理豆子?

第一步是检查哪个 Bean 管理框架负责管理 Bean 实例。是通过@NamedCDI吗?还是通过@ManagedBeanJSF?还是通过@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.xmlbean-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.0web.xml容器上使用 JSF 2.3 时,您需要将特定于 JSF 2.3 的@FacesConfig注释显式放在 WAR 中的任意类(通常是某种应用程序范围的启动类)上。这在 Servlet 3.x 中不是必需的。

  • 使用 CDI 3.0 时,包的第一个版本从javax.*重命名为jakarta.*,则需要确保所有部署描述符文件beans.xmlweb.xmlfaces-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_02.0分别替换为2_12.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_22.2分别替换为2_32.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/resourcessrc/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"上的一个小设置。

检查这个:

  1. 右键单击"服务器"选项卡上的Weblogic服务器
  2. 选择"属性">
  3. 在属性的新小窗口中,展开"Weblogic"菜单
  4. 在"Weblogic"菜单中,点击"发布"选项
  5. 现在,在右侧,确保选中"发布为松散存档"选项。

就我而言,我选中了"发布为虚拟应用程序",因此,更改它我解决了"目标无法访问"错误。

在旧样式中使用 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"丢失了。

相关内容

  • 没有找到相关文章

最新更新