Reputation: 67370
TL;DR: Web Service uses an @Inject
ed class, @Inject
ed class uses @EJB
s. @EJB
s are null. Why are they null and how do I fix this?
I'm using Glassfish 3 and I have a @Stateless
@WebService
that is @Inject
ing a class with a @Dependent
annotation on it. I'd like this class to be able to use other stateless ejbs as fields like this:
@EJB(name = "ejb/MySessionBean", beanName = "MySessionBean")
private MySessionLocal mySessionLocal;
But, when I try to call this web service, these @EJB
fields are null (although the @Dependent
class itself seems to be injected into the web service correctly). Is it possible to do what I'm trying to do?
I should add that my Web Service and my EJBs are in an EJB jar in an ear's root. The @Dependent
class is inside a jar in the ear's lib/ directory.
UPDATE: I've discovered that the @EJBs work correctly (are not null) if I move the @Dependent
class into the same jar as the web service. To me this suggests a classloader issue? An ear's ejb jar can @Inject
a class in a "lib/*.jar", but a class in a "lib/*.jar" can't get an @EJB
from a ejb jar in the ear's root.
It's still unclear to me if this is by design.
Upvotes: 2
Views: 293
Reputation: 67370
I have found a workaround, though I'd prefer not to have to use it. Its always been the case that I can get a reference to the @EJB
by doing this (in my "lib/*.jar"):
//inside EjbLookup.java
public <T> T lookupEjb(String sessionBeanClassName) {
return lookup("java:comp/env/ejb/" + sessionBeanClassName);
}
public <T> T lookup(String name) {
try {
Context c = new InitialContext();
return (T) c.lookup(name);
} catch (NamingException ne) {
log.error(ne.getMessage(), ne);
throw new RuntimeException(ne);
}
}
So I can create a class like this in my "lib/*.jar":
import javax.enterprise.inject.Produces;
public class EjbProducer {
private EjbLookup ejbLookup = new EjbLookup();
@Produces
public MySessionLocal getMySessionLocal() {
return ejbLookup.lookupEjb("MySessionBean");
}
}
And now I can @Inject
the EJB anywhere in my "lib/*.jar" by doing this:
@Inject
private MySessionLocal mySessionLocal;
On the other hand, if I attempt to use this code inside the EJB jar itself, I get an error about how the stateless ejb could not be created. Perhaps that has more to do with the way you're supposed to use JNDI than CDI though. I can work around this by using @EJB
when I'm inside the ejb jar and using @Inject
when I'm in the lib.
Upvotes: 0
Reputation: 16196
An ear's ejb jar can
@Inject
a class in a "lib/*.jar
", but a class in a "lib/*.jar
" can't get an@EJB
from a ejb jar in the ear's root.It's still unclear to me if this is by design.
I believe this is by design. A library (something in the .ear
file's library directory) does not have to be processed by the machinery that fills @EJB
-annotated slots. To put it another way, only a Java EE module (an EJB jar, a web application) will have its @EJB
-annotated fields "filled".
CDI, by contrast, has no such restrictions (provided that the relevant META-INF/beans.xml
files exist), so it can "fill" @Inject
-annotated fields with beans sourced from any bean archive.
Upvotes: 1