Dependency injection not working as expected (Tomcat9, Weld, RESTEasy)

Viewed 406

I'm building a Java web application based on JAX-RS running on Tomcat 9 and I'd like to use dependency injection for instantiating objects.

Strangely, when I use @Inject inside a Listener class (class annotated with @WebListener) - the injection work as expected. When I use @Inject inside a REST endpoint (class annotated by @Path) - then the injection doesn't work and I get NullPointerException.

My question: Can anyone explain to me why is the CDI behaving differently in these different contexts?

The listener code is executed during server startup. The endpoint code has to be invoked by an incoming HTTP GET call on /hello. That would point to a different scopes of both examples. But trying to mark the class being injected with any scope annotation did not help.

Also, when I try to call CDI.current().select(HelloProvider.class).get() from the REST endpoint class, I get a valid instance of my provider from CDI.

Here's some details of my setup:

pom.xml

...
<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-jaxrs</artifactId>
  <version>3.13.2.Final</version>
</dependency>
<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-servlet-initializer</artifactId>
  <version>3.13.2.Final</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.jboss.weld.servlet</groupId>
  <artifactId>weld-servlet-shaded</artifactId>
  <version>3.1.5.Final</version>
</dependency>
<dependency>
  <groupId>org.jboss</groupId>
  <artifactId>jandex</artifactId>
  <version>2.2.2.Final</version>
</dependency>
<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-cdi</artifactId>
  <version>3.13.2.Final</version>
</dependency>
...

WEB-INF\beans.xml

<?xml version="1.0"?>
<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>

WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3_1.xsd" version="3.1">

  <display-name>Hello World</display-name>
</web-app> 

Class I want to inject with CDI

public class HelloProvider {

  public String getHello() {
    return "Hello";
  }
}

Listener implementation

@WebListener
public class HelloApplicationListener implements ServletContextListener {

  @Inject
  private HelloProvider provider;
  
  @Override
  public void contextInitialized(ServletContextEvent event) {
    System.out.println("listener says: " + provider.getHello()); // works fine
  }

  @Override
  public void contextDestroyed(ServletContextEvent arg0) {}

}

Endpoint implementation

@Path("/hello")
public class HelloEndpoint {

  @Inject
  private HelloProvider provider;
  
  @GET
  public Response getHello() {   
    System.out.println("enpoint says: " + provider.getHello()); // throws NPE
    HelloProvider instance = CDI.current().select(HelloProvider.class).get(); // this give me the provider instance
    return Response.ok().build();
  }
}
0 Answers
Related