I am trying to inject and EJB 3.1 in one of my RESTful services. I've followed the post: Inject an EJB into JAX-RS (RESTful service) and tried all options except building an injection provider. The current solution that I am trying uses a combination of @RequestScoped
and @Inject
, but my injected bean variable is still null
. I have a beans.xml
in the /WEB-INF
folder.
How can I inject an EJB into my REST service class?
UserService
@Local
@Path("user/v1")
@Produces(MediaType.APPLICATION_JSON)
public class UserServiceV1 implements SystemLogger {
@Inject
private ApplicationBean appBean;
@GET
@Path("pingbean")
@Produces(MediaType.APPLICATION_JSON)
public Response pingAppBean() {
if(appBean == null) {
return Response.status(Response.Status.UNAUTHORIZED).entity("{\"faild\": \"App bean is null\"}").build();
}
String message = appBean.getHello();
return Response.status(Response.Status.OK)
.entity(message)
.build();
}
}
ApplicationBean
The SystemHandler
resides in jar module and is a standard class with business logic.
@Stateless
@Local
public class ApplicationBean implements ApplicationBeanLocal {
@Override
public String getHello() {
return "Hello from ApplicationBean";
};
}
JAX-RS configuration
@ApplicationPath("service")
public class ApplicationService extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(UserServiceV1.class);
resources.add(ApplicationBean.class);
resources.add(CorsFilterProvider.class);
return resources;
}
}
Exception
14:07:01,230 ERROR [io.undertow.request] UT005023: Exception handling request to /MyApp/service/user/v1/login: org.jboss.resteasy.spi.UnhandledException: java.lang.NullPointerException
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76) [resteasy-jaxrs-3.0.14.Final.jar:3.0.14.Final]
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:212) [resteasy-jaxrs-3.0.14.Final.jar:3.0.14.Final]
Resteasy /JAX-RS
I've added a CDI implementation for resteasy according to the documentation
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-cdi</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
EDIT: changed code details in the question and title
EJB 3.1 implies a Java EE 6 container implementation.
Java EE 6 implies JAX-RS 1.1.
JAX-RS 1.1 is only required to support @EJB injection of enterprise java beans.
JAX-RS 2.0 as provided in a Java EE 7 implementation supports @Inject for EJBs.
As Steve C answered, the proper way to inject an EJB in JAX-RS 1.1 is with the javax.ejb.EJB annotation. The REST service must also be an EJB for this to work. As such, you have to use the javax.ejb.Stateless annotation instead of javax.enterprise.context.RequestScoped.
The end result is as follows:
@Stateless
@Path("user/v1")
public class UserServiceV1 implements SystemLogger {
@EJB
private ApplicationBean appBean;
//etc.
}
EDIT
Your updated code doesn't deploy. Either have ApplicationBean
implement ApplicationBeanLocal
and inject the interface, or don't implement it and inject the class directly. With that corrected, I managed to run your example just fine.
Also, in ApplicationService
, you don't need to add ApplicationBean.class
. You only register there REST root resources and feature providers. @Local
is also unnecessary in the UserServiceV1
class, it's not an EJB.
Furthermore, it's beans.xml
, not bean.xml
(but this file is not necessary anymore from CDI 1.1 on).
See my testcode below:
pom.xml
dependencies for the jar module:
<dependencies>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
ApplicationBeanLocal.java
:
public interface ApplicationBeanLocal {
String getHello();
}
ApplicationBean.java
:
@Stateless
@Local
public class ApplicationBean implements ApplicationBeanLocal {
@Override
public String getHello() {
return "Hello from ApplicationBean";
}
}
pom.xml
dependencies for the JAX-RS application:
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-cdi</artifactId>
<version>3.0.14.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<!-- The jar-module containing ApplicationBean and ApplicationBeanLocal -->
<dependency>
<groupId>test</groupId>
<artifactId>testjar</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
TestApplication.java
:
@ApplicationPath("service")
public class TestApplication extends Application {
private final Set<Class<?>> resources = new HashSet<>();
public TestApplication() {
resources.add(UserServiceV1.class);
}
@Override
public Set<Class<?>> getClasses() {
return resources;
}
}
UserServiceV1.java
@Path("user/v1")
@RequestScoped
@Produces(MediaType.APPLICATION_JSON)
public class UserServiceV1 {
@Inject // Note that I'm referencing the interface, not the implementation
private ApplicationBeanLocal appBean;
@GET
@Path("pingbean")
@Produces(MediaType.APPLICATION_JSON)
public Response pingAppBean() {
final String message = appBean.getHello();
return Response.status(Response.Status.OK).entity(message).build();
}
}