简体   繁体   中英

Dependency injection through constructor does not work for EJB bean

My app is being deployed on to IBM WebSphere. I have a simple service and I'd like to know how dependency injection works in this case.

// stateless EJB
@Stateless
public class UserService {

    private UserDAO userDAO;

    // btw, UserDAO is stateless EJB as well
    @Inject
    public UserService(UserDAO userDAO) {
        this.userDAO = userDAO;    
    }

    // biz methods ...
}

It fails with the following error:

[ERROR ] CWWKZ0002E: An exception occurred while starting the application my-app. The exception message was: com.ibm.ws.container.service.state.StateChangeException: com.ibm.ws.cdi.CDIException: com.ibm.wsspi.injectionengine.InjectionException: com.ibm.ejs.container.EJBConfigurationException: EJB class com.demo.app.UserService must have a public constructor that takes no parameters

I remember there was something in EJB spec that says: the class must have a public constructor that takes no parameters and it makes sense for me that the bean instance is first instantiated by the container and afterward dependency injection is done .

On the other hand, I've found this in WELD docs:

First, the container calls the bean constructor (the default constructor or the one annotated @Inject), to obtain an instance of the bean.

And I am confused a little bit, why my EJB cannot be instantiated.

How is the EJB instance being created and dependencies injected when we have constructor injection point?

Any ideas? :)

the creation of EJB session beans is done by EJB container but it can choose to use CDI to provide EE resource injection but EJB resolution is delegated to the container

https://docs.jboss.org/weld/reference/2.1.0.Final/en-US/html/ri-spi.html says:

Alternatively, the integrator may choose to use CDI to provide EE resource injection. In this case, the EE_INJECT environment should be used, and the integrator should implement the Section A.1.4, “EJB services”, Section A.1.7, “Resource Services” and Section A.1.5, “JPA services”. ....
Weld registers resource injection points with EjbInjectionServices, JpaInjectionServices, ResourceInjectionServices and JaxwsInjectionServices implementations upfront (at bootstrap). This allows validation of resource injection points to be performed at boot time rather than runtime

if you interested in how CDI and EJB are integrated. you can have a look at the code of weld-EJB module and weld-integration(glassfish code)

So what happens is that you do not meet the requirements for initializing EJB beans.

CDI spec has some limitations on constructors - either no-args or one with @Inject . But there is also this chapter , which specifies that in EE, the set of rules is extended by what EJB session beans require.

And now we are getting into EJB spec which requires a no-arg constructor on a bean. This should be in chapter Enterprise Bean Class where it states

The class must define a public constructor that takes no arguments.

Now, finally moving on to whether this should work - eg can you have an EJB bean using CDI constructor injection? Well, let's have a look at CDI TCK, a set of tests that all implementation and containers have to pass in order to be able to claim they implement CDI. There, we can see this bean and this test using it - so yea, this can work, but you need to have both constructors.

EJBs are registered as CDI beans. But first they have to meet the requirements of the EJB spec.

I guess it works just by providing the no-args constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM