htipk
htipk

Reputation: 109

CDI and Resource Injection with JAX-RS and Glassfish

I'm currently developing a JAX-RS Servlet which I then want to deploy in a Glassfish 4.1 Server (consequently the JAX-RS runtime is Jersey 2.x).

Instead of going with Spring for the configuration and DI stuff, I wanted to try out the Java EE way of doing this. However, neither CDI nor the injection of the datasource I configured in the Glassfish Server is working. But first of all here are the relevant things about the servlet.

Dependencies (are declared with version and scope in the parent pom - which is not the one you see here):

<dependencies>
    <!-- Java EE API -->
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
    </dependency>

    <!-- Jersey CDI support -->
    <dependency>
        <groupId>org.glassfish.jersey.ext.cdi</groupId>
        <artifactId>jersey-cdi1x</artifactId>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.ext.cdi</groupId>
        <artifactId>jersey-cdi1x-ban-custom-hk2-binding</artifactId>
    </dependency>

    <!-- Logging dependencies -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
</dependencies>

web.xml:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

<servlet>
    <servlet-name>Backend</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

    <!-- Disable Moxy JSON -->
    <init-param>
        <param-name>jersey.config.disableMoxyJson</param-name>
        <param-value>true</param-value>
    </init-param>

    <!-- Register resource classes -->
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>org.test.Service</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>Backend</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

</web-app>

beans.xml:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
   version="1.1" bean-discovery-mode="all">
</beans>

Service.java:

@Path("/")
@RequestScoped
public class Service {

    @Inject
    private DataProvider dataProvider;

    @Path("test")
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public Response test(){
        return Response.ok(dataProvider.getArticles()).build();
    }

}

SQLDataProvider.java:

@Default
@ApplicationScoped
@Singleton
@Path("singleton-bean")
public class SQLDataProvider implements DataProvider {

    @Resource(name = "jdbc/db_1")
    private DataSource dataSource;

    private SQLQueryFactory factory;

    @Override
    public List<Article> getArticles() {
        if(factory == null){
            factory = new SQLQueryFactory(new Configuration(new MySQLTemplates()), dataSource);
        }

        QArtikel artikel = QArtikel.artikel;
        List<String> names = factory.select(artikel.artikeltyp).from(artikel).fetch();

        return names.stream().map(Article::new).collect(Collectors.toList());
    }
}

If I deploy this servlet in the Glassfish Server and do a Request, the following exception is thrown:

javax.servlet.ServletException: A MultiException has 3 exceptions.  They are:
    1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=DataProvider,parent=SkiBazaarService,qualifiers={},position=-1,optional=false,self=false,unqualified=null,158365417)
    2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of org.skiclub.service.SkiBazaarService errors were found
    3. java.lang.IllegalStateException: Unable to perform operation: resolve on org.skiclub.service.SkiBazaarService

As you can see I already tried the solution of user G. Demecki from this post by including the two Jersey dependencies in my servlet - but with no success. I also tried the solution from Oracle, which was posted somewhere in this post. But this did not work for me as well.

I also saw a solution in which you specify the bindings from Types to Instances for the HK2 runtime in this post. I admit that I haven't tried it because I think that having to programmaticlly register the instances to be injected makes absolute nonsense of the idea behind DI.

But there also is another problem. If I modify the declaration of the DataProvider in the Service class to the following

private DataProvider dataProvider = new SQLDataProvider();

the problem with CDI vanishes but a NPE is thrown, since the DataSource I'm trying to get from JNDI is not injected into the instance of the SQLDataProvider. So it seems that the Resource Injection of Java EE also does not work in the JAX-RS Container. For this problem I did not find any possible solutions during my research.

I hope that someone can show me what I need to change in my configuration in order to make CDI and Resource Injection work with JAX-RS because at the moment, this seems impossible for me.

Kind Regards Pascal

Upvotes: 3

Views: 3844

Answers (1)

Jason Holmberg
Jason Holmberg

Reputation: 291

See this question:

Recource injection doesn't work with glassfish 4 while lookup works

Try looking up your Resource a different property, like mappedName as the above questions suggests.

 @Resource(mappedName = "jdbc/db_1")
 private DataSource dataSource;

Upvotes: 0

Related Questions