Search code examples
tomcatguicespring-jdbcjersey-2.0hk2

Using Guice with embedded Tomcat?


I have a jersey 2 project with Guice used for DI (via hk2 bridge). Spring JDBC is used for DB calls and is configured via Guice. I'm running it locally with embedded tomcat. This setup works fine for the application i.e. i'm able to access database in my jersey resources

Now I want to write test cases for the application where I need database access for initial setup, but I'm getting NullPointerException on injected objects.

Main file (here inject gives null value)

public class StartApp {
    @Inject
    private JdbcTemplate jdbcTemplate;

    public static void main(String[] args) throws Exception {
        startTomcat();
    }

    private static void startTomcat() throws Exception {
        String webappDirLocation = "src/main/webapp/";
        Tomcat tomcat = new Tomcat();
        String webPort = System.getProperty("app.port", "8080");
        tomcat.setPort(Integer.valueOf(webPort));
        tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
        tomcat.start();
        new StartApp().initDatabase();
        tomcat.getServer().await();
    }

    public void initDatabase() throws Exception {
        String sql = new String(Files.readAllBytes(Paths.get(StartApp.class.getClassLoader().getResource("db_base.sql").toURI())), "UTF-8");
        jdbcTemplate.execute(sql);
    }
}

JdbcTemplate inject fails here only. In the actual jersey resources, it works fine.

web.xml (showing guice part only)

<filter>
    <filter-name>Guice Filter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Guice Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<listener>
    <listener-class>MyGuiceServletContextListener</listener-class>
</listener>

MyGuiceServletContextListener

public class MyGuiceServletContextListener extends GuiceServletContextListener {
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new AbstractModule() {

            @Override
            protected void configure() {
                bind(JdbcTemplate.class).toProvider(JdbcTemplateProvider.class).in(Scopes.SINGLETON);
            }
        });
    }
}

JerseyConfig

public class JerseyConfig extends ResourceConfig {
    @Inject
    public JerseyConfig(ServiceLocator serviceLocator, ServletContext servletContext) {
        packages("resources");

        GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
        GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
        guiceBridge.bridgeGuiceInjector((Injector) servletContext.getAttribute(Injector.class.getName()));
    }
}

Solution

  • Since tomcat starts in a different process, guice injector created in Jersey App is not accessible in StartApp. Guice injector have to be created in StartApp to get JdbcTemplate instamnce

    JdbcTemplate jdbcTemplate = Guice.createInjector(new PaymentGatewayModule()).getInstance(JdbcTemplate.class);