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.
Related
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?
I have 2 EJB module projects and I want from one of the projects to call a stateless no-interface bean from another project. I want to inject the bean to be called using the EJB annotation. The problem is the injection doesn't work(I use NetBeans 7.4 if that is relevant).
The stateless no-interface EJB being called:
package standalonepackage;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
#Stateless
#LocalBean
public class StandaloneBean {
private static final String message="Greetings!";
public String returnMessage(){
return message;
}
}
The interface of the bean that calls the bean above(this ejb resides in another ejb module project)
#Local
public interface ExampleBeanLocal {
public String getMessage();
}
The implementation of the interface:
#Stateless
public class ExampleBean implements ExampleBeanLocal {
#EJB
private StandaloneBean standaloneBean;
#Override
public String getMessage() {
return String.format("Me - and the second message %s", standaloneBean.returnMessage());
}
}
I also have a main class that just calls the ExampleBean getMessage method(MainClass is located in the second ejb module project):
public class MainClass {
private static ExampleBeanLocal instance = new ExampleBean();
public static void main(String[] args) {
System.out.println(instance.getMessage());
}
}
What am I missing?
First of all if you want to access your business logic as EJB then first you will need to deploy the EJB in an application server. During the deployment process the application server will create something called the JNDI name which is like a gatepass to access your business logic.
Secondly, there are two ways you can invoke an EJB.
1. Creating ContextLookup using JNDI name
2. Using Context Dependency Injection CDI (only within the same Container)
You cannot invoke an EJB using CDI from a POJO ( since it is not contained in any container and the EJB your accessing is in a different JVM ). If you want to access an EJB from a POJO you'll need to use #Remote and use the ContextLookup way of accessing an EJB, you can find more information here
http://wiki.netbeans.org/CreatingEJB3UsingNetbeansAndGlassfish
You need application server with EJB container to run this. Have a look at JBoss, Apache TomEE or something else.
you can use this way to run your jar GLASFISH_HOME/bin/appclient -client app.jar
before compiling your maven project mvn assembly:assembly
and add your main class in your pom.xml
When I try to access EJB from another module inside one Application I got NullPointerException.
I'll explain an example to be more exact.
EAR Structure following:
EAR
|
— core.jar (EJB-module with core EJB) — application core
|
— app.jar (another EJB-module with EJBs) — business logic here
|
— web.war (servlets)
At code.jar there is EJB:
#LocalBean
#Singleton
#Startup
public class AppInfo(){
private int counter;
public void incCounter(){
counter++;
}
public int getCounterValue(){
return counter;
}
}
At module app.jar we have Stateless EJB which tries to read counter.
#Stateless
public class SomeBean{
#EJB private AppInfo appinfo;
public void run(){
int counter = appInfo.getCounterValue(); // here method throws with NPE
System.out.println("Counter value is: "+counter);
}
}
At module web.war there is servlet that increment counter value for every request:
public class MyServlet extends HttpServlet{
#EJB private AppInfo appInfo;
protected void doPost(params){
appInfo.incCounter();
...
other code
}
}
While debugging, I detected that:
At servlet injection work well: when entering doPost() appInfo is Proxy object for AppInfo EJB.
At SomeBean there is NPE: at run() entry point value of appInfo = null.
How I do correctly inject EJB from core.jar to another EJB from App?
P.S. I deploy EAR to JBoss 6.1 EAP
P.S.S. I also tried using #Remote: not working (appInfo is still equals null)
I think Local should work - this is in the same Application.
Try the fully qualified package name:
#EJB(beanName="my.package.AppInfo")
It seems to be that this is a JBoss deployment ordering issue. When the container creates a new instance of SomeBean and tries to inject the AppInfo bean, this one hasn't been created/deployed yet.
Try to rename your jars file, indicating the correct dependency order. (eg. a_core.jar and b_app.jar).
Other possibility could be to inject the singleton bean on a setter method.
To access EJB from another module, you need to do with following ways:
Use Remote access instead of Local access. or
Use JNDI.
For details, read this tutorial.
#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