识别和解决 javax.el.PropertyNotFoundException: 目标无法到达

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

似乎有五种不同的信息:

  1. 目标不可达,标识符“ bean”解析为空
  2. 目标不可达,“实体”返回空
  3. 目标无法到达,‘ null’返回 null
  4. 目标无法到达,“0”返回空
  5. 目标无法到达,‘ BracketAffix’返回空

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

142048 次浏览

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

这可以归结为托管 bean 实例本身不能像 #{bean}那样由 EL 中的标识符(托管 bean 名称)精确地找到。

查明原因可分为三个步骤:

谁负责管理这个豆子?
(默认)托管 bean 名称是什么?
后台 bean 类在哪里?

谁负责管理这个豆子?

第一步是检查哪个 bean 管理框架负责管理 bean 实例。是通过 @NamedCDI吗?还是 JSF通过 @ManagedBean?或者是通过 @ManagedBean1的 @ManagedBean0?您能确保不会在同一个支持 bean 类上混合使用多个 bean 管理框架特定的注释吗?例如 @Named @ManagedBean@Named @Component@ManagedBean @Component。这是不对的。Bean 最多只能由一个 bean 管理框架管理,并且该框架必须得到正确的配置。如果你已经不知道选择哪一个,头部的 @ManagedBean2和 @ManagedBean3

如果是 CDI通过 @Named管理 bean,那么您需要确保以下几点:

  • 为了在 WAR 中启用 CDI,CDI 1.0(Java EE 6)需要一个 /WEB-INF/beans.xml文件。它可以是 空荡荡的,也可以只包含以下内容:

      <?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.0的 beans.xml,其行为将与 CDI 1.0相同。如果有一个兼容 CDI 1.1的 beans.xml和一个显式的 version="1.1",那么默认情况下它将只注册 @Named bean beans.xml3一个显式的 CDI 范围注释,如 beans.xml4、 beans.xml5、 beans.xml6、 beans.xml7等。如果您打算将所有 bean 注册为 CDI 托管 bean,即使是那些没有显式 CDI 作用域的 bean,也可以使用以下兼容 beans.xml1集的 CDI 1.1兼容 beans.xml0(默认值是 beans.xml2)。

      <?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>
    
  • bean-discovery-mode="annotated"中使用 CDI 1.1 + 时(默认情况下) ,请确保没有意外地导入诸如 javax.faces.bean.RequestScoped之类的 JSF 作用域而不是 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容器上使用 JSF 2.3并声明遵循 Servlet 4.0的 web.xml时,您需要将 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?

  • 您的运行时类路径是干净的,没有 CDIAPI 相关 JAR 中的重复。确保您没有混合使用多个 CDI 实现(Weld、 OpenWebBeans 等)。确保当目标容器已经打包出 CDI API 时,不会沿着 webapp 提供另一个 CDI 甚至 JavaEEAPI 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中的 JSF 1.x 样式 <managed-bean>条目覆盖同一个后台 bean 类以及不同的托管 bean 名称。这个优先于 @ManagedBean。在 faces-config.xml中注册一个托管 bean 是没有必要的,因为 JSF 2.0已经把它删除了。

  • 您的运行时类路径是干净的,没有 JSFAPI 相关 JAR 中的重复。确保您没有混合使用多个 JSF 实现(Mojarra 和 MyFaces)。确保当目标容器已经打包好 JSF API 时,不要在 webapp 中提供另一个 JSF 甚至 JavaEEAPI JAR 文件。有关 JSF 安装说明,请参阅 JSF wiki 页面的“安装 JSF”部分。如果您打算从 WAR 中升级容器绑定的 JSF,而不是在容器本身中,请确保您已经指示目标容器使用 WAR 绑定的 JSF API/impl。

  • 如果您在 JAR 中打包 JSF 托管 bean,那么请确保 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注释就不会混淆地成功编译)。


如果是 春天通过 @Component管理 bean,那么您需要确保以下几点:

  • 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属性(例如 <h:dataTable var="item"><ui:repeat var="item"><p:tabView var="item">等)来管理(嵌套的) bean,并且你实际上得到了一个“ Target Unreaced,标识符‘ item’解析为 null”,那么你需要确认以下几点:

  • 在任何子组件的 binding属性中都不引用 #{item}。这是不正确的,因为 binding属性在视图构建时运行,而不是在视图呈现时运行。此外,组件树中物理上只有一个组件,在每个迭代周期中可以简单地重用它。换句话说,您实际上应该使用 binding="#{bean.component}"而不是 binding="#{item.component}"。但更好的做法是完全去掉组件二进制代码并研究/询问您认为可以用这种方法解决的问题的适当方法。另请参见: “在 JSF 中绑定属性是如何工作的?”?何时及如何使用?


1b. (默认)托管 bean 名称是什么?

