1. 目标不可达,标识符“bean”解析为空
这归结为托管 bean 实例本身无法通过 EL 中的标识符(托管 bean 名称)找到,就像这样#{bean}
。
确定原因可以分为三个步骤:
一种。谁在管理豆子?
湾。什么是(默认)托管 bean 名称?
C。支持 bean 类在哪里?
1a。谁在管理豆子?
第一步是检查哪个 bean 管理框架负责管理 bean 实例。是通过CDI@Named
吗?还是JSF via @ManagedBean
?或者是Spring via @Component
?你能确保你没有在同一个支持 bean 类上混合多个 bean 管理框架特定的注释吗?例如@Named @ManagedBean
,@Named @Component
或@ManagedBean @Component
. 这是错误的。bean 必须由最多一个 bean 管理框架管理,并且该框架必须正确配置。如果您已经不知道该选择哪个,请前往Backing bean (@ManagedBean) 或 CDI Beans (@Named)?和Spring JSF 集成:如何在 JSF 托管 bean 中注入 Spring 组件/服务?
如果是CDI通过 管理 bean @Named
,那么您需要确保以下内容:
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 相同。当有一个beans.xml
与显式兼容的 CDI 1.1version="1.1"
时,默认情况下它只会注册具有@Named
显式 CDI 范围注释的bean ,例如, , ,等。如果您打算将所有 bean 注册为 CDI 托管 bean,即使是那些没有显式CDI 范围,使用下面的 CDI 1.1 兼容set (默认为)。@RequestScoped
@ViewScoped
@SessionScoped
@ApplicationScoped
/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 自动完成功能。
当使用 Mojarra 2.3.0-2.3.2 和 CDI 1.1+ bean-discovery-mode="annotated"
(默认)时,由于存在错误,您需要将 Mojarra 升级到 2.3.3 或更高版本。如果您无法升级,那么您需要设置bean-discovery-mode="all"
inbeans.xml
或将 JSF 2.3 特定@FacesConfig
注释放在 WAR 中的任意类上(通常是某种应用程序范围的启动类)。
在声明符合 Servlet 4.0 的 Servlet 4.0 容器上使用 JSF 2.3 时web.xml
,您需要显式地将 JSF 2.3 特定@FacesConfig
注释放在 WAR 中的任意类上(通常是某种应用程序范围的启动类)。这在 Servlet 3.x 中不是必需的。
使用 CDI 3.0 时,第一个版本的包重命名为javax.*
至jakarta.*
,那么您需要确保所有部署描述符文件beans.xml
、web.xml
、faces-config.xml
符合新jakartaee
模式,因此不符合旧javaee
模式。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/beans_3_0.xsd"
version="3.0" bean-discovery-mode="all">
</beans>
Tomcat 和 Jetty 等非 JEE 容器不附带 CDI。您需要手动安装它。这比仅添加库 JAR 需要更多的工作。对于 Tomcat,请确保遵循此答案中的说明:如何在 Tomcat 上安装和使用 CDI?
您的运行时类路径是干净的,并且在与 CDI API 相关的 JAR 中没有重复项。确保您没有混合多个 CDI 实现(Weld、OpenWebBeans 等)。当目标容器已经捆绑了 CDI API 时,请确保不要在 webapp 中提供另一个 CDI 甚至 Java EE API JAR 文件。
如果您在 JAR 中为 JSF 视图打包 CDI 托管 bean,那么请确保 JAR 至少有一个有效的/META-INF/beans.xml
(可以保持为空)。
如果JSF通过自 2.3 deprecated 管理 bean @ManagedBean
,并且您无法迁移到 CDI,则需要确保以下内容:
根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 会自动建议错误的一个作为列表中的第一项。
您没有在同一个支持 bean 类以及不同的托管 bean 名称中覆盖@ManagedBean
由 JSF 1.x 样式<managed-bean>
条目。faces-config.xml
这一项将优先于@ManagedBean
。faces-config.xml
从 JSF 2.0 开始,不需要在其中注册托管 bean ,只需将其删除即可。
您的运行时类路径是干净的,并且在与 JSF API 相关的 JAR 中没有重复项。确保您没有混合多个 JSF 实现(Mojarra 和 MyFaces)。当目标容器已经捆绑了 JSF API 时,请确保不要在 webapp 中提供另一个 JSF 甚至 Java EE API JAR 文件。有关JSF 安装说明,另请参阅我们 JSF wiki 页面的“安装 JSF”部分。如果您打算从 WAR 而非容器本身升级容器捆绑的 JSF,请确保您已指示目标容器使用 WAR 捆绑的 JSF API/impl。
如果您将 JSF 托管 bean 打包到 JAR 中,请确保 JAR 至少具有 JSF 2.0 兼容的/META-INF/faces-config.xml
. 另请参阅如何引用 JAR 文件中提供的 JSF 托管 bean?
如果您实际使用的是侏罗纪 JSF 1.x,并且无法升级,那么您需要通过<managed-bean>
infaces-config.xml
而不是@ManagedBean
. 不要忘记修复您的项目构建路径,使您不再拥有 JSF 2.x 库(这样@ManagedBean
注释就不会成功编译而令人困惑)。
如果是Spring通过 管理 bean @Component
,那么您需要确保以下几点:
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 配置相关的问题)
如果它是通过其属性(例如,,,等)管理(嵌套)bean的中继器组件,并且您实际上得到了“目标无法访问,标识符 'item' 解析为 null”,那么您需要确保以下内容:var
<h:dataTable var="item">
<ui:repeat var="item">
<p:tabView var="item">
1b。什么是(默认)托管 bean 名称?
第二步是检查注册的托管 bean 名称。JSF 和 Spring 使用约定符合JavaBeans 规范,而 CDI 有例外,具体取决于 CDI impl/version。
像下面这样的FooBean
支持 bean 类,
@Named
public class FooBean {}
#{fooBean}
根据 JavaBeans 规范,所有 bean 管理框架都会有一个默认的托管 bean 名称。
像下面这样的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) 和 OpenWebBeans 中都不是这种情况,因为CDI规范 在那些 Weld 版本和所有 OWB 版本中,它只是第一个字符小写#{fOOBean}
。
如果您已显式指定托管 bean 名称foo
,如下所示,
@Named("foo")
public class FooBean {}
or 等价于@ManagedBean(name="foo")
or @Component("foo")
,那么它只能由 使用#{foo}
,因此不能由 使用#{fooBean}
。
1c。支持 bean 类在哪里?
第三步是仔细检查支持 bean 类是否在构建和部署的 WAR 文件中的正确位置。确保您已正确执行项目和服务器的完全清理、重建、重新部署和重新启动,以防您实际上正忙于编写代码并在浏览器中不耐烦地按 F5。如果仍然无效,让构建系统生成一个 WAR 文件,然后使用 ZIP 工具提取和检查该文件。.class
支持 bean 类的编译文件必须驻留在其包结构中/WEB-INF/classes
。或者,当它被打包为 JAR 模块的一部分时,包含已编译.class
文件的 JAR 必须驻留在/WEB-INF/lib
而不是例如 EAR/lib
或其他地方。
如果您使用的是 Eclipse,请确保支持 bean 类是 insrc
而不是 WebContent
,并确保Project > Build Automatically已启用。如果您使用的是 Maven,请确保支持 bean 类在 in 中,src/main/java
因此不在src/main/resources
or中src/main/webapp
。
如果您使用 EJB+WAR(s) 将 Web 应用程序打包为 EAR 的一部分,那么您需要确保支持 bean 类在 WAR 模块中,因此不在 EAR 模块或 EJB 模块中。业务层 (EJB) 必须没有任何与 Web 层 (WAR) 相关的工件,以便业务层可跨多个不同的 Web 层(JSF、JAX-RS、JSP/Servlet 等)重用。
2.目标不可达,'实体'返回null
这归结为返回的嵌套属性。这通常仅在 JSF 需要通过如下所示的输入组件设置值时才会公开,而实际返回的.entity
#{bean.entity.property}
null
property
#{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
;如果您使用的是使用代理的 bean 管理框架,例如 CDI,那么在常规构造函数中执行此操作将失败。始终用于@PostConstruct
挂钩托管 bean 实例初始化(并用于@PreDestroy
挂钩托管 bean 实例销毁)。此外,在构造函数中,您还无法访问任何注入的依赖项,另请参阅NullPointerException 在尝试访问构造函数中的 @Inject bean 时。
如果entityId
是通过 提供的<f:viewParam>
,您需要使用<f:viewAction>
而不是@PostConstruct
. 另请参阅何时使用 f:viewAction / preRenderView 与 PostConstruct?
您还需要确保null
在回发期间保留非模型,以防您仅在add()
操作方法中创建它。最简单的方法是将 bean 放在视图范围内。另请参阅如何选择正确的 bean 范围?
3.目标不可达,'null'返回null
这实际上与 #2 的原因相同,只是使用的(较旧的)EL 实现在保留要在异常消息中显示的属性名称方面有些错误,最终错误地暴露为“null”。当你有很多像这样的嵌套属性时,这只会使调试和修复变得更加困难#{bean.entity.subentity.subsubentity.property}
。
解决方案仍然相同:确保所讨论的嵌套实体不是null
, 在所有级别。
4.目标不可达,''0''返回null
这也与 #2 有相同的原因,只有正在使用的(较旧的)EL 实现在制定异常消息时存在错误。仅当您[]
在 EL 中使用大括号表示法时才公开,#{bean.collection[index]}
因为#{bean.collection}
它本身是非空的,但指定索引处的项目不存在。然后必须将此类消息解释为:
目标不可达,'collection[0]' 返回 null
解决方法也和#2一样:确保集合项可用。
5.目标不可达,'BracketSuffix'返回null
这实际上与 #4 的原因相同,只是使用的(较旧的)EL 实现在保留迭代索引以显示在异常消息中有些错误,最终错误地暴露为 'BracketSuffix' 这实际上是字符]
。当您在集合中有多个项目时,这只会使调试和修复变得更加困难。
其他可能的原因javax.el.PropertyNotFoundException
: