11 Replies Latest reply: Jul 31, 2013 10:04 PM by Adrian Cole RSS

Google Guice Extension

Jakub Narloch Novice

Some time ago I had this idea for creating a Google Guice extension as an alternative to CDI or Spring IOC. I didn't forgot about it but due to excess of activities it had to wait.

 

Recently I had made major update and the results can be found here https://github.com/jmnarloch/arquillian-extension-guice

 

Very briefly: The extension is quite similar to the Spring one. It alows for configuring Guice modules through annotation per each test case. Besides that it auto packages the Guice dependencies.

 

Example of test case:

 

@RunWith(Arquillian.class)
@GuiceConfiguration({EmployeeModule.class})
public class DefaultEmployeeServiceTestCase {

    @Deployment
    public static JavaArchive createTestArchive() {
        return ShrinkWrap.create(JavaArchive.class, "guice-test.jar")
                .addClasses(Employee.class,
                        EmployeeService.class, DefaultEmployeeService.class,
                        EmployeeRepository.class, DefaultEmployeeRepository.class,
                        EmployeeModule.class);
    }

    @Inject
    private EmployeeService employeeService;

    @Test
    public void testGetEmployees() {
        List<Employee> result = employeeService.getEmployees();

        assertNotNull("Method returned null list as result.", result);
        assertEquals("Two employees were expected.", 2, result.size());
    }
}

 

 