第二步是检查已注册的托管 bean 名称。JSF 和 Spring 的使用约定符合 JavaBeans 规范,而 CDI 有例外,这取决于 CDI impl/version。

  • 像下面这样的 FooBean后台 bean 类,

      @Named
    public class FooBean {}
    

    将在所有 bean 管理框架中按照 JavaBeans 规范具有默认的管理 bean 名称 #{fooBean}

  • 像下面这样的 FOOBean后台 bean 类,

      @Named
    public class FOOBean {}
    

    其不限定类名以至少两个大写字母开头的将在 JSF 和 Spring 中有一个默认的托管 bean 名称,正好是不限定类名 #{FOOBean},也符合 JavaBeans 规范。在 CDI 中,2015年6月之前发布的 Weld 版本也是如此,但是在2015年6月之后发布的 Weld 版本(2.2.14/2.3.0)则不是这样。B1/3.0.A9)或由于 CDI 规范中的疏忽而在 OpenWebBeans 中。在这些焊接版本和所有 OWB 版本中,它只是与第一个字符小写 #{fOOBean}

  • 如果像下面这样显式地指定了托管 bean 名称 foo,

      @Named("foo")
    public class FooBean {}
    

    或者等效于 @ManagedBean(name="foo")或者 @Component("foo"),那么它只能通过 #{foo}获得,因此 没有通过 #{fooBean}获得。


后台 bean 类在哪里?

第三步是双重检查支持 bean 类是否位于构建和部署的 WAR 文件中的正确位置。确保您已经正确地执行了项目和服务器的完全清理、重新构建、重新部署和重新启动,以防您实际上正忙于编写代码并不耐烦地在浏览器中按 F5键。如果仍然徒劳,那么让构建系统生成一个 WAR 文件,然后使用 ZIP 工具提取和检查该文件。后台 bean 类的编译后的 .class文件必须驻留在它在 /WEB-INF/classes中的包结构中。或者,当它被打包为 JAR 模块的一部分时,包含已编译的 .class文件的 JAR 必须驻留在 /WEB-INF/lib中,因此不能像 EAR 的 /lib或其他地方那样。

如果您正在使用 Eclipse,请确保后台 bean 类位于 src中,因此位于 没有WebContent中,并确保启用了 项目 > 自动生成。如果您正在使用 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 实例销毁)。此外,在构造函数中,您还不能访问任何注入的依赖项,请参见 在构造函数中访问@Injectbean 时发生 NullPointerException

如果 entityId是通过 <f:viewParam>提供的,那么您需要使用 <f:viewAction>而不是 @PostConstruct

您还需要确保在回发期间保留非 null模型,以防只在 add()操作方法中创建它。最简单的方法是将 bean 放在视图作用域中。参见 如何选择正确的 bean 范围?


3. 目标无法到达,‘ null’返回 null

这实际上与 # 2的原因相同,只是使用的(较老的) EL 实现在保留属性名以显示在异常消息中时有一些错误,最终错误地暴露为“ null”。这只会让调试和修复变得更加困难,因为您已经有了很多嵌套属性,比如 #{bean.entity.subentity.subsubentity.property}

解决方案仍然是相同的: 确保所讨论的嵌套实体在所有级别上都不是 null


4. 目标无法到达,“0”返回空

这也与 # 2有相同的原因,只是使用的(旧的) EL 实现在制定异常消息时有错误。只有当您在 EL 中使用大括号 []时,才会暴露出来,就像在 #{bean.collection[index]}中一样,其中 #{bean.collection}本身是非空的,但是指定索引处的项不存在。这种信息必须解释为:

目标无法到达,‘ Collection [0]’返回空

解决方案也与 # 2相同: 确保集合项可用。


5. 无法到达目标,‘ BracketAffix’返回空

这实际上与 # 4的原因相同,只是使用的(较老的) EL 实现在保留异常消息中显示的迭代索引方面有些错误,最终错误地暴露为‘ BracketAffix’,这实际上是字符 ]。当集合中有多个项时,这只会增加调试和修复的难度。


javax.el.PropertyNotFoundException的其他可能原因:

对于那些仍然被困在..。

使用带 CDI 的 NetBeans 8.1和 GlassFish 4.1,由于某种原因,我只在本地有这个问题,而不是在远程服务器上。是什么起了作用:

- > 使用 javaee-web-api 7.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 作为一个 lib 文件上传到服务器(domain1文件夹中的 lib 文件夹)并重新启动服务器。

使用旧样式的 JSF,您必须在 Bean-config.xml 文件(位于 WEB-INF 文件夹中) ,并在 Xml文件中引用它,这样做:

Beans-config. 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 依赖项: Com.sun.faces 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.Propertynotfound 异常)。问题在于 JSF 生成的是 ManagedBean,而不是 Primefaces,我要求 Primefaces 生成对象。我不得不从我的。清洁并安装项目。 从现在开始一切都很顺利。 希望能帮上忙。

在我的例子中,我在@Named (“ beanName”)中犯了一个拼写错误,它应该是“ beanName”,但是我写了“ beanNam”,例如。

我使用野蝇10为 javaee 容器。我经历过“目标无法到达,‘实体’返回空”的问题。谢谢 BalusC 的建议,但我的问题出解决方案解释。 意外地使用“ import com.sun.istack.logg.Logger;”而不是“ import org.jboss.logg.Logger;”导致 CDI 实现了 JSF EL。 希望对改进解决方案有所帮助。

我也有同样的问题。结果证明,解决方案要简单得多。似乎数据表希望方法采用 getter 的形式,即 getSome 方法() ,而不仅仅是 some 方法()。在数据表中,我调用 findResults。我将后台 bean 中的方法更改为 getFindResults () ,它工作正常。

命令 Button 使用 find 而不使用 get,这只会使它更加混乱。

在我自己解决了这个错误之后,我决定与大家分享我的发现。

首先,应该认真对待 BalusC 解决方案,但是在 Netbeans 还有另一个可能的问题需要注意,尤其是在使用 Maven 构建 企业应用项目(EAR)时。

Netbeans 生成一个 父 POM 档案、一个 EAR 项目、一个 EJB 项目和一个 战争计划。 我的项目中其他的一切都很好,我几乎认为问题可能是 GlassFish 4.0(我必须安装并插入 Netbeans)中的一个 bug,因为 GlassFish 4.1有一个 Weld CDI bug,这使得在 Netbeans 8.0.2中嵌入的 GlassFish 4.1除了通过一个补丁之外不能使用。

解决方案:

要解析 < strong > “ Target Unreaced,标识符‘ bean’解析为 null” 错误-

右键单击父 POM 项目,并选择 物业。一个项目属性对话框出现,点击“来源”,你会惊讶地看到“ 源/二进制格式”设置为1.5,“ 编码中”设置为 Windows 1250。 将“ 源/二进制格式”更改为1.60r 1.7,以符合项目 CDI 的要求为准,将“ 编码中”更改为 UTF-8。

如果其他子项目(EAR、 EJB、 WAR)尚不可兼容,则对它们执行相同的操作。 运行您的项目,就不会再次出现该错误。

我希望这对有类似错误的人有所帮助。

我决定分享我的解决方案,因为尽管这里提供的许多答案是有帮助的,我仍然有这个问题。在我的例子中,我使用 JSF 2.3,jdk10,jee8,cdi 2.0作为我的新项目,并且我确实在 Wildfly 12上运行了我的应用程序,按照 Wildfly 网站上推荐的那样,使用参数 stanalone.sh-Dee8.preview.mode = true 启动服务器。在下载 Wildfly 13之后,“ bean 已解决为 null”的问题消失了。把完全一样的战争上传到野蝇13号就成功了。

EL 解释 ${ bean.propretyName }如上所述-在假设您使用显式或隐式方法生成 getter/setter 的情况下,properties 名称变成 getPropertyName ()

可以通过显式地将名称标识为函数来覆盖此行为: ${ bean.methodName ()}这将直接调用函数方法 Name () ,而不需要修改。

你的访问者并不总是被命名为“ get...”。

至于第二点,在我的例子中,它在更换之后神奇地活了过来

<body>

与。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

<h:body>

在完成了几个(老实说,更简单) JSF 项目之后,我不记得现在做过任何不同的设置,而且我第一次遇到了这种错误。我制作了一个非常基本的登录页面(用户名、密码、用户 Bean... ...) ,像往常一样设置所有东西。我发现的唯一区别是前面提到的标签。也许有人觉得这个有用。

在我的例子中,问题在于我包含了一个带有参数的构造函数,但是没有包含带有 Inject 注释的空构造函数,就像这样。

@Inject public VisitorBean() {}

我只是测试了它没有任何构造函数,这似乎也工作。

主题(目标不可达,标识符“ bean”解析为空) ;

我检查了@BalusC 和其他分享者的有价值的答案,但是我在我的场景中超过了这个问题。 在创建一个新的具有不同名称的 xhtml 并创建具有不同名称的 bean 类之后,我将代码一步一步地编写(而不是复制粘贴)到新的 bean 类和新的 xhtml 文件中。

我在这个错误上卡住了,因为在具有 @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")

我决定分享我的解决方案,因为尽管正确的答案非常全面,但它并没有涵盖这个(愚蠢的)错误:)

当我从 web.xml 文件中删除 AnnotationConfigWebApplicationContext 上下文参数时,这是工作

如果您得到了如下所示的类似 param,则必须从 web.xml 文件中删除它

<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>

在我的情况下“ el-ri-1.0.jar”不见了。

它也可能是 Mojarra 2.3 abc0中的一个 bug

首先,我使用的是: Eclipse、 Weblogic、 CDI、 JSF、 PrimeFaces。

在我的例子中,错误的原因是在“ Eclipse”上的一个小设置。

看看这个:

  1. 在“ Servers”选项卡上右键单击 Weblogic 服务器
  2. 选择「属性」
  3. 在 Properties 的新窗口中,展开“ Weblogic”菜单
  4. 在“ Weblogic”菜单中,点击“ Publishing”选项
  5. 现在,在右侧,确保选中了“作为爆炸存档发布”选项。

在我的例子中,我选中了“作为虚拟应用程序发布”,因此,更改后我解决了“ TargetUnreaced”错误。