I am a newbie for EJB and CDI.
Please help me understand what I am doing wrong here:
My code is as below and deployed in a WAR on JBoss WildFly 8:
#Stateless(name = "application.listDao")
public class ListDao extends BaseDao {
#Inject
private SomeOtherDao someOtherDao;
// some other methods
}
#Stateless
public abstract class BaseDao {
#Inject
protected EntityManager entityManager;
public List find( long id ) {
List list = new ArrayList<>();
// JPA stuff to perform operations
return list;
}
}
Now, I am injecting this ListDao in other WAR deployed on same wildfly instance:
#RequestScoped
public class ListReport {
#Inject
private ListDao listDao;
public List getReport(long id) {
// Here I am getting NullPointerException
List reportList = listDao.find(id);
return reportList;
}
}
I am getting listDao as null and hence getting NullPointerException.
CDI is enabled by placing empty beans.xml under WEB-INF folder.
As mentioned in one of the comments, you're #Inject'ing your EntityManager, however you haven't provided any evidence that you have a producer for it. There is no default producer method for EntityManager
If the other war is not in the same EAR (enterprise archive), this is not possible. Those are two completely separate deployments. The two deployments can't even see the classes of each other because of the classloader isolation.
You'd need to package the two wars into one ear in this case.
Related
I do have a EJB ActionService which I can inject into other EJBs, that is working fine.
Now I created another EJB:
#Stateless
public class ActionsPerDateDataSet extends ScriptedDataSetEventAdapter {
#EJB
ActionService actionService;
#Override
public void open(IDataSetInstance dataSet) {
actionService.foo() // However actionService is null here!
}
}
Where the ScriptedDataSetEventAdapter comes from another framework (BIRT).
However now my actionService is always null. I can not understand why
You should introduce the lib as ejbModule in ear file , so that container search the jar file and deploy it and inject it whenever it needs
ActionService has an interface with the #local annotation or if this is a class it has to have the annotation #LocalBean.
(this to be able to access the instance of it at runtime)
In case it is an interface and if it has multiple implementations you will have to reference the implementation you need using #EJB (beanName = "nameOfImplementation") in case it is a class where #LocalBean is used to use #EJB (name = "nameEjb")
Interface with #Local
Class with #LocalBean
In the aggregation class
Interface with multiple implementations #EJB(beanName="nameOfImplementation")
Class #EJB(name="nameEjb")
note: implements an interface for ActionService with #Local and test
note: add trace the console log to know if the class is being initialized as an ejb:ActionService
Did you try using CDI? I think it is worth a shot. You need to place an empty beans.xml inside your meta-inf folder and change #EJB to #Inject. But the only way this could work is if you have the external lib and your war/jar file in the same deployment unit.
if this does not work you will need to use JNDI for looking up your bean:
http://docs.oracle.com/javaee/6/tutorial/doc/gipjf.html
It is possible that the class ScriptedDataSetEventAdapter
can not be initialized in the EJB Container (First part of the cycle)
and as the initialization is not correct, the dependency injection (#EJB and #Inject) is not made.
What you could do is change the Design of your EJB and instead it's extends "ScriptedDataSetEventAdapter"
change it to a composition.
#Stateless
public class ActionsPerDateDataSet {
ScriptedDataSetEventAdapter scriptedDataSetEventAdapter;
#EJB
ActionService actionService;
#PostConstruct
public void init (){
try {
scriptedDataSetEventAdapter = new ScriptedDataSetEventAdapter();
} catch( AppException e){
}
}
#Override
public void open(IDataSetInstance dataSet) {
actionService.foo() // However actionService is null here!
}
}
I'm using Eclipse with Glassfish for my first steps in Java EE. I've created three eclipse projects (JPA project, EJB project, Web project). I've created a local EJB bean TestBean with a local interface TestBeanLocal:
#Stateless
#LocalBean
class TestBean implements TestBeanLocal {
#Override
public void doSomething(List<JPAEntity> myEntities) {
for(JPAEntity a : myEntities) {
}
}
}
and a ManagedBean that uses the EJB:
#MangagedBean
public class MyBean {
#EJB
private TestBeanLocal testBean;
#PostConstruct
private void init() {
//load JPAEntity from Database
List<JPAEntity> myEntities = ....
testBean.doSomething(myEntities);
}
}
My problem is that I get a ClassCastException at the for loop in the TestBean.
java.lang.ClassCastException: us.mypackage.jpa.JPAEntity cannot be cast to us.mypackage.jpa.JPAEntity
I found another stackoverflow question that says that this error message is because of two different classloaders. How can I fix this? Can I tell EJB to use the same classloader that my webproject uses?
It seems that the entity jar is located in both war and ear
Try to remove the entity jar from the war library
War should see the ear libraries file
HTH
I'm trying to use CDI for the first time. While I have successfully injected one EJB inside another using #EJB, I can't get the #Inject annotation to work.
#Stateless
public class AccountDaoImpl implements AccountDAO {
#Inject
private MultiTenantEntityManagerImpl mtem; //always null
}
And the multi-tenancy entity manager looks like this:
#Default
public class MultiTenantEntityManagerImpl {
.....
}
I've created a beans.xml file (empty) but and shoehorned it into the META-INF folder in the built jar file. Still no joy.
I'm sure it's something simple. I'm running in jboss 5.0.1.GA.
Update
So it looks like the #Inject annotation is not supported in jboss 5.
An alternative is to use the #EJB annotation, but this isn't working either:
#Stateless
public class AccountDaoImpl implements AccountDAO {
#EJB
private MultiTenantEntityManager mtem; //still null!
}
Weirdly, in another EJB, this exact declaration of the entity manager is working fine.
in my case i was missing subsystem in the standalone
It looks like, in jboss 5 at least, an #EJB annotation will only be respected if both the following conditions hold:
The class in which you're using it is an EJB
The class is retrieved from the container somehow (eg JNDI), rather than being simply instantiated via a constructor.
I'm trying to figure out how to setup a Service/Dao layer in my application. I've found a few dozen resources all with different ways on how to do it and decided to follow the model found here: How should EntityManager be used in a nicely decoupled service layer and data access layer?
I can't figure out what I'm missing that's causing this NPE.
Usage:
#Path("/helloworld")
public class MyController {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
WorkflowService workflowService = new WorkflowService();
workflowService.save(workflow);
return "Workflow ID:";
}
}
My Dao:
#Stateless
public class WorkflowDao {
#PersistenceContext(unitName = "unit")
private EntityManager entityManager;
public int save(Workflow workflow) {
entityManager.persist(workflow);
return workflow.getId();
}
}
My Service:
#Stateless
public class WorkflowService {
#EJB
WorkflowDao workflowDao;
public int save(Workflow workflow) {
int id = workflowDao.save(workflow); //throws NullPointerException because workflowDao is null
return id;
}
}
This is my first time setting up a Java project (only have worked on 1 before and it used Spring) so please keep that in mind if this looks horribly wrong.
WorkflowDao is not an EJB, it's a POJO with a#Stateless annotation. So naturally, injecting it with #EJB fails, creating a null workflowDao attribute and eventually producing a NullPointerException.
To make WorkflowDao into a full-fledged EJB, besides having a #Stateless or #Stateful annotation it needs to implement a local, remote or both interfaces, and those interfaces must be annotated respectively with #Local and #Remote. Please refer to the tutorial for details.
Also, quite possibly (this can be application server-dependent) you'll have to register the EJB in the application's xml descriptor files - for instance, in web.xml's <ejb-local-ref> element.
As a side note - it's not a good idea to use an EJB as a DAO, an EJB is typically used for implementing business logic (true, persist/merge operations can be called from here) but the actual persistence layer nowadays is implemented using JPA. In other words, WorkflowService should be the EJB service, there's no need to inject an EJB into it, and there's no need for a separate DAO layer - JPA entities fulfill this role.
If you instantiate your WorkflowService manually, the container wont perform any injection, since your WorkflowService is not managed by the Container.
I suggest you:
Annotate your Jax-RS Resource #Stateless
Inject your WorkfloService via #EJB as a member
Implementing a Local or Remote Interface is not necessary anymore
#Path("workflows")
#Stateless
public class WorkFlowResource{
#EJB
WorkflowService workflowService;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String TestRequest() {
Workflow workflow = new Workflow();
workflow.setName("test");
workflowService.save(workflow);
return "Workflow ID:";
}
}
I'm trying to inject a Stateless EJB into my JAX-RS webservice via annotations. Unfortunately the EJB is just null and I get a NullPointerException when I try to use it.
#Path("book")
public class BookResource {
#EJB
private BookEJB bookEJB;
public BookResource() {
}
#GET
#Produces("application/xml")
#Path("/{bookId}")
public Book getBookById(#PathParam("bookId") Integer id)
{
return bookEJB.findById(id);
}
}
What am I doing wrong?
Here is some information about my machine:
Glassfish 3.1
Netbeans 6.9 RC 2
Java EE 6
Can you guys show some working example?
I am not sure this is supposed to work. So either:
Option 1: Use the injection provider SPI
Implement a provider that will do the lookup and inject the EJB. See:
#EJB injection.
Example for com.sun.jersey:jersey-server:1.17 :
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import javax.ejb.EJB;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;
/**
* JAX-RS EJB Injection provider.
*/
#Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) return null;
try {
Class c = (Class)t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue() {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Option 2: Make the BookResource an EJB
#Stateless
#Path("book")
public class BookResource {
#EJB
private BookEJB bookEJB;
//...
}
See:
How to Combine REST Services with EJB 3.1
EJB 3.1 And REST - The Lightweight Hybrid
Option 3: Use CDI
#Path("book")
#RequestScoped
public class BookResource {
#Inject
private BookEJB bookEJB;
//...
}
See:
Injecting an EJB from a jar into a jax-rs class in a war
This thread is rather old, nevertheless i fought the same problem just yesterday. Here is my solution:
Just make the BookResource a managed bean through #javax.annotation.ManagedBean at class level.
For this to work you need to enable CDI with a beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>
This file needs to be in WEB-INF if the BookResource is part of a war file. If the BookResource is packaged with the ejbs put it into META-INF.
If you want to use #EJB you're done. If you want to inject the EJB through #Inject than a beans.xml must be put into the ejbs jar file into META-INF as well.
What you're doing: You're just telling the container that the resource should be container managed. Therefor it supports injection as well as lifecycle events. So you have your business facade without promoting it to an EJB.
You don't need to extend javax.ws.rs.core.Application for this to work. BookResource is as a root resource automatically request scoped.
Tested with Glassfish 3.1.2 and a maven project.
Happy coding.
You shall be able to do injection in JAX-RS resource without making it EJB or CDI component. But you have to remember that your JAX-RS resource must not be singleton.
So, you setup your application with this code. This makes BookResource class per-request JAX-RS resource.
#javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public InjectionApplication() {
// no instance is created, just class is listed
classes.add(BookResource.class);
}
#Override
public Set<Class<?>> getClasses() {
return classes;
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
With this setup, you are letting JAX-RS to instantiate BookResource for you on per-request basis and also inject all the required dependencies. If you make BookResource class singleton JAX-RS resource, this is, you put in getSingletons
public Set<Object> getSingletons() {
singletons.add(new BookResource());
return singletons;
}
then, you created instance which is not managed by JAX-RS runtime and nobody in container cares to inject anything.
Unfortunately, my answer is too long for a comment, so here goes. :)
Zeck, I hope that you are aware of what exactly you are doing by promoting your bean to an EJB, as suggested by Pascal. Unfortunately, as easy as it is nowadays with Java EE to 'make a class an EJB', you should be aware of the implications of doing so. Each EJB creates overhead along with the additional functionality it provides: they are transaction aware, have their own contexts, they take part in the full EJB life cycle, etc.
What I think you should be doing for a clean and reusable approach is this: extract the access to your servers services (which hopefully are accessed through a SessionFacade :) into a BusinessDelegate. This delegate should be using some kind of JNDI lookup (probably a ServiceLocator - yes, they are still valid in Java EE!) to access your backend.
Okay, off the record: if you really, really, really need the injection because you do not want to write JNDI access manually, you could still make your delegate an EJB, although it ... well, it just feels wrong. :)
That way at least it will be easy to replace it later with something else if you do decide to switch to a JNDI lookup approach...
I was trying to do the exact same thing. I'm using EJB 3.1 and have a deployed my app as an EAR with separate EJB project. As Jav_Rock pointed out, I use context lookup.
#Path("book")
public class BookResource {
#EJB
BookEJB bookEJB;
public BookResource() {
try {
String lookupName = "java:global/my_app/my_ejb_module/BookEJB";
bookEJB = (BookEJB) InitialContext.doLookup(lookupName);
} catch (NamingException e) {
e.printStackTrace();
}
}
#GET
#Produces("application/xml")
#Path("/{bookId}")
public Book getBookById(#PathParam("bookId") Integer id) {
return bookEJB.findById(id);
}
}
See the link below for very useful JNDI look up tips
JNDI look up tips
Arjan is right. I created another class to initialize the EJB instead of creating a bean for RS
#Singleton
#LocalBean
public class Mediator {
#EJB
DatabaseInterface databaseFacade;
to avoid null pointer with:
#Path("stock")
public class StockResource {
#EJB
DatabaseInterface databaseFacade;
...
it actually works on GF
I have the same problem, and I solved it calling te EJB by a context lookup (the injection was impossible, I had the same error NullPointerException).