I have an EAR file containing a WAR.
The EAR contains an EJB jar. The EJB exposes a Local and Remote interface.
#Stateless(name = "FooServiceEJB")
#Local(IFooServiceLocal.class)
#Remote(IFooService.class)
public class FooServiceBean implements IFooService, IFooServiceLocal {
...
}
The WAR file defines a JAXRS annotated class.
#Path("/foo")
#LocalBean
#Stateless
public class FooResource {
...
}
I wish to inject the local 'view' of the EJB into the JAXRS resource class. Apparently I have two options, which I assumed would be equivalent (for the most part):
Use #EJB
Use #Inject (To many, this appears to be the preferred option - see Should I use #EJB or #Inject)
I'm running JBoss EAP 6.2.0.GA (AS 7.3.0.Final-redhat-14).
The difference in behaviour that I am seeing is as follows (on JBoss - haven't tried any other app servers):
If I use #EJB to inject the local ejb, then the call semantics are by reference (as expected). For example:
#EJB
private FooServiceLocal fooService;
However, if I use #Inject to inject the local ejb, the call semantics are by value (i.e. serialization occurs). For example:
#Inject
private IFooServiceLocal fooService;
Here's a snapshot of the thread stack with the class that I believe is performing the serialization. The thread stack is completely different when I use the #EJB annoation.
http://i.stack.imgur.com/BXSaz.png
Any ideas why I am seeing this difference in behaviour?
Related
TL;DR: Web Service uses an #Injected class, #Injected class uses #EJBs. #EJBs 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 #Injecting 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.
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.
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.
I have a testcase which makes use of OpenEjb's #LocalClient annotation (embedded container) and injects EJBs using the #EJB annotation:
#LocalClient
public class MyTestCase {
#EJB
private BoxDao boxDao;
...
}
BoxDao is a remote EJB interface. Now, for testing, I need to access some internal state of BoxDao's implementation BoxDaoBean, which is a stateful session bean. I created a protected method in BoxDaoBean, which exposes the needed internal state, but I found not yet a way to access it in my test case, since the injected BoxDao is a remote interface proxy (an cannot be cast to BoxDaoBean).
Is there a way to access the stateful session bean behind the remote interface BoxDao in the test case? Would not matter if solution is OpenEjb specific.
Update: We can't use EJB 3.1 specific solutions unfortunately, as we have several EJB 3.0 projects running. Using Proxy.getInvocationHandler(boxDao), I can get access to the OpenEjb container, via StatefulEjbObjectHandler. Is it possible to access the stateful bean this way?
You could try having BoxDaoBean also expose an #LocalBean interface. A single EJB can expose a near unlimited number of views from #WebService, #Local, #Remote, JAX-RS and more.
Just update your bean like so:
#Stateful
#LocalBean
public class BoxDaoBean implements BoxDao {
//...
}
Then add another field to your test:
#LocalClient
public class MyTestCase {
#EJB
private BoxDao boxDao;
#EJB
private BoxDaoBean boxDaoBean;
...
}
#Local
public interface EJBA{
// declares a method 'validate'
}
#Stateless
public class EJBABean implements EJBA{
// implements the method 'validate'
}
class Model{
#EJB
private EJBA ejbA;
public void doSomething(){
ejbA.validate();
}
}
Now, if I do the following from the execute method of a Struts 1.2 action class
new Model().validate();
ejbA of Model is null, resulting in a NullPointerException. The question is similar to this but, in my case, I am running the client code (Model) as well as the bean in the JBoss 6.1 Final server itself. The model and the EJB are in the a separate jar file and the the action classes are in a war file. Both of these are packaged inside an ear file.
If I use a context lookup using [ear-name]/EJBABean/local, I am able to access it though. What am I doing wrong ?
Your Model class is not managed by the container and therefore JBoss is not able to identify ejbA as an injected EJB. You have to turn your Model class into an EJB by annotating it with #Stateless/#Stateful/#Singleton.
That's why a JNDI lookup in which the container doesn't take part, works perfectly.
I am new to Java EE 6 and CDI. I have read a couple of tutorials and the weld documentation. However something that should work from my understanding doesn't so I need help.
I have the following situation. I created a Java EE 6 Application with NetBeans 7.0.1 using the maven archetype supplied with the IDE and I deploy to GlassFish 3.1 also supplied by the IDE.
The beans.xml is located in the META-INF directory of my EJB jar.
I have created a class that works soley as a producer class for my EJB Artifacts (and EntityManager)
#Stateless
public class EjbArtifactProducer {
#PersistenceContext(unitName = "trackProfiler-PU")
private EntityManager em;
#EJB
private UserFacadeLocal userFacade;
#EJB
private AuthServiceLocal authService;
#EJB
private NewsEntryFacadeLocal newsEntryFacade;
#EJB
private RoleFacadeLocal roleFacade;
#EJB
private TrackCommentFacade trackCommentFacade;
#EJB
private TrackFacade trackFacade;
#EJB
private TrackTypeFacade trackTypeFacade;
#EJB
private WaypointFacadeLocal waypointFacade;
#Produces
public AuthServiceLocal getAuthService() {
return authService;
}
#Produces
public EntityManager getEm() {
return em;
}
#Produces
public NewsEntryFacadeLocal getNewsEntryFacade() {
return newsEntryFacade;
}
#Produces
public RoleFacadeLocal getRoleFacade() {
return roleFacade;
}
#Produces
public TrackCommentFacade getTrackCommentFacade() {
return trackCommentFacade;
}
#Produces
public TrackFacade getTrackFacade() {
return trackFacade;
}
#Produces
public TrackTypeFacade getTrackTypeFacade() {
return trackTypeFacade;
}
#Produces
public UserFacadeLocal getUserFacade() {
return userFacade;
}
#Produces
public WaypointFacadeLocal getWaypointFacade() {
return waypointFacade;
}
}
I tried to apply the #Produces annotation directly to the fields an on methods as shown above.
However the following does not inject anything in another EJB
#Inject
private NewsEntryFacadeLocal newsEntryFacade;
This is done in a stateless session ejb but when I try to access newsEntryFacade in any of my business methods a NullPointerException is thrown. So clearly no Injection is happening or my producers produce null references.
Am I missing something? Or should this work according to CDI/Weld?
Strangely it seems to work that way when I try to #Inject EJBs into the web application part (however i needed an extra producer class in my .war for this to work, is this as it should be?).
EDIT: The project works with an ant build (generated by NetBeans). Are there issues with the Maven archetype provided by NetBeans? It seems that with the Maven archetype there are some issues with CDI injection between the war and ejb modules. I found that if I had separate producers in the web and ejb module Glassfish generates a deployment error stating that there are two indistinguishable implementations of an interface. But when I remove the producer in the web module Weld complains that the EJB i want to inject into my beans in the web module cannot be resolved. Also with the Ant build EJBs can be #Injected without a producer while the maven build needs producer fields on a class. I can't explain how this could happen. After all the final deployment should be more or less equal, shouldn't it?
If you want to use #Inject then annotate it as #Named #ApplicationScoped, otherwise use #EJB when injecting your singleton.
Jordan Denison is correct. You're trying to #Inject and EJB, but you be using #EJB for EJBs. You're EJB class is probably annotated with #Stateless or something. #Inject should be used on session beans that annotated with #Named and some sort of scope.
Hard to tell whats going wrong but what definitely did not work for us is to use CDI between class loader boundaries. For example if your application is packaged as an ear file you would have your ejbs in an jar file and your webapp in your war file. In this case you can not use CDI to inject your ejbs in your web layer. The problem is that the jar and the war is loaded by different class loaders. Maybe newer CDI implementations behave different but at least JBoss 6 and Glassfish had this problem.
Try to put #Named into EjbArtifactProducer. Also, if the produces is this kind of simple, I think it's better to remove it too (else, you should do one more change).
you are mixing two different concepts... use CDI as backing beans for JSF. (CDI in Web Container) and use EJB and JPA in the Business Layer... the CDI layer can inject a EJB to call the specific business method.
in this case you have a clean separation on concerns.
BTW: you do not need any EJB interfaces at all! use only interfaces if you have a requirements to communicate from remote... (#Remote). with the #LocalBean annotation you can inject directly the EJB itself..
if you have e clean separation of layers each with his own concern i think you better find the reason for this NullPointerException.. and i think your NullPointerException does not exists any more after this...
Layering:
Web Browser --> JSF Facelet --> CDI Backing Bean --> EJB Service(s) --> EntityManager
I have the following configuration:
1 EAR on one GF containing 2 EJB-JARs with EJB components.
1 WAR on another Glassfish server (=> other JVM) containing web components accessing the EJB components.
I have 2 EJB business services in each EJB-JAR of my EAR, and they are all developped like this:
#Remote
public interface ServiceAItf {
...
}
#Stateless
#Local
public class ServiceAImpl implements ServiceAItf {
...
}
In my WAR, I access the EJB components via an explicit "InitialContext.lookup" on the remote interface.
In my EAR, I am quite confused about the best practice for injection, in terms of performance, architecture, and so on...
I have the following questions:
As you can see, I have declared the annotation "#Local" on the service implementation without defining the local interface. Is it correct? At least I have no error at deployment. But maybe I should use the "#LocalBean" annotation instead? I suppose that the "#LocalBean" annotation simply allows to invoke the implementation directly as a "Local" EJB, but you have to use the implementation in your code like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAImpl serviceA;
...
}
What is the best way to inject one EJB into another one?
It works like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAItf serviceA;
...
}
But from what I noticed, the "serviceA" injected is the remote proxy, while it is in the same JVM within the same EAR file. So I suppose that there will be an impact on the performance. That's why I have tried to inject the service like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#Inject
private ServiceAItf serviceA;
...
}
But it doesn't work in GF, I have the following exception:
WELD-001408 Unsatisfied dependencies for type [...] ...
I then tried to create a local interface, and the injection via the annotation "#Inject" works when both services
Even if I create a local interface like this, the service is not injected via the annotation "#Inject" but is null:
#Local
public interface ServiceALocalItf {
...
}
I read a lot of articles where it is highly recommended to use "#Inject" instead of "#EJB" when it is for a local invocation. That leads me to the following question: in which case the "#Local" EJB invocation is recommended (or simply used)?
After all this analysis, I come to the following conclusion:
For each service, I create a "#Local" and a "#Remote" interface.
From WAR to EJB-JAR of EAR, make a JNDI lookup to the remote interface.
From EJB-JAR to EJB-JAR, make an injection via "#EJB" to the local interface.
For two services within the same EJB-JAR, make an injection via "#Inject" to the local interface.
What do you think about it? Is it correct?
As you can see, I have declared the annotation "#Local" on the service
implementation without defining the local interface. Is it correct?
With EJB 3.1, the requirement for local interfaces was dropped. No need to write them unless you explicitly need them.
What is the best way to inject one EJB into another one?
Couple of things to write here:
With Java EE 6, Java Enterprise has changed. A new JSR defines a so-called managed bean (don't confuse with JSF managed beans) as a sort of minimum component that can still benefit from the container in terms of dependency injection and lifecycle management. This means: If you have a component and "just" want to use DI and let the container control its lifecycle, you do not need to use EJBs for it. You'll end up using EJBs if - and only if - you explicitly need EJB functionality like transaction handling, pooling, passivation and clustering.
This makes the answer to your question come in three parts:
Use #Inject over #EJB, the concept of CDI (a) works for all managed
beans (this includes EJBs) and (b) is stateful and therefore far
superior over pure #EJB DI
Are you sure that you need EJBs for your
components?
It's definitely worthwhile to have a look at the CDI
documentation
#Inject annotation is used for java beans(POJOs) while #EJB annotation is used for enterprise java beans. When a container inject an ejb provided by #EJB annotation to another bean it also controls that ejb's lifecycle, performs pooling for stateless beans and so on(when bean which is going to be injected is not deployed the reference will be null). If you use #Inject annotation CDI mechanism simply find and create an instance of injected resource like with new operator(if the implementation of interface which is going to be injected doesn't exist the reference will be null). You can use qualifiers with #Inject annotation to choose different implementation of injected interface.