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

问题描述 投票:110回答:13

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

似乎有五种不同的消息:

  1. Target Unreachable, identifier 'bean' resolved to null
  2. Target Unreachable, 'entity' returned null
  3. Target Unreachable, 'null' returned null
  4. Target Unreachable, ''0'' returned null
  5. Target Unreachable, 'BracketSuffix' returned null

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

jsf cdi el managed-bean propertynotfoundexception
13个回答
217
投票

1. Target Unreachable, identifier 'bean' resolved to null

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

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

一个。谁在管理豆子? 湾什么是(默认)托管bean名称? C。支持bean类在哪里?

1a. Who's managing the bean?

第一步是检查哪个bean管理框架负责管理bean实例。它是通过@ManagedBean的JSF吗?或者是通过@Named的CDI?或者是通过@Component春天?您能否确保在同一个支持bean类中没有混合多个bean管理框架特定的注释?例如。 @Named @Component,或@Named @ManagedBean,或@ManagedBean @Component。这是错的。 bean必须由最多一个bean管理框架管理,并且必须正确配置该框架。如果您已经不知道该选择哪个,请前往Backing beans (@ManagedBean) or CDI Beans (@Named)?Spring JSF integration: how to inject a Spring component/service in JSF managed bean?

如果是JSF谁通过@ManagedBean管理bean,那么你需要确保以下内容:

  • 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会自动提取错误的列表作为列表中的第一项。
  • 您没有在@ManagedBean中使用JSF 1.x样式<managed-bean>条目在同一个支持bean类上覆盖faces-config.xml以及不同的托管bean名称。这个优先于@ManagedBean。在faces-config.xml中注册托管bean不是必需的,因为JSF 2.0只是将其删除。
  • 您的运行时类路径是干净的,并且与JSF API相关的JAR中没有重复项。确保您没有混合多个JSF实现(Mojarra和MyFaces)。当目标容器已经将JSF API捆绑在一起时,请确保您不沿webapp提供另一个JSF甚至Java EE API JAR文件。有关JSF安装说明,另请参阅"Installing JSF" section of our JSF wiki page。如果您打算从WAR而不是容器本身升级容器捆绑的JSF,请确保您已指示目标容器使用WAR捆绑的JSF API / impl。
  • 如果您在JAR中打包JSF托管bean,那么请确保JAR至少具有JSF 2.0兼容的/META-INF/faces-config.xml。另见How to reference JSF managed beans which are provided in a JAR file?
  • 如果您实际使用的是侏罗纪JSF 1.x,并且无法升级,那么您需要通过<managed-bean>中的faces-config.xml而不是@ManagedBean来注册bean。不要忘记修复项目构建路径,使得您不再拥有JSF 2.x库(因此@ManagedBean注释不会混淆地成功编译)。

如果它是通过@Named管理bean的CDI,那么你需要确保以下内容:

  • 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>
  • 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"时,它默认只注册带有明确CDI范围注释的@Named 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>
  • 当使用带有bean-discovery-mode="annotated"的CDI 1.1+(默认)时,请确保您不会意外地导入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"(默认)时,由于bug,您需要将Mojarra升级到2.3.3或更高版本。如果你无法升级,那么你需要在bean-discovery-mode="all"中设置beans.xml,或者将JSF 2.3特定的@FacesConfig注释放在WAR中的任意类(通常是某种应用程序范围的启动类)上。
  • 像Tomcat和Jetty这样的非Java EE容器不附带CDI。您需要手动安装它。这比仅添加库JAR要多一些工作。对于Tomcat,请确保按照此答案中的说明操作:How to install and use CDI on Tomcat?
  • 您的运行时类路径是干净的,并且与CDI API相关的JAR中没有重复项。确保您没有混合多个CDI实现(Weld,OpenWebBeans等)。当目标容器已经将CDI API捆绑在一起时,请确保您不沿webapp提供另一个CDI甚至Java EE API JAR文件。
  • 如果您在JAR中为JSF视图打包CDI托管bean,请确保JAR至少具有有效的/META-INF/beans.xml(可以保留为空)。

