jsf – 标识和解决javax.el.PropertyNotFoundException:Target Unreachable

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

似乎有五种不同类型的消息:

> Target Unreachable, identifier ‘bean’ resolved to null
> Target Unreachable, ‘entity’ returned null
> Target Unreachable, ‘null’ returned null
> Target Unreachable, ”0” returned null
> Target Unreachable, ‘BracketSuffix’ returned null

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

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

这可以归结为,在EL中完全使用标识符(托管bean名称)找不到托管bean实例本身,如#{bean}。

识别原因可以分为三个步骤:

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

1a。谁管理bean?

第一步是检查哪个bean管理框架负责管理bean实例。是JSF通过@ManagedBean?或者是CDI通过@Named?还是通过@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?

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

> faces-config.xml根声明与JSF 2.0兼容。因此,XSD文件和版本必须至少指定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自动完成,Eclipse知道自动建立错误的作为列表中的第一项。
>您没有通过JSF 1.x样式覆盖@ManagedBean< 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。不要忘记修复你的项目构建路径,这样你就没有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与显式版本=“1.1”,那么它将默认情况下只注册@Named bean与显式CDI范围注释,如@RequestScoped@ViewScoped@SessionScoped@ApplicationScoped等。如果你打算要将所有bean注册为CDI管理的bean,即使没有明确的CDI范围,也使用以下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>

>当使用CDI 1.1和bean-discovery-mode =“annotated”(默认)时,请确保没有意外导入JSF范围,如javax.faces.bean.RequestScoped,而不是CDI范围javax.enterprise.context.RequestScoped.注意IDE自动完成。
>非Java EE容器(如Tomcat和Jetty)不附带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,那么您需要确保以下内容:

> Spring正在按照its documentation安装和集成。重要的是,你至少需要在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)管理(嵌套)bean的中继器组件var =“item”>等),你实际上得到了一个“Target Unreachable,identifier’item’resolved to null”,那么你需要确保以下内容:

>#{item}未在任何子组件的绑定属性中引用。这是不正确的,因为绑定属性在视图构建时运行,而不是在视图渲染时。此外,在组件树中物理上只有一个组件,其在每次迭代循环期间被简单地重用。换句话说,你应该实际使用binding =“#{bean.component}”而不是binding =“#{item.component}”。但是更好的是完全摆脱组件绑定到bean,调查/询问正确的方法,你认为解决这个问题。参见How does the ‘binding’ attribute work in JSF? When and how should it be used?

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

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

>一个FooBean支持bean类如下,

@Named
public class FooBean {}

将在所有bean管理框架中具有默认托管bean名称#{fooBean},按照JavaBean规范。
>一个FOOBean支持bean类如下,

@Named
public class FOOBean {}

其不合格的类名以至少两个资本开始在JSF和Spring中具有完全不合格的类名#{FOOBean}的默认托管bean名称,也符合JavaBeans特定。在CDI中,在2015年6月之前发布的Weld版本中也是如此,但是在2015年6月之后发布的Weld版本(2.2.14 / 2.3.0.B1 / 3.0.0.A9)中以及在2007年发布的OpenWebBeans中都不会发生。那些Weld版本,在所有OWB版本中,它只有第一个字符lowercased#{fOOBean}。
>如果您已经明确指定了如下所示的托管bean名称foo,

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

或者等同于@ManagedBean(name =“foo”)或@Component(“foo”),那么它只能通过#{foo}可用,因此不能通过#{fooBean}。

1c。支持bean类在哪里?

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

如果您使用Eclipse,请确保backing bean类在src中,因此不是WebContent,并确保Project>自动构建已启用。如果你使用Maven,请确保支持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.目标不可达,“entity”返回null

这可以归结为,#{bean.entity.property}中的嵌套属性实体返回null。这通常只暴露当JSF需要通过一个输入组件设置属性的值,如下所示,而#{bean.entity}实际返回null。

<h:inputText value="#{bean.entity.property}" />

您需要确保您事先在@PostConstruct或< f:viewAction>中准备了模型实体。方法,或者可能使用add()动作方法,以防您在同一视图上使用CRUD列表和/或对话框。

@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?

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

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

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

解决方案仍然是相同的:确保所有级别的问题的嵌套实体不为null。

4.目标无法访问,“0”返回null

这也有与#2相同的原因,只有使用的(较旧的)EL实现在制定异常消息时是错误的。只有当您在#{bean.collection [index]}中的EL中使用大括号[]时,才会公开此处,其中#{bean.collection}本身不为null,但指定索引处的项目不存在。这样的消息必须被解释为:

Target Unreachable, ‘collection[0]’ returned null

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

5.目标无法访问,“BracketSuffix”返回null

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

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

> javax.el.ELException: Error reading ‘foo’ on type com.example.Bean
> javax.el.ELException: Could not find property actionMethod in class com.example.Bean
> javax.el.PropertyNotFoundException: Property ‘foo’ not found on type com.example.Bean
> javax.el.PropertyNotFoundException: Property ‘foo’ not readable on type java.lang.Boolean
> javax.el.PropertyNotFoundException: Property not found on type org.hibernate.collection.internal.PersistentSet
> Outcommented Facelets code still invokes EL expressions like #{bean.action()} and causes javax.el.PropertyNotFoundException on #{bean.action}

http://stackoverflow.com/questions/30128395/identifying-and-solving-javax-el-propertynotfoundexception-target-unreachable

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:jsf – 标识和解决javax.el.PropertyNotFoundException:Target Unreachable