“无法将 ejbRef 转换为 ejb”关于将 @Stateless EJB 的 CDI(焊接)注入 Glassfish 中的 @SessionScoped JSF2 bean
[更新:在 的 Glassfish 论坛/ML 上进行讨论后http://forums.java.net/jive/thread.jspa?messageID=480532 针对 Glassfish https://glassfish.dev.java.net/issues/show_bug.cgi?id=13040 对于此问题。]
我正在尝试注入本地@Stateless EJB 到 JSF2 @Named @javax.enterprise.context.SessionScoped 支持 bean 的无接口视图。 EJB 是扩展抽象通用基类的几个之一。 “@Inject TheEJBClass varName”的注入失败,并显示“无法将 ejb TheEJBClass 的 ejbRef 转换为 my.package.name.TheAbstractBase 类型的业务对象”。 [编辑:实际上,事实证明注入成功,但从超类继承的方法的注入代理中的方法解析失败。]如果我使用“@EJB TheEJBClass varName”,则 varName 保持为 null,即什么都没有被注入。
详细信息:
我在 Linux 上运行 Glassfish 3.0.1(如果重要,则为 Ubuntu 10.04),并且在使用 CDI (Weld) 将数据模型 EJB 注入到 JSF2 会话范围模型中时遇到真正的问题。是的,在你问之前,我已经准备好 beans.xml 并且 CDI 正在激活以执行注入。
如果我使用 @EJB 注释注入它,例如:
@EJB TheEJBClass memberName;
... EJB 实际上并未注入,而 memberName 为空。
如果我用 CDI @Inject 注释注入它:
@Inject TheEJBClass memberName;
...那么当我调用在 TheEJBClass 的超类中实现的“memberName”方法时,CDI 会抱怨,该方法在 TheEJBClass 的超类中实现,并且未在 TheEJBClass 自身中重写,报告:
java.lang.IllegalStateException: Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase
at
com.sun.ejb.containers.EjbContainerServicesImpl.getBusinessObject(EjbContainerServicesImpl.java:104)
at
org.glassfish.weld.ejb.SessionObjectReferenceImpl.getBusinessObject(SessionObjectReferenceImpl.java:60)
....
我已尝试转换基类到具体类并对其进行去泛化,但遇到了同样的问题,所以我认为我不会用通用基础来解决 Weld 错误(https://jira.jboss.org/browse/WELD-305,https://jira.jboss.org/browse/WELD-381,https://jira.jboss.org/browse/WELD-518)。
为清楚起见,添加了注释的完整包限定的代码大纲如下:
// JSF2 managed backing bean.
//
// Called via #{someJSF2Model.value} in a JSF2 page
//
@javax.inject.Named
@javax.enterprise.context.SessionScoped
public class SomeJSF2Model implements Serializable {
@javax.inject.Inject TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
@javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
请注意,如果我重写 TheEJBClass 中的 TheAbstractBase.getValue(),或者调用 TheEJBClass 中定义的方法,注入就会起作用。而不是任何超类。看来这个问题与继承有关。
使用 JSF2 内置生命周期和注入功能的非常相似的代码可以工作,但考虑到这是一个新项目,并且 CDI 是未来的发展方向,我认为最好尝试使用 CDI。这是我开始使用 JSF2/EJB 注入的方法,它有效:
// JSF2 managed backing bean. Using @ManagedBean and JSF2's @SessionScoped
// instead of CDI @Named and CDI @SessionScoped this time.
//
@javax.faces.bean.ManagedBean
@javax.faces.bean.SessionScoped
public class SomeJSF2Model implements Serializable {
@javax.ejb.EJB TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
// Unchanged from CDI version
@javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
// Unchanged from CDI version
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
我目前正在编写一个独立的测试用例,但我想我现在就可以解决这个问题,以防万一这是我想要的做了一些愚蠢的事情,或者有一个众所周知的解决方案,我的 Google-fu 无法找到。为什么 JSF2/EJB 注入可以工作,但 CDI 注入却失败?
(自从在 Glassfish 论坛上重新发布为 http://forums.java.net /jive/thread.jspa?threadID=152567 )
[UPDATE: After discussion on the Glassfish forums/ML at http://forums.java.net/jive/thread.jspa?messageID=480532 a bug was filed against Glassfish https://glassfish.dev.java.net/issues/show_bug.cgi?id=13040 for this issue.]
I'm trying to inject a local no-interface view of a @Stateless EJB into a JSF2 @Named @javax.enterprise.context.SessionScoped backing bean. The EJB is one of several that extend an abstract generic base class. Injection of "@Inject TheEJBClass varName" fails with "Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase". [edit: Actually, it turns out that injection succeeds, but method resolution in the injected proxy for methods inherited from superclasses fails.] If I use "@EJB TheEJBClass varName" then varName remains null, ie nothing is injected.
Details:
I'm running Glassfish 3.0.1 on Linux (Ubuntu 10.04 in case it matters) and having real problems handling injection of my data model EJBs into my JSF2 session scoped models using CDI (Weld). And yes, before you ask, I have beans.xml in place and CDI is activating to perform injection.
If I inject it with an @EJB annotation, eg:
@EJB TheEJBClass memberName;
... the EJB isn't actually injected, leaving memberName null.
If I inject it with a CDI @Inject annotation:
@Inject TheEJBClass memberName;
... then CDI complains when I call a method of "memberName" that's implemented in a superclass of TheEJBClass and not overridden in TheEJBClass its self, reporting:
java.lang.IllegalStateException: Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase
at
com.sun.ejb.containers.EjbContainerServicesImpl.getBusinessObject(EjbContainerServicesImpl.java:104)
at
org.glassfish.weld.ejb.SessionObjectReferenceImpl.getBusinessObject(SessionObjectReferenceImpl.java:60)
....
I've tried converting the base to concrete class and de-generifying it, but encounter the same problem, so I don't think I'm hitting the Weld bugs with generic bases (https://jira.jboss.org/browse/WELD-305, https://jira.jboss.org/browse/WELD-381, https://jira.jboss.org/browse/WELD-518).
An outline of the code, with full package qualification on annotations added for clarity, is:
// JSF2 managed backing bean.
//
// Called via #{someJSF2Model.value} in a JSF2 page
//
@javax.inject.Named
@javax.enterprise.context.SessionScoped
public class SomeJSF2Model implements Serializable {
@javax.inject.Inject TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
@javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
Note that injection does work if I override TheAbstractBase.getValue() in TheEJBClass, or if I call a method defined in TheEJBClass and not any superclass. It seems like the issue is something to do with inheritance.
Very similar code that used JSF2's built-in lifecycle and injection features worked, but given that this is a new project and CDI is where things are heading in the future, I thought it best to try to go for CDI. Here's what I started out with using JSF2/EJB injection, which worked:
// JSF2 managed backing bean. Using @ManagedBean and JSF2's @SessionScoped
// instead of CDI @Named and CDI @SessionScoped this time.
//
@javax.faces.bean.ManagedBean
@javax.faces.bean.SessionScoped
public class SomeJSF2Model implements Serializable {
@javax.ejb.EJB TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
// Unchanged from CDI version
@javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
// Unchanged from CDI version
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
I'm currently working on putting together a self-contained test case, but thought I'd fire off the question now in case this is something where I'm just doing something silly or there's a well known solution my Google-fu isn't up to finding. Why did it work with JSF2/EJB injection, but fail with CDI injection?
( Since re-posted on the Glassfish forums as http://forums.java.net/jive/thread.jspa?threadID=152567 )
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如上所述,这是一个 Weld/glassfish 错误。
修复:放弃 Glassfish 并转向 JBoss AS 7,它实际上在大多数情况下都可以工作。
As noted above, it's a Weld/glassfish bug.
Fix: Give up on Glassfish and move to JBoss AS 7, which actually works most of the time.