识别并解决javax.el.PropertyNotFoundException:目标无法访问
当试图在EL中引用一个托pipebean,就像#{bean.entity.property}
,有时候会抛出一个javax.el.PropertyNotFoundException: Target Unreachable
exception,通常在设置bean属性时,或者当一个bean动作被调用。
似乎有五种不同的信息:
- 目标无法访问,标识符“bean”parsing为null
- 目标不可到达,“实体”返回null
- Target Unreachable,'null'返回null
- 目标无法访问,“0”返回null
- 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组件/服务?
如果是通过@ManagedBean
pipe理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
注解不会混淆成功编译)。
如果是通过@Named
pipe理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.xml
和bean-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
(可以保留为空)。
如果是通过@Component
pipe理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/resources
或src/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.ELException:读取types为com.example.Bean的'foo'时出错
- javax.el.ELException:在类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>