So I am testing a simple Google Guice interceptor –
My Annotation –
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AppOpsOperation { }
My Interceptor
public class AppOpsOperationDecorator implements MethodInterceptor { private ServiceCallStack callStack = null ; @Inject public void setServiceCallStack(ServiceCallStack stack ){ callStack = stack ; } @Override public Object invoke(MethodInvocation arg0) throws Throwable { // Retrieve the call stack // exclude service population if caller service is the same service // else push the current service onto top of stack System.out.println("Intercepting method -- :: " + arg0.getMethod().getName()); System.out.println("On object - :: " + arg0.getThis().getClass().getName()); System.out.println("On accessible object - :: " + arg0.getStaticPart().getClass().getName()); return invocation.proceed(); } }
And now my Service interface and method
public interface MockCalledService extends AppOpsService { @AppOpsOperation public String methodOneCalled(String some); @AppOpsOperation public String methodTwoCalled(String some); } public class MockCalledServiceImpl extends BaseAppOpsService implements MockCalledService { @Override @AppOpsOperation public String methodOneCalled(String some) { System.out.println("MockCalledServiceImpl.methodOneCalled()"); return this.getClass().getCanonicalName() + "methodOneCalled"; } @Override public String methodTwoCalled(String some) { System.out.println("MockCalledServiceImpl.methodTwoCalled()"); return this.getClass().getCanonicalName() + "methodTwoCalled"; } }
And my Guice test module
public class MockTestGuiceModule extends AbstractModule { @Override protected void configure() { bind(ServiceCallStack.class).toInstance(new ServiceCallStack()); AppOpsOperationDecorator decorator = new AppOpsOperationDecorator() ; requestInjection(decorator); bindInterceptor(Matchers.any(), Matchers.annotatedWith(AppOpsOperation.class), decorator); bind(MockCalledService.class).toInstance(new MockCalledServiceImpl()); } }
This interceptor doesn’t execute when I run the test below –
public class AppOpsOperationDecoratorTest { private Injector injector = null ; @Before public void init(){ injector = Guice.createInjector(new MockTestGuiceModule()); } @Test public void testDecoratorInvocation() { MockCalledService called = injector.getInstance(MockCalledService.class); called.methodOneCalled("Test String"); } }
Can you please highlight what I am doing wrong ?
Advertisement
Answer
I am answering after finding the real reason. Its so simple that its really tricky.
Method interception only works if you bind the interface with the class and not an instance of this implementation.
so instead of bind(MockCalledService.class).toInstance(new MockCalledServiceImpl());
we should write bind(MockCalledService.class).to(MockCalledServiceImpl.class);
Seems instances are not proxied 🙁