识别并解决javax.el.PropertyNotFoundException:目标无法访问

当试图在EL中引用一个托pipebean,就像#{bean.entity.property} ,有时候会抛出一个javax.el.PropertyNotFoundException: Target Unreachableexception,通常在设置bean属性时,或者当一个bean动作被调用。

似乎有五种不同的信息:

  1. 目标无法访问,标识符“bean”parsing为null
  2. 目标不可到达,“实体”返回null
  3. Target Unreachable,'null'返回null
  4. 目标无法访问,“0”返回null
  5. Target Unreachable,'BracketSuffix'返回null

他们都是什么意思? 他们是如何造成的,应该如何解决?

1. Target Unreachable,标识符“bean”parsing为null

这可以归结为托pipebean实例本身不能被EL中的标识符(托pipebean名称)所识别,就像#{bean}

确定原因可以分三步进行:

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

1A。 谁在pipe理这个bean?

第一步是检查哪个beanpipe理框架负责pipe理bean实例。 是通过@ManagedBean JSF吗? 或者它是通过@Named CDI ? 或者它是通过@Component spring ? 你能确定你没有在同一个支持bean类上混合多个beanpipe理框架特定的注释吗? 例如, @Named @Component@Named @ManagedBean@ManagedBean @Component 。 这是错误的。 该bean必须至多由一个beanpipe理框架来pipe理,并且该框架必须被正确configuration。 如果你已经不知道该select哪一个,那么可以前往Backing beans(@ManagedBean)或者CDI Beans(@Named)? 和Spring JSF集成:如何在JSF托pipebean中注入Spring组件/服务?

如果是通过@ManagedBeanpipe理bean的JSF ,则需要确保以下内容:

  • faces-config.xml根声明与JSF 2.0兼容。 所以XSD文件和version必须至less指定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.2,当然可以这样指定。

     <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"> 
  • 您没有意外导入javax.annotation.ManagedBean而不是javax.faces.bean.ManagedBean 。 小心使用IDE自动完成function,Eclipse会自动提示错误的列表中的第一项。
  • 您没有在同一个支持bean类的faces-config.xml的JSF 1.x风格的<managed-bean>条目中覆盖@ManagedBean ,以及不同的托pipebean名称。 这个将优先于@ManagedBean 。 在faces-config.xml注册一个托pipebean是没有必要的,因为JSF 2.0只是删除它。
  • 您的运行时类path干净且没有JSF API相关JAR中的重复项。 确保你没有混合多个JSF实现(Mojarra和MyFaces)。 确保当目标容器已经将JSF API包装在外时,不会在webapp上提供另一个JSF甚至Java EE API JAR文件。 另请参阅JSF wiki页面中的“安装JSF”部分,了解JSF安装说明。 如果您打算将容器绑定的JSF从WAR中升级到容器本身,请确保您已经指示目标容器使用WAR绑定的JSF API / impl。
  • 如果要将JSF托pipe的bean打包到JAR中,请确保JAR至less具有一个兼容JSF 2.0的/META-INF/faces-config.xml 。 另请参见如何引用JAR文件中提供的JSF受pipeBean?
  • 如果您实际使用的是jurassic JSF 1.x,并且无法升级,则需要通过faces-config.xml而不是@ManagedBean通过<managed-bean>注册bean。 不要忘记修复你的项目构buildpath,以免你再没有JSF 2.x库(这样@ManagedBean注解不会混淆成功编译)。


如果是通过@Namedpipe理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相同。 当有一个明确的version="1.1"的CDI 1.1兼容的beans.xml时,默认情况下,它只会注册@Named bean, 并且有一个明确的CDI范围注释,比如@SessionScoped @ViewScoped@SessionScoped @ViewScoped@SessionScoped@SessionScoped @ViewScoped等等。如果你打算将所有bean注册为CDIpipe理的bean,即使没有明确的CDI范围,也可以使用下面的CDI 1.1兼容的/WEB-INF/beans.xmlbean-discovery-mode="all" set(默认是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自动完成。

  • 当使用带有bean-discovery-mode="annotated" (缺省)的Mojarra 2.3.0-2.3.2和CDI 1.1+时,由于缺陷 ,您需要将Mojarra升级到2.3.3或更高版本。 如果你不能升级,那么你需要在beans.xml设置bean-discovery-mode="all" ,或者把JSF 2.3特定的@FacesConfig注解放在WAR中的一个任意类上(通常是某种一个应用程序范围的启动类)。
  • Tomcat和Jetty之类的非Java EE容器没有捆绑CDI。 您需要手动安装它。 这比添加库JAR(s)要多一点工作。 对于Tomcat,请确保您按照此答案中的说明操作: 如何在Tomcat上安装和使用CDI?
  • 您的运行时类path干净且没有CDI API相关JAR中的重复项。 确保你没有混合多个CDI实现(Weld,OpenWebBeans等)。 确保当目标容器已经将CDI API打包出来时,不会在webapp上提供另一个CDI甚至Java EE API JAR文件。
  • 如果在JAR中为JSF视图打包CDI托pipebean,请确保JAR至less有一个有效的/META-INF/beans.xml (可以保留为空)。


如果是通过@Componentpipe理bean的Spring ,则需要确保以下内容:

  • Spring正按照其文档安装和集成。 重要的是,你至less需要在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相关的原因;例如一些XMLconfiguration相关的麻烦)


如果是通过var属性pipe理(嵌套的)Bean的重复器组件 (例如<h:dataTable var="item"><ui:repeat var="item"><p:tabView var="item">等),你实际上有一个“目标不可达,标识符”项目“parsing为空”,那么你需要确保以下内容:

  • 在任何子组件的binding属性中都没有引用#{item} 。 这是不正确的,因为binding属性在视图构build时运行,而不是在视图渲染时间内 此外,组件树中实际上只有一个组件,在每次迭代过程中都会重用。 换句话说,你实际上应该使用binding="#{bean.component}"而不是binding="#{item.component}" 。 但更好的办法是摆脱组件捆绑到bean,并调查问问题你认为这样解决问题的正确方法。 另请参见JSF中的“绑定”属性如何工作? 何时以及如何使用?


1B。 什么是(默认)托pipebean名称?

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

  • 像下面的FooBean支持bean类,

     @Named public class FooBean {} 

    在所有的beanpipe理框架中都会有一个默认的托pipebean名称#{fooBean} ,按照JavaBeans规范。

  • FOOBean支持bean类如下所示,

     @Named public class FOOBean {} 

    其不合格的类名以至less两个大写字母开头,在JSF和Spring中都有一个默认的托pipebean名称,即#{FOOBean}类名称#{FOOBean} ,也符合JavaBeans的特定。 在CDI中,在2015年6月之前发布的焊接版本中也是如此,但2015年6月以后发布的焊接版本(2.2.14 / 2.3.0.B1 / 3.0.0.A9)以及OpenWebBeans 中, CDI规范 。 在那些焊接版本和所有OWB版本中,只有第一个字符是小写的#{fOOBean}

  • 如果你已经像下面那样明确指定了一个托pipebean名称foo

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

    或者等同于@ManagedBean(name="foo")或者@Component("foo") ,那么它只会被#{foo} ,因此不会#{fooBean}


1C。 支持bean类在哪里?

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

如果您使用的是Eclipse,请确保backing bean类在src ,因此不是 WebContent ,并确保已启用Project> Build Automatically 。 如果您使用Maven,请确保backing bean类位于src/main/java ,因此不在 src/main/resourcessrc/main/webapp

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


2.目标不可到达,“实体”返回null

这归结为#{bean.entity.property}中的嵌套属性entity返回null 。 这通常只在JSF需要通过像下面这样的input组件设置 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的重要性, 在常规构造函数中执行此操作将会失败,因为您正在使用使用代理 (例如CDI)的Beanpipe理框架。 总是使用@PostConstruct挂钩托pipebean实例的初始化(并使用@PreDestroy钩挂托pipebean实例的销毁)。 另外,在一个构造函数中,你还不能访问任何注入的依赖项,也可以在构造函数中访问@Inject bean的同时参见NullPointerException 。

如果entityId是通过<f:viewParam> ,则需要使用<f:viewAction>而不是@PostConstruct 。 另请参见何时使用f:viewAction / preRenderView与PostConstruct?

您还需要确保在回发期间保留非null模型,以防止仅在add()操作方法中创build它。 最容易的是将bean放在视图范围内。 另请参见如何select正确的bean作用域?


3.目标无法访问,“空”返回null

