Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Unable to convert ejbRef for ejb" on CDI (Weld) injection of @Stateless EJB into @SessionScoped JSF2 bean in Glassfish

[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 )

like image 200
Craig Ringer Avatar asked Aug 18 '10 05:08

Craig Ringer


1 Answers

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.

like image 199
Craig Ringer Avatar answered Nov 05 '22 00:11

Craig Ringer