javaaopguicetomcat8guice-servlet

Google Guice MethodInterceptor under Tomcat 8.5


We wan't to use aop methodinterceptors using guice as provider under tomcat 8.5. We are currently already using interceptors and guice in our Java-FX applications without any problems.

Trying to do the same under Tomcat does not work. Objects are injected into servlets via guice, but the annotated methods of those objects are not bound to the interceptor. It looks as if guice might think that cglib/asm are not available and revert to none-aop.

Are there any special preconditions the servlet containers needs to fullfil in order to use guice's aop? As stated above the same configuration of guice/cglib/asm works for us in none webapp projects.

@Singleton
public class TestServlet extends HttpServlet {

    @Inject
    X                           x;

    public TestServlet() {
        System.out.println("constructor");
        try {
            throw new IOException();
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)
        throws ServletException, IOException {
        testMethod(resp);
    }

    protected void testMethod(final HttpServletResponse resp) throws IOException {
        x.test(resp);
    }
}

We wan't X in our servlet to contain methods that are intercepted. By putting the throw/catch thing in the constructor we verified that the constructor is called through guice.

public class X {
    @Y
    public int test(final ServletResponse res) throws IOException {
        res.getWriter().write("123");
        return 1;
    }
}


public class TestInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(final MethodInvocation arg0) throws Throwable {
        System.out.println("METHOD INTERCEPTOR " + arg0);
        return arg0.proceed();
    }
}


public class Module extends AbstractModule {
    @Override
    protected void configure() {
        System.out.println("TestInterceptor configuration");
        bindInterceptor(Matchers.any(), Matchers.annotatedWith(Y.class), new TestInterceptor());
    }
}


@WebListener
public class BootStrap extends GuiceServletContextListener {

...

    @Override
    protected Injector getInjector() {
    final Injector inject = Guice.injector(new Module(), new ServletModule() {
            @Override
            protected void configureServlets() {
                super.configureServlets();
                System.out.println("Injector");
                serve("/test2/*").with(TestServlet.class);
            }
        });
        return inject;
    }
}

The servlet is reachable and X is none-null but looking at it in the debugger it is clear no binary code modifications were done.

Are we missing somethings here? Can anyone link an example of a working guice (4+)/tomcat (8+)/aop example?

Edit

It turned out to be unrelated to the servlet container. The trouble was with guice itself. Sorry for the confusion, this problem was very hard to fence in. For those interested we opened an issue https://github.com/google/guice/issues/1094

Note that at the time of writing this is not accepted as a bug. It could also be that we missinterpreted the javadoc.


Solution

  • I've used Guice AOP with Tomcat before (though it was an older version of Tomcat) and AOP worked. (I can't link because it was proprietary code).

    One thing I notice looking at your posted code is that you are not using the GuiceFilter, which I believe is required.

    As stated here you need to configure it at the top of your web.xml like so:

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

    Edit based on comments: You shouldn't have to modify/hack the classloader to use Guice interceptors in a servlet container. They should work out of the box with no additional changes.