3

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

Community
  • 1
  • 1
htipk
  • 109
  • 3
  • 10
  • Is `jdbc/db_1` actually in JNDI. I assume you have the DataSource set up on GlassFish. Have you verified through the GlassFish JNDI browser that this is the correct JNDI address? I am little confused by the `@Path` annotation `SQLDataProvider`. Also, `@ApplicationScoped` and `@Singleton` seem a little redundant. – Jason Holmberg Sep 18 '15 at 20:14
  • Yes DataSource is available under that name. I just checked it in the admin console under JDBC Resources. In the corressponding list appears my DataSource and it states that it is available under the JNDI name jdbc/db_1. I also checked it using the "asadmin list-jndi-entries --context jdbc" command. The @Path annotation is from the solution Oracle published under this link http://docs.oracle.com/javaee/7/tutorial/jaxrs-advanced004.htm – htipk Sep 18 '15 at 20:26

1 Answers1

0

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;
Community
  • 1
  • 1
Jason Holmberg
  • 291
  • 2
  • 17
  • Thanks for the hint! However, it does not seem to work for me with the annotation (When I explicitly open the context and load the DataSource it works fine - but I still would like to get it to work using the annotation) ... Currently I think that the ServletContainer from Jersey is absolutely messing things up but I would be happy to have an expert on this topic correct me and show me the real reason why it does not work – htipk Sep 18 '15 at 21:14
  • So why are you using the Jersey ServletContainer or even including Jersey 1.x. GlassFish 4.* ships with Jersey 2. See http://docs.oracle.com/javaee/7/tutorial/jaxrs002.htm#GILIK section 29.2.7 – Jason Holmberg Sep 18 '15 at 21:33
  • I'm not using Jersey 1.x stuff. The ServletContainer is still contained in Jersey 2.x as you can see here https://jersey.java.net/apidocs/2.11/jersey/org/glassfish/jersey/servlet/ServletContainer.html – htipk Sep 18 '15 at 21:47
  • Regarding the use of the Servlet Container: The Container is just a Servlet 2+ conform way to hook up Jersey in the web.xml (https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.2). I did it this way because I did not want to create an Application subclass if I can also specify my Resource classes in the web.xml file – htipk Sep 18 '15 at 21:54
  • Fair enough. Have you tried just sticking to the Java EE API and using this to bootstrap your REST application: ` javax.ws.rs.core.Application /* ` – Jason Holmberg Sep 18 '15 at 22:02
  • The funny thing with this approach is that allthough jersey says it is one way to do it (https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.3) - the runtime does not seem to look up my Resource class so that I get a 404 Not Found when I try to do a request from my browser. This seems very odd but I definetly have a Glassfish 4.1 Server running and with that Servlet 3 support. – htipk Sep 18 '15 at 22:12
  • Perhaps simplify. It doesn't really seem like you need the Jersey Servlet Container. Roll back to the simplest possible configuration. Good Luck. – Jason Holmberg Sep 18 '15 at 22:29