如果是Spring通过@Component管理bean,那么你需要确保以下内容:

  • 根据its documentation正在安装和集成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,并且你实际上得到了“目标无法访问,标识符'项'解析为null',那么你需要制作确定以下内容:

  • #{item}未在任何儿童成分的binding属性中引用。这是不正确的,因为binding属性在视图构建时运行,而不是在视图渲染时。而且,在组件树中物理上只有一个组件,它在每次迭代循环中都被简单地重用。换句话说,你应该使用binding="#{bean.component}"而不是binding="#{item.component}"。但更好的方法是完全摆脱对bean的组件限制,并调查/询问您认为以这种方式解决的问题的正确方法。另见How does the 'binding' attribute work in JSF? When and how should it be used?

1b. What's the (default) managed bean name?

第二步是检查已注册的托管bean名称。 JSF和Spring使用约定符合JavaBeans specification,而CDI具有异常,具体取决于CDI impl / version。

  • 像下面的FooBean支持bean类, @Named public class FooBean {} 根据JavaBeans规范,所有bean管理框架中的默认托管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.0.A9)以及an oversight in CDI spec发布的OpenWebBeans中都没有。在那些焊接版本和所有OWB版本中,它只有第一个字符小写的#{fOOBean}
  • 如果您已明确指定了托管bean名称foo,如下所示, @Named("foo") public class FooBean {} 或者与@ManagedBean(name="foo")@Component("foo")等效,那么它只能由#{foo}提供,因此不能由#{fooBean}提供。

1c. Where's the backing bean class?

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

如果您正在使用Eclipse,请确保支持bean类位于src中,因此不是WebContent,并确保启用了Project> Build Automatically。如果你正在使用Maven,请确保支持bean类在src/main/java中,因此不在src/main/resourcessrc/main/webapp中。

如果您将Web应用程序打包为带有EJB + WAR的EAR的一部分,那么您需要确保支持bean类在WAR模块中,因此不在EAR模块或EJB模块中。业务层(EJB)必须没有任何与Web层(WAR)相关的工件,因此业务层可以跨多个不同的Web层(JSF,JAX-RS,JSP / Servlet等)重用。


2. Target Unreachable, 'entity' returned null

这归结为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的重要性;如果您正在使用使用proxies的bean管理框架(例如CDI),那么在常规构造函数中执行此操作将会失败。始终使用@PostConstruct挂钩托管bean实例初始化(并使用@PreDestroy挂钩托管bean实例销毁)。此外,在构造函数中,您还无法访问任何注入的依赖项,另请参阅NullPointerException while trying to access @Inject bean in constructor

如果entityId是通过<f:viewParam>提供的,你需要使用<f:viewAction>而不是@PostConstruct。另见When to use f:viewAction / preRenderView versus PostConstruct?

你还需要确保在回发期间保留非null模型,以防你只在add()动作方法中创建它。最简单的方法是将bean放在视图范围内。另见How to choose the right bean scope?


3. Target Unreachable, 'null' returned null

这与#2实际上是相同的原因,只有正在使用的(较旧的)EL实现在保留要在异常消息中显示的属性名称时有些错误,最终错误地暴露为“null”。当你有一些像#{bean.entity.subentity.subsubentity.property}这样的嵌套属性时,这只会使调试和修复变得更难。

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


4. Target Unreachable, ''0'' returned null

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

目标无法访问,'collection [0]'返回null

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


5. Target Unreachable, 'BracketSuffix' returned null

这与#4实际上是相同的原因,只有正在使用的(较旧的)EL实现在保留迭代索引以显示在异常消息中有些错误,最终错误地暴露为'BracketSuffix',这实际上是字符]。当您在集合中有多个项目时,这只会使调试和修复变得更加困难。


Other possible causes of javax.el.PropertyNotFoundException:


0
投票

对于1.主题(目标无法访问,标识符'bean'已解析为null);

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


-1
投票

使用旧样式使用JSF您必须在beans-config.xml文件(位于WEB-INF文件夹中)中定义托管bean,并在web.xml文件中对其进行引用,这样:

豆类-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>

(我尝试过使用其他示波器,但......)

