pombreda / google-guice

Automatically exported from code.google.com/p/google-guice
Apache License 2.0
0 stars 1 forks source link

Private modules and aop interceptors do not work together - test code in description #702

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
package blah;

import static com.google.inject.matcher.Matchers.any;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.PrivateModule;
import com.google.inject.Injector;
import com.google.inject.Module;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class GuiceAopTesting {

  private static final Module PRIVATE_WITH_ADVICE_AND_BINDING = new PrivateModule() {
    @Override
    public void configure() {
      expose(Intercepted.class);
      bindInterceptor(any(), any(), new InterceptClass());
      bind(Intercepted.class).to(MethodIntercepted.class);
    }
  };

  private static final Module PRIVATE_WITH_ADVICE_ONLY = new PrivateModule() {
    @Override
    public void configure() {
      bindInterceptor(any(), any(), new InterceptClass());
    }
  };

  private static final Module PRIVATE_WITH_BINDING = new PrivateModule() {
    @Override
    public void configure() {
      expose(Intercepted.class);
      bind(Intercepted.class).to(MethodIntercepted.class);
    }
  };

  private static final Module ABSTRACT_WITH_ADVICE = new AbstractModule() {
    @Override
    public void configure() {
      bindInterceptor(any(), any(), new InterceptClass());
    }
  };

  private static final Module ABSTRACT_WITH_BINDING = new AbstractModule() {
    @Override
    public void configure() {
      bind(Intercepted.class).to(MethodIntercepted.class);
    }
  };

  private static final Module PRIVATE_INSTALLING_ABSTRACT_WITH_ADVICE_AND_EXPOSING
      = new PrivateModule() {
        @Override
        public void configure() {
          install(ABSTRACT_WITH_ADVICE);
          install(ABSTRACT_WITH_BINDING);
          expose(Intercepted.class);
        }
      };

  public static void main(String[] args) {

    // Fails advices does not apply to the binding in the private module
    System.out.println("CASE 1: PRIVATE DEFINING ADVICE AND BINDING\n");
    print(Guice.createInjector(PRIVATE_WITH_ADVICE_AND_BINDING));

    // Works!
    System.out.println("CASE 2: ABSTRACT DEFINING ADVICE AND PRIVATE WITH BINDING\n");
    print(Guice.createInjector(ABSTRACT_WITH_ADVICE, PRIVATE_WITH_BINDING));

    // Works!
    System.out.println("CASE 3: ABSTRACT DEFINING ADVICE AND ABSTRACT BINDING\n");
    print(Guice.createInjector(ABSTRACT_WITH_ADVICE, ABSTRACT_WITH_BINDING));

    // Works advices from private module does not apply to the binding in the abstract module
    System.out.println("CASE 4: PRIVATE DEFINING ADVICE AND ABSTRACT BINDING\n");
    print(Guice.createInjector(PRIVATE_WITH_ADVICE_ONLY, ABSTRACT_WITH_BINDING));

    // Fails private kills testcase 3.
    System.out.println("CASE 5: PRIVATE INSTALLING CASE #3 AND EXPOSING IT\n");
    print(Guice.createInjector(PRIVATE_INSTALLING_ABSTRACT_WITH_ADVICE_AND_EXPOSING));
  }

  private static void print(Injector injector) {

    // Abstract binding interceptor installs private where interceptor applies successfully
    // Private binds interceptor binds target and target is not advise.

    Intercepted intercepted = injector.getInstance(Intercepted.class);
    intercepted.interceptedMethod();

    System.out.println("\n");

    MethodIntercepted methodIntercepted = injector.getInstance(MethodIntercepted.class);
    methodIntercepted.interceptedMethod();
    methodIntercepted.packagePrivateInterceptedMethod();
    methodIntercepted.protectedInterceptedMethod();
    methodIntercepted.privateMethod();
    methodIntercepted.finalMethod();

    System.out.println("\n");

    Method2Intercepted method2Intercepted = injector.getInstance(Method2Intercepted.class);
    method2Intercepted.interceptedMethod();
    method2Intercepted.packagePrivateInterceptedMethod();
    method2Intercepted.protectedInterceptedMethod();
    method2Intercepted.finalMethod();
  }

  public interface Intercepted {
    public void interceptedMethod();
  }

  public static class MethodIntercepted implements Intercepted {

    @Override @InterceptMethod
    public void interceptedMethod() {
      System.out.println("interceptedMethod");
    }

    @InterceptMethod
    protected void protectedInterceptedMethod() {
      System.out.println("protectedMethod");
    }

    @InterceptMethod
    void packagePrivateInterceptedMethod() {
      System.out.println("packagePrivateMethod");
    }

    @InterceptFinal
    public final void finalMethod() {
      System.out.println("finalMethod");
    }

    @InterceptPrivate
    private void privateMethod() {
      System.out.println("privateMethod");
    }
  }

  public static class Method2Intercepted extends MethodIntercepted {
  }

  @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD})
  @interface InterceptFinal {}

  @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD})
  @interface InterceptMethod {}

  @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD})
  @interface InterceptNothing {}

  @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD})
  @interface InterceptPrivate {}

  public static class InterceptClass implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
      System.out.print("Intercepted! ");
      invocation.proceed();
      return invocation;
    }
  }

}

Original issue reported on code.google.com by djwh...@google.com on 3 May 2012 at 11:47

GoogleCodeExporter commented 9 years ago
Although I haven't analyzed it as closely, this I think this is the same issue 
as described in issue 722. The problem is that your bind statement is:
      bind(Intercepted.class).to(MethodIntercepted.class);
and there's no separate binding for MethodIntercepted.class.  So Guice doesn't 
know you want MethodIntercepted to be private, it just knows you want 
Intercepted to link to whatever MethodIntercepted is.  MethodIntercepted gets 
promoted to the parent module, and the interceptor doesn't apply to the parent 
module.

Adding bind(MethodIntercepted.class) to your PrivateModule should fix it.
Alternately, adding binder().requireExplicitBindings() to the parent Module 
will tell Guice that just-in-time bindings aren't allowed, and it won't attempt 
to promote MethodIntercepted to the parent module.

Original comment by sberlin on 2 Aug 2012 at 1:30