当试图引用EL中的托管bean时,如#{bean.entity.property}
,有时会抛出javax.el.PropertyNotFoundException: Target Unreachable
异常,通常是在设置bean属性时,或者要调用bean动作时。
似乎有五种不同的消息:
这些都意味着什么?它们是如何引起的,它们应该如何解决?
这归结为托管bean实例本身无法通过EL中的标识符(托管bean名称)找到,就像#{bean}
一样。
确定原因可分为三个步骤:
一个。谁在管理豆子? 湾什么是(默认)托管bean名称? C。支持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_0
和2.0
替换2_1
和2.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_2
和2.2
替换2_3
和2.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只是将其删除。/META-INF/faces-config.xml
。另见How to reference JSF managed beans which are provided in a JAR file?<managed-bean>
中的faces-config.xml
而不是@ManagedBean
来注册bean。不要忘记修复项目构建路径,使得您不再拥有JSF 2.x库(因此@ManagedBean
注释不会混淆地成功编译)。如果它是通过@Named
管理bean的CDI,那么你需要确保以下内容:
/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
,或空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.xml
和bean-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自动完成。bean-discovery-mode="annotated"
(默认)时,由于bug,您需要将Mojarra升级到2.3.3或更高版本。如果你无法升级,那么你需要在bean-discovery-mode="all"
中设置beans.xml
,或者将JSF 2.3特定的@FacesConfig
注释放在WAR中的任意类(通常是某种应用程序范围的启动类)上。/META-INF/beans.xml
(可以保留为空)。如果是Spring通过@Component
管理bean,那么你需要确保以下内容:
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>
如果它是一个转发器组件,它通过其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?第二步是检查已注册的托管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}
。foo
,如下所示,
@Named("foo")
public class FooBean {}
或者与@ManagedBean(name="foo")
或@Component("foo")
等效,那么它只能由#{foo}
提供,因此不能由#{fooBean}
提供。如果支持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/resources
或src/main/webapp
中。
如果您将Web应用程序打包为带有EJB + WAR的EAR的一部分,那么您需要确保支持bean类在WAR模块中,因此不在EAR模块或EJB模块中。业务层(EJB)必须没有任何与Web层(WAR)相关的工件,因此业务层可以跨多个不同的Web层(JSF,JAX-RS,JSP / Servlet等)重用。
这归结为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?
这与#2实际上是相同的原因,只有正在使用的(较旧的)EL实现在保留要在异常消息中显示的属性名称时有些错误,最终错误地暴露为“null”。当你有一些像#{bean.entity.subentity.subsubentity.property}
这样的嵌套属性时,这只会使调试和修复变得更难。
解决方案仍然是相同的:确保所讨论的嵌套实体不是所有级别的null
。
这也与#2的原因相同,只有正在使用的(较旧的)EL实现在制定异常消息时存在错误。只有当你在[]
中使用括号符号#{bean.collection[index]}
时才会暴露这种情况,其中#{bean.collection}
本身是非空的,但指定索引处的项目不存在。这样的消息必须解释为:
目标无法访问,'collection [0]'返回null
解决方案也与#2相同:确保收集项目可用。
这与#4实际上是相同的原因,只有正在使用的(较旧的)EL实现在保留迭代索引以显示在异常消息中有些错误,最终错误地暴露为'BracketSuffix',这实际上是字符]
。当您在集合中有多个项目时,这只会使调试和修复变得更加困难。
javax.el.PropertyNotFoundException
:对于1.主题(目标无法访问,标识符'bean'已解析为null);
我检查了@BalusC和其他分享者的有价值的答案,但我在我的方案中超出了这个问题。在创建一个具有不同名称的新xhtml并创建具有不同名称的bean类之后,我将代码逐步写入(而非复制粘贴)到新的bean类和新的xhtml文件。
使用旧样式使用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>
另一个线索:我使用的是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。从这一点开始一切顺利。希望有所帮助。
EL如前所述解释$ {bean.propretyName} - 假设您使用生成getter / setter的显式或隐式方法,propertyName变为getPropertyName()
您可以通过将名称显式标识为函数来覆盖此行为:$ {bean.methodName()}这直接调用函数方法Name()而不进行修改。
您的访问者被命名为“get ...”并不总是正确的。
对于那些仍然被卡住的人......
将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文件夹)并重新启动服务器。
在我自己解决之后,我决定分享我对这个错误的发现。
首先,应该认真对待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)执行相同操作(如果它们尚不可分隔)。运行您的项目,您将不会再次收到该错误。
我希望这可以帮助那些有类似错误的人。
我决定分享我的解决方案,因为虽然这里提供的许多答案都很有用,但我仍然遇到了这个问题。在我的情况下,我使用JSF 2.3,jdk10,jee8,cdi 2.0作为我的新项目,我确实在wildfly 12上运行我的应用程序,启动服务器参数standalone.sh -Dee8.preview.mode = true,如wildfly网站上的建议。下载wildfly后,“bean解析为null”的问题就消失了。将完全相同的战争上传到wildfly 13后,一切正常。
在我的情况下,我在@Named(“beanName”)中犯了一个拼写错误,它被认为是“beanName”,但我写了“beanNam”,例如。
我使用wildfly 10作为javaee容器。我曾经历过“Target Unreachable,'entity'返回null”问题。感谢BalusC的建议,但我解决了解决方案的问题。无意中使用“import com.sun.istack.logging.Logger;”而不是“import org.jboss.logging.Logger;”导致CDI实施JSF EL。希望它有助于改善解决方案。
我有同样的问题。结果证明解决方案要简单得多。似乎数据表需要getter形式的方法,即getSomeMethod(),而不仅仅是someMethod()。在我的数据表中,我调用了findResults。我将我的支持bean中的方法更改为getFindResults()并且它工作正常。
一个commandButton工作找不到get,这使得它更加令人困惑。
至于#2,在我的情况下,它取代后神奇地变为现实
<body>
标记
<h:body>
在完成了几个(更简单,更诚实的)JSF项目之后,我不记得现在做了什么不同的设置,我第一次遇到了这种错误。我正在创建一个非常基本的登录页面(用户名,密码,用户Bean ...)并像往常一样设置所有内容。我发现的唯一区别是前面提到的标签。也许有人觉得这很有用。
我的问题是我包含了一个构造函数,它接受参数但不包含带有Inject注释的空构造函数,就像这样。
@Inject public VisitorBean() {}
我刚刚测试它没有任何构造函数,这似乎也工作。