0

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

Community
  • 1
  • 1
Chris
  • 712
  • 3
  • 16
  • 39

2 Answers2

0

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.

Steve C
  • 18,876
  • 5
  • 34
  • 37
0

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();
    }
}
  • I used @EJB to inject beans in other project that I've done with JAX-RS 1.1. But my current project uses JAX-RS 2.0, see the resteasy-jaxrs dependency. Will try to solve the issue tomorrow, any input welcomed. – Chris Apr 20 '16 at 12:30
  • What application server and version are you using? I'm assuming JBoss EAP or Wildfly, since you declared RestEasy and not Jersey as a dependency. – RafaelHamasaki Apr 20 '16 at 14:12
  • If you want to use that RestEasy version, and not the one provided by JBoss (which might be an older, JAX-RS 1.1 compliant version), you'll also have to exclude the module from deployment. See: [link](https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6/html/Development_Guide/Exclude_a_Subsystem_from_a_Deployment.html) [link](https://docs.jboss.org/author/display/WFLY8/Class+Loading+in+WildFly) – RafaelHamasaki Apr 20 '16 at 14:20
  • You'll also have to remove `provided` from your dependency, so that it's packed with your application. – RafaelHamasaki Apr 20 '16 at 14:27
  • I am running Wildfly 10.0.final and it comes with resteasy-jaxrs, that why I have . No point including a separate lib in the war file when its already included in the application server. – Chris Apr 21 '16 at 07:30
  • It would actually be a point if you were trying to use a different version than the one provided by the application server. What I was trying to say is that, if you use a JBoss application server (EAP or AS/Wildfly), the version of RestEasy declared in the pom would be irrelevant if you don't also exclude the provided RestEasy module in `jboss-deployment-structure.xml` (and at that point you would have to alter the dependency scope to `compile` in the POM). – RafaelHamasaki Apr 21 '16 at 12:27
  • As such, the causal relation that you establish in your first comment (that your declared RestEasy pom dependency is JAX-RS 2.0, therefore your application uses version 2.0) is incorrect. – RafaelHamasaki Apr 21 '16 at 12:27