这实际上是与#2相同的原因,只有(较老的)EL实现被使用,在保留属性名称以显示在exception消息中,最终被错误地暴露为“空白”时有点麻烦。 这只会使debugging和修复有点困难,当你有一些像#{bean.entity.subentity.subsubentity.property}这样的嵌套属性。

解决scheme仍然是一样的:确保所讨论的嵌套实体在所有级别都不为null


4.目标不可到达,“0”返回null

这与#2的原因也是一样的,只有在使用(较老的)EL实现时,在制定exception消息时是有问题的。 只有在EL中使用括号notation []时,才会暴露#{bean.collection[index]} ,其中#{bean.collection}本身非空,但指定索引处的项不存在。 这样的信息必须被解释为:

Target Unreachable,'collection [0]'返回null

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


5.目标不可到达,“BracketSuffix”返回null

这实际上与#4的原因是一样的,只有(旧的)EL实现被使用,在保存迭代索引以显示在exception消息中,这最终被错误地暴露为“BracketSuffix”,这实际上是字符] 。 只有在集合中有多个项目时,这只会使debugging和修复变得困难一些。


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

  • javax.el.E​​LException:读取types为com.example.Bean的'foo'时出错
  • javax.el.E​​LException:在类com.example.Bean中找不到属性actionMethod
  • javax.el.PropertyNotFoundException:在typescom.example.Bean上找不到属性'foo'
  • javax.el.PropertyNotFoundException:属性'foo'在typesjava.lang.Boolean上不可读
  • javax.el.PropertyNotFoundException:在typesorg.hibernate.collection.internal.PersistentSet上找不到属性
  • Outcommented Facelets代码仍会调用ELexpression式,例如#{bean.action()},并在#{bean.action}上导致javax.el.PropertyNotFoundException

对于那些仍然卡住…

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

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

我为javaee容器使用wildfly 10。 我遇到过“Target Unreachable”,实体“返回null”的问题。 感谢BalusC的build议,但解决了我的问题。 意外使用“import com.sun.istack.logging.Logger;” 而不是“import org.jboss.logging.Logger;” 造成CDI执行JSF EL。 希望它有助于改善解决scheme。

我有同样的问题。 解决scheme变得简单得多。 看起来,数据表需要getterforms的方法,即getSomeMethod(),而不仅仅是someMethod()。 在我的数据表中,我打电话给findResults。 我改变了我的支持bean中的方法getFindResults(),它的工作。

一个commandButton工作find没有得到使得它只是更令人困惑。

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

首先,应该认真对待BalusC解决scheme,但是在Netbeans中还有一个可能的问题需要注意,特别是在使用Maven构build企业应用程序项目(EAR)时

Netbeans生成一个父POM文件 ,一个EAR项目 ,一个EJB项目和一个WAR项目 。 我的项目中的其他一切都很好,我几乎认为这个问题可能是GlassFish 4.0(我不得不安装并将其插入到Netbeans中)的一个错误,因为GlassFish 4.1有一个Weld CDI错误,它使Netbeans 8.0中的embedded式GlassFish 4.1成为可能。 2通过补丁除外。

解:

为了解决“Target Unreachable,identifier'bean'parsing为null”错误 –

I右键单击父POM项目,然后select“ 属性” 。 出现一个项目属性对话框,点击“Sources”,你会惊讶地看到“ Source / Binary Format ”设置为1.5,“ Encoding ”设置为Windows 1250.将“ Source / Binary Format ”改为1.6或1.7,您更喜欢使您的项目CDI兼容,并且“ 编码 ”为UTF-8。

对所有其他子项目(EAR,EJB,WAR),如果它们不是已经分开的话,也要这样做。 运行你的项目,你不会再得到这个错误。

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

另一个线索:我正在使用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运行正常,managedbean才能正常运行。我得到了无法访问的对象(javax.el.propertynotfoundexception)。问题是JSF生成的ManagedBean,而不是Primefaces,我问的是对象的primefaces,我不得不从我的;.pom删除jsf-impl,干净安装这个工程,从这一点开始就一切正常,希望有帮助。

在旧样式中使用JSF必须在beans-config.xml文件(位于WEB-INF文件夹中)中定义托pipebean,并在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> 

(我试过使用其他范围,但是…)

web.xml中

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