网嗯

<context-param>
  <param-name>javax.faces.CONFIG_FILES</param-name>
  <param-value>"/WEB-INF/beans-config.xml</param-value>
</context-param>

-1
投票

另一个线索:我使用的是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,proyect运行正常,并且使managedbean达到了正确。当我添加Primefaces时我得到了无法访问的对象(javax.el.propertynotfoundexception)。问题是JSF正在生成ManagedBean,而不是Primefaces,我正在询问对象的primefaces。我不得不从我的.pom中删除jsf-impl,清理和安装proyect。从这一点开始一切顺利。希望有所帮助。


-2
投票

EL如前所述解释$ {bean.propretyName} - 假设您使用生成getter / setter的显式或隐式方法,propertyName变为getPropertyName()

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

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


6
投票

对于那些仍然被卡住的人......

将NetBeans 8.1和GlassFish 4.1与CDI一起使用,出于某种原因我只在本地使用此问题,而不是在远程服务器上。诀窍是什么:

- >使用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文件夹)并重新启动服务器。


2
投票

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

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

Netbeans生成,父POM文件,EAR项目,EJB项目和WAR项目。我项目中的其他所有内容都很好,我几乎认为问题是GlassFish 4.0中的一个错误(我必须安装并将其插入Netbeans),因为GlassFish 4.1有一个Weld CDI错误,它在Netbeans 8.0中嵌入了GlassFish 4.1。除了通过补丁,2无法使用。

解:

要解决“目标无法访问,标识符'bean'已解析为null”错误 -

我右键单击父POM项目,然后选择“属性”。出现“项目属性”对话框,单击“源”,您会惊讶地看到“源/二进制格式”设置为1.5并且“编码”设置为Windows 1250.将“源/二进制格式”更改为1.6 0r 1.7,以较小者为准您希望使您的项目符合CDI标准,并将“编码”设置为UTF-8。

对所有其他子项目(EAR,EJB,WAR)执行相同操作(如果它们尚不可分隔)。运行您的项目,您将不会再次收到该错误。

我希望这可以帮助那些有类似错误的人。


1
投票

我决定分享我的解决方案,因为虽然这里提供的许多答案都很有用,但我仍然遇到了这个问题。在我的情况下,我使用JSF 2.3,jdk10,jee8,cdi 2.0作为我的新项目,我确实在wildfly 12上运行我的应用程序,启动服务器参数standalone.sh -Dee8.preview.mode = true,如wildfly网站上的建议。下载wildfly后,“bean解析为null”的问题就消失了。将完全相同的战争上传到wildfly 13后,一切正常。


0
投票

在我的情况下,我在@Named(“beanName”)中犯了一个拼写错误,它被认为是“beanName”,但我写了“beanNam”,例如。


0
投票

我使用wildfly 10作为javaee容器。我曾经历过“Target Unreachable,'entity'返回null”问题。感谢BalusC的建议,但我解决了解决方案的问题。无意中使用“import com.sun.istack.logging.Logger;”而不是“import org.jboss.logging.Logger;”导致CDI实施JSF EL。希望它有助于改善解决方案。


0
投票

我有同样的问题。结果证明解决方案要简单得多。似乎数据表需要getter形式的方法,即getSomeMethod(),而不仅仅是someMethod()。在我的数据表中,我调用了findResults。我将我的支持bean中的方法更改为getFindResults()并且它工作正常。

一个commandButton工作找不到get,这使得它更加令人困惑。


0
投票

至于#2,在我的情况下,它取代后神奇地变为现实

<body>

标记

<h:body>

在完成了几个(更简单,更诚实的)JSF项目之后,我不记得现在做了什么不同的设置,我第一次遇到了这种错误。我正在创建一个非常基本的登录页面(用户名,密码,用户Bean ...)并像往常一样设置所有内容。我发现的唯一区别是前面提到的标签。也许有人觉得这很有用。


0
投票

我的问题是我包含了一个构造函数,它接受参数但不包含带有Inject注释的空构造函数,就像这样。

@Inject public VisitorBean() {}

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

© www.soinside.com 2019 - 2024. All rights reserved.