javaguicejersey-2.0hk2jersey-test-framework

Jersey Test Framework & HK2-Guice bridge


There are REST web service based on Jersey 2.23.2 & Guice 3.0. To use Guice it is necessary to adjust the hk2-guice bridge (I'm using 2.5.0-b07). Everything works fine until I have tried to test the service using Jersey Test Framework. Can't configure hk2-guice bridge for tests.

My test:

public class SomeTest extends JerseyTestNg.ContainerPerClassTest {

    @Override
    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
        return new GrizzlyWebTestContainerFactory();
    }

    @Override
    protected Application configure() {
        return super.configure(); // cant't configure
    }

    @Test
    public void test() {
        Assert.assertEquals(1, 1);
    }
}

I can't configure test in SomeTest.configure() just returning new JerseyConfiguration() (see below) because JerseyConfiguration's constructor expected ServiceLocator's object.

Even if it were possible to return an object of class `JerseyConfiguration` - I'm not sure that my test would work because some filters and listener are defined in the web.xml file.

How to configure the test taking into account all filters, listener and hk2-guice bridge?


Web service details

Dependencies section from build.gradle:

def jerseyVersion = '2.23.2'
def hk2Version = '2.5.0-b07'
def giuceVersion = '3.0'

dependencies {
    compile "javax.servlet:javax.servlet-api:3.1.0"
    //jersey
    compile "org.glassfish.jersey.core:jersey-server:${jerseyVersion}"
    compile "org.glassfish.jersey.containers:jersey-container-servlet:${jerseyVersion}"
    //hk2
    compile "org.glassfish.hk2:guice-bridge:${hk2Version}"
    //guice
    compile "com.google.inject:guice:${giuceVersion}"
    compile "com.google.inject.extensions:guice-servlet:${giuceVersion}"
}

File web.xml:

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

    <display-name>REST API App</display-name>

    <listener>
        <listener-class>com.example.core.JerseyGuiceServletContextListener</listener-class>
    </listener>

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

    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>jerseyFilter</filter-name>
        <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.example.core.JerseyConfiguration</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>jerseyFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

Class JerseyGuiceServletContextListener:

public class JerseyGuiceServletContextListener extends GuiceServletContextListener {
    static Injector injector;

    @Override
    protected Injector getInjector() {
        injector = Guice.createInjector(new JerseyServletModuleConfig());
        return injector;
    }
}

Class JerseyServletModuleConfig:

class JerseyServletModuleConfig extends ServletModule {
    @Override
    protected void configureServlets() {
        bind(HeyResource.class).in(Scopes.SINGLETON);
    }
}

Class JerseyConfiguration:

package com.example.core;

import com.google.inject.Injector;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.ResourceConfig;
import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;

import javax.inject.Inject;
import javax.servlet.ServletContext;

class JerseyConfiguration extends ResourceConfig {
    @Inject
    public JerseyConfiguration(ServiceLocator serviceLocator, ServletContext servletContext) {
        packages("com.example.ws");
         GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
         GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
         guiceBridge.bridgeGuiceInjector(JerseyGuiceServletContextListener.injector);
    }
}

Solution

  • just overrode configureDeployment() & modified configure() methods in test

    public class SomeTest extends JerseyTestNg.ContainerPerClassTest {
    
        @Override
        protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
            return new GrizzlyWebTestContainerFactory();
        }
    
    @Override
        protected Application configure() {
            return new ResourceConfig()
                    .packages("com.example.ws")
                    .register(GensonCustomResolver.class);
        }
    
        @Override
        protected DeploymentContext configureDeployment() {
            Application application = configure();
    
            return ServletDeploymentContext.builder(application)
                    .addListener(JerseyGuiceServletContextListener.class)
                    .addFilter(GuiceFilter.class, "guiceFilter")
                    .addFilter(ServletContainer.class, "jerseyFilter", new HashMap<String, String>(){{
                        put("javax.ws.rs.Application", JerseyConfiguration.class.getCanonicalName());
                    }})
                    .build();
        }
    
        @Test
        public void test() {
            Assert.assertEquals(1, 1);
        }
    }
    

    & add web.xml to test classpath.