So the question is do we need it and do we want it?

  • 1. Re: Google Guice Extension
    Jakub Narloch Novice

    One major update on this issue:

     

    Since the Guice Injector is being configured based on the module instances instead of just "static" configuration classes like in Spring, so in some cases it would be preferable to instantiate the Injector with instantiated and fully configured modules.

     

    So I would like to propose an alternative way for enabling the Guice capabilitites on the test case, by giving the user complete control over how the Injector will be created. Example:

     

     

    @RunWith(Arquillian.class)
    public class CustomInjectorTestCase {
    
        @Deployment
        public static JavaArchive createTestArchive() {
            return ShrinkWrap.create(JavaArchive.class, "guice-test.jar")
                    .addClasses(Employee.class,
                            EmployeeService.class, DefaultEmployeeService.class,
                            EmployeeRepository.class, DefaultEmployeeRepository.class,
                            EmployeeModule.class);
        }
    
        @GuiceInjector
        public static Injector createInjector() {
    
            return Guice.createInjector(new EmployeeModule());
        }
    
        @Inject
        private EmployeeService employeeService;
    
        @Test
        public void testGetEmployees() {
    
            List<Employee> result = employeeService.getEmployees();
    
            assertNotNull("Method returned null list as result.", result);
            assertEquals("Two employees were expected.", 2, result.size());
        }
    }
    
    

     

     

    The above code looks pretty much similar with one major difference, the static createInjector method annotated with @GuiceInjector. This way user can have complete control how the Injector can be instantiated and the actuall type that will be used. One of potential usage is for example registering JpaPersistModle which takes as the argument name of the JPA persistence unit.

     

            return Guice.createInjector(new EmployeeModule(), new JpaPersistModle("jpa-test-unit"));
    

     

  • 2. Re: Google Guice Extension
    Jakub Narloch Novice

    I'm finally closing to finish this extension entirely. So within days, it could be finally released.

  • 3. Re: Google Guice Extension
    Loïc Lacombe Newbie

    Just so that you don't get desperate that people have no interest: your stuff looks really cool. It's kinda counterintuitive to use Guice and CDI at the same time, but CDI is so verbose that your lib comes as a god sent. I'm spending all my time saying "damn, it would be so easier to use plain Guice for that part".

    Thanks, I'll try and evaluate your extension.

     

    Sure it perverts the core principles of CDI, but I don't care as long as I can reduce the cost of using CDI

  • 4. Re: Google Guice Extension
    Adrian Cole Newbie

    Can you explain how this could (or does) interact with the guice servlet ecosystem?

     

    At Netflix, we use karyon, which is an extension of the guice servlet filter

     

    ex.


        <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>

     

        <listener>

            <listener-class>com.netflix.karyon.server.guice.KaryonGuiceContextListener</listener-class>

        </listener>

     

    I'm hoping to be able to write a test that can inject something bound by one of these injectors.  Any ideas of how this could interact with the guice extension?

     

    -A

  • 5. Re: Google Guice Extension
    Jakub Narloch Novice

    Hi Adrian,

     

    At the moment we don't have such support in the Guice extension. Although I already done similar thing in the Spring extension, so this is definetly doable. In Guice the only difference would be the fact that this would be more "invasive" and would require some way to capture the injector and bind it with the executing thread, the same injector can be accessed from the test afterwards. In Spring this is provieded out of the box through WebApplicationContextUtils. I could try to develop such functionality.

  • 6. Re: Google Guice Extension
    Jakub Narloch Novice

    I had quick look at the Guice Servlet source code and I think we can go with two different aproaches:

     

    • Extension ServletContextListener

     

    This can be done on two ways.

    In the first approach we can introduce class that should replace the the GuiceServletContextListener and should be used instead of it. Although this can won't be usefull with the existing code and won't be usefull with integrating with extension that are based on the Guice Servlet module.

     

    Example:

     

     

    public class TestGuiceServletConfig extends ArquillianGuiceServletContextListener {
      @Override
      protected Injector getInjector() {
         ...
      }
    }
    

     

     

    web.xml

     

    <listener>

      <listener-class>com.example.test.TestGuiceServletConfig</listener-class>
    </listener>

     

    An alternative approach would be relay on the order of the executing listeners and add listener that would "capture" the injector created by the oder context listeners. The drowback would be that it would have to declared as a last listener in the web.xml, so this might be a bit error prone solution.

     

    Example:

     

    <listener>

       <!-- Application injector configuration -->
     
    <listener-class>com.example.test.GuiceServletConfig</listener-class>
    </listener>

     

    <listener>

       <!-- Test injector configuration -->
     
    <listener-class>org.jboss.arquillian.guice.servlet.ArquilllianGuiceServletContextListener</listener-class>
    </listener>

     

     

    • The second possible approach would be to introdce Arquillian Guice filter, that should be used instead of the standard one.

     

    For instance:

     

      <filter>

        <filter-name>arquillianGuiceFilter</filter-name>
       
    <filter-class>org.jboss.arquillian.guice.servlet.ArquiilianGuiceFilter</filter-class>
     
    </filter>

     
    <filter-mapping>
       
    <filter-name>arquillianGuiceFilter</filter-name>

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

     

     

    What do you think? Which solution would best to implement?

  • 7. Re: Google Guice Extension
    Adrian Cole Newbie

    +1 to ArquiilianGuiceFilter


    It is a simple string replacement on web.xml, and could be automated in shrinkwrap or our use of it.

     

    Thanks for having a look!

  • 8. Re: Google Guice Extension
    Jakub Narloch Novice

    Hi again,

     

    I have prototyped the implementation. Now I'm going to polish it and I think that later this week I can push that to the repository.

  • 9. Re: Google Guice Extension
    Jakub Narloch Novice

    What do you think about something like this: https://github.com/arquillian/arquillian-extension-guice/pull/2/files#L18R47?

     

    Basicly all you will have to do is to define the ArquillianGuiceFilter in your web.xml, like:

     

        <filter>

            <filter-name>guiceFilter</filter-name>

            <filter-class>org.jboss.arquillian.guice.api.servlet.ArquillianGuiceFilter</filter-class>

        </filter>

     

     

        <filter-mapping>

            <filter-name>guiceFilter</filter-name>

            <url-pattern>/*</url-pattern>

        </filter-mapping>

     

     

    And afterards annotated your test with @GuiceWebConfiguration and that's it, you can automaticly inject any dependency that has been created within your servlet container. So you should be able to inject servlets, filters and any other Guice configured instances.

     

    Example code:

     

     

    
    @GuiceWebConfiguration
    @RunWith(Arquillian.class)
    public class WebInjectorTestCase {
    
    
        /**
         * Creates the test deployment.
         *
         * @return the test deployment
         */
        @Deployment
        public static Archive createTestArchive() {
            return ShrinkWrap.create(WebArchive.class, "guice-test.war")
                    .addClasses(Employee.class,
                            EmployeeService.class, DefaultEmployeeService.class,
                            EmployeeRepository.class, DefaultEmployeeRepository.class,
                            EmployeeModule.class, EmployeeModuleContextListener.class)
                    .addAsWebInfResource("WEB-INF/web.xml", "web.xml");
        }
    
    
        /**
         * <p>The injected {@link EmployeeService}.</p>
         */
        @Inject
        private EmployeeService employeeService;
    
    
        /**
         * <p>Tests the {@link EmployeeService#getEmployees()}</p>
         */
        @Test
        public void testGetEmployees() {
    
    
            List<Employee> result = employeeService.getEmployees();
    
    
            assertNotNull("Method returned null list as result.", result);
            assertEquals("Two employees were expected.", 2, result.size());
        }
    }
    

     

     

    I will ask for review and I think that after this change goes to master we could have Alpha 2 release. Stricly speaking there is no road map for the Guice Extension, but in the exchange we can have pretty often releases

  • 10. Re: Google Guice Extension
    Adrian Cole Newbie

    Good job.  I can test this (in karyon) as soon as you tell me the release is out.

  • 11. Re: Google Guice Extension
    Adrian Cole Newbie

    I'm having build infra issues testing the snapshot which aren't likely to resolve in the next day or two.  Please release another alpha (beta etc), and I'll give it a go!