3

I'm trying to print a "Hello, AOP!" message whenever Guice/AOP Alliance intercepts a method marked with a particular (custom) annotation. I have followed the official docs (a PDF that can be found here - AOP method interception stuff on pg. 11) and cannot get it to work, only compile.

First, my annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@BindingAnnotation
public @interface Validating {
    // Do nothing; used by Google Guice to intercept certain methods.
}

Then, my Module implementation:

public class ValidatingModule implements com.google.inject.Module {
    public void configure(Binder binder) {
        binder.bindInterceptor(Matchers.any(), 
            Matchers.annotatedWith(Validating.class,
            new ValidatingMethodInterceptor()),
    }
}

Next, my method interceptor:

public class ValidatingMethodInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("Hello, AOP!");
    }
}

Finally, the driver that attempts to make use of all this AOP stuff:

public class AopTest {
    @Validating
    public int doSomething() {
        // do whatever
    }

    public static main(String[] args) {
        AopTest test = new AopTest();

        Injector injector = Guice.createInjector(new ValidatingModule());

        System.out.println("About to use AOP...");

        test.doSomething();
    }
}

When I run this little test driver, the only console output I get is About to use AOP...... the Hello, AOP! never gets executed, which means the @Validating doSomething() method is never being intercepted the way the Guice docs show.

The only thing I can think of is the fact that in my Module implementation I am specifying the MethodInterceptor to bind to (as the 3rd argument to the bindInterceptor method) as being a new ValidatingMethodInterceptor(), whereas in that interceptor, I am only defining a required invoke(MethodInvocation) method.

Perhaps I am not wiring these two together correctly? Perhaps Guice doesn't implicitly know that the invoke method should be ran when an intercept occurs?!?!

Then again, not only have I followed the Guice docs, I have also followed several other tutorials to no avail.

Is there something obvious I am missing here? Thanks in advance!

Edit One other discrepancy between my code and the examples I followed, although small, is the fact that my invoke method (inside the interceptor) is not annotated with @Override. If I try to add this annotation, I get the following compile error:

The method invoke(MethodInvocation) of type ValidatingMethodInterceptor must override a superclass method.

This error makes sense, because org.aopalliance.intercept.MethodInterceptor is an interface (not a class). Then again, every example using Guice/AOP Alliance uses this @Override annotation on the invoke method, so it obviously works/compiles for some people...weird.

IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756
  • Re: the `@Override` thing--it's not weird at all, the people for whom it works are using Java 1.6 (or 1.6 source compliance), and you're not. – Dave Newton Jan 14 '12 at 13:52

1 Answers1

10

If you don't let Guice construct your object, it can't provide you an instance with the interceptor wrapped around. You must not use new AopTest() to get an instance of your object. Instead, you must ask Guice to give you one instance:

Injector injector = Guice.createInjector(new ValidatingModule ());
AopTest test = injector.getInstance(AopTest.class);

See http://code.google.com/p/google-guice/wiki/GettingStarted

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks JB! Quick question though - my understanding is that making an explicit call to the Injector is an IoC anti-pattern (by the time we get to the point where we need an `AopTest`, we should already know what concretion it is). Your code example works for me (so thank you!!!) but is there another way to write this so that I'm not explicitly calling `injector.getInstance()`? Thanks again! – IAmYourFaja Jan 14 '12 at 13:50
  • 2
    You have to boostrap the dependency injection from somewhere. You typically use this code only once, in your main method, to get a root object. This root object is injected with other objects, which are injected with other objects, and so on. Bu the root of the tree of objects must be looked up from the injector. – JB Nizet Jan 14 '12 at 13:58
  • @JBNizet If I use an `AopTestProvider` to get `AopTest` instance instead of using `injector.getInstance(AopTest.class)`, will the AOP still work? If not, is it one of the limitation of Guice AOP mentioned [here](https://github.com/google/guice/wiki/AOP#limitations)! – Akshat Jun 28 '15 at 10:54