Author: limpbizkit
Date: Sun Jun 21 10:28:03 2009
New Revision: 1024

Modified:
    trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
    trunk/test/com/google/inject/BindingTest.java

Log:
New tests for toConstructor().

I found one bug - we were looking for scoping annotations on the bind  
source type rather than the bind target type. This is fixed now.

One weird behaviour - @Singleton is per-binding, not per-type. Check the  
scoping test for an illustration.

Modified: trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructorBindingImpl.java     
(original)
+++ trunk/src/com/google/inject/internal/ConstructorBindingImpl.java    Sun  
Jun 21 10:28:03 2009
@@ -17,8 +17,8 @@
  package com.google.inject.internal;

  import com.google.inject.Binder;
-import com.google.inject.Key;
  import com.google.inject.ConfigurationException;
+import com.google.inject.Key;
  import static com.google.inject.internal.Preconditions.checkState;
  import static com.google.inject.internal.Annotations.findScopeAnnotation;
  import com.google.inject.spi.BindingTargetVisitor;
@@ -76,9 +76,21 @@
        errors.cannotInjectInnerClass(rawType);
      }

+    errors.throwIfNewErrors(numErrors);
+
+    // Find a constructor annotated @Inject
+    if (constructorInjector == null) {
+      try {
+        constructorInjector =  
InjectionPoint.forConstructorOf(key.getTypeLiteral());
+      } catch (ConfigurationException e) {
+        throw errors.merge(e.getErrorMessages()).toException();
+      }
+    }
+
      // if no scope is specified, look for a scoping annotation on the  
concrete class
      if (!scoping.isExplicitlyScoped()) {
-      Class<? extends Annotation> scopeAnnotation =  
findScopeAnnotation(errors, rawType);
+      Class<?> annotatedType =  
constructorInjector.getMember().getDeclaringClass();
+      Class<? extends Annotation> scopeAnnotation =  
findScopeAnnotation(errors, annotatedType);
        if (scopeAnnotation != null) {
          scoping =  
Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
              injector, errors.withSource(rawType));
@@ -90,15 +102,6 @@
      Factory<T> factoryFactory = new Factory<T>();
      InternalFactory<? extends T> scopedFactory
          = Scoping.scope(key, injector, factoryFactory, scoping);
-
-    // Find a constructor annotated @Inject
-    if (constructorInjector == null) {
-      try {
-        constructorInjector =  
InjectionPoint.forConstructorOf(key.getTypeLiteral());
-      } catch (ConfigurationException e) {
-        throw errors.merge(e.getErrorMessages()).toException();
-      }
-    }

      return new ConstructorBindingImpl<T>(
          injector, key, source, scopedFactory, scoping, factoryFactory,  
constructorInjector);

Modified: trunk/test/com/google/inject/BindingTest.java
==============================================================================
--- trunk/test/com/google/inject/BindingTest.java       (original)
+++ trunk/test/com/google/inject/BindingTest.java       Sun Jun 21 10:28:03 2009
@@ -17,12 +17,20 @@
  package com.google.inject;

  import static com.google.inject.Asserts.assertContains;
-import com.google.inject.name.Names;
+import com.google.inject.internal.ImmutableSet;
+import com.google.inject.internal.Sets;
+import com.google.inject.matcher.Matchers;
+import static com.google.inject.name.Names.named;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
+import java.lang.reflect.Constructor;
  import java.util.Collection;
  import java.util.List;
+import java.util.Set;
  import java.util.concurrent.atomic.AtomicInteger;
-import java.lang.reflect.Constructor;
  import junit.framework.TestCase;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;

  /**
   * @author [email protected] (Bob Lee)
@@ -69,14 +77,14 @@

        // Provider.
        bind(Foo.class)
-          .annotatedWith(Names.named("provider"))
+          .annotatedWith(named("provider"))
            .toProvider(FooProvider.class);

        // Class.
        bind(Bar.class).in(Scopes.SINGLETON);

        // Constant.
-      bindConstant().annotatedWith(Names.named("name")).to("Bob");
+      bindConstant().annotatedWith(named("name")).to("Bob");
      }
    }

@@ -229,36 +237,142 @@
      assertEquals(injector, two.anotherT);
    }

-  public static class C<T> {
-    private Stage stage;
-    private T t;
-    @Inject T anotherT;
+  public void testToConstructorBinding() throws NoSuchMethodException {
+    final Constructor<D> constructor = D.class.getConstructor(Stage.class);

-    public C(Stage stage, T t) {
-      this.stage = stage;
-      this.t = t;
-    }
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bind(Object.class).toConstructor(constructor);
+      }
+    });

-    @Inject C() {}
+    D d = (D) injector.getInstance(Object.class);
+    assertEquals(Stage.DEVELOPMENT, d.stage);
    }

-
-  public void testToConstructorBinding() throws NoSuchMethodException {
+  public void testToConstructorAndMethodInterceptors() throws  
NoSuchMethodException {
      final Constructor<D> constructor = D.class.getConstructor(Stage.class);
+    final AtomicInteger count = new AtomicInteger();
+    final MethodInterceptor countingInterceptor = new MethodInterceptor() {
+      public Object invoke(MethodInvocation methodInvocation) throws  
Throwable {
+        count.incrementAndGet();
+        return methodInvocation.proceed();
+      }
+    };

      Injector injector = Guice.createInjector(new AbstractModule() {
        protected void configure() {
          bind(Object.class).toConstructor(constructor);
+        bindInterceptor(Matchers.any(), Matchers.any(),  
countingInterceptor);
        }
      });

      D d = (D) injector.getInstance(Object.class);
-    assertEquals(Stage.DEVELOPMENT, d.stage);
+    d.hashCode();
+    d.hashCode();
+    assertEquals(2, count.get());
+  }
+
+  public void testInaccessibleConstructor() throws NoSuchMethodException {
+    final Constructor<E> constructor =  
E.class.getDeclaredConstructor(Stage.class);
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bind(E.class).toConstructor(constructor);
+      }
+    });
+
+    E e = injector.getInstance(E.class);
+    assertEquals(Stage.DEVELOPMENT, e.stage);
+  }
+
+  public void testToConstructorAndScopes() throws NoSuchMethodException {
+    final Constructor<F> constructor = F.class.getConstructor(Stage.class);
+
+    final Key<Object> d = Key.get(Object.class, named("D")); // default  
scoping
+    final Key<Object> s = Key.get(Object.class, named("S")); // singleton
+    final Key<Object> n = Key.get(Object.class, named("N")); // "N"  
instances
+    final Key<Object> r = Key.get(Object.class, named("R")); // a regular  
binding
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bind(d).toConstructor(constructor);
+        bind(s).toConstructor(constructor).in(Singleton.class);
+        bind(n).toConstructor(constructor).in(Scopes.NO_SCOPE);
+        bind(r).to(F.class);
+      }
+    });
+
+    assertDistinct(injector, 1, d, d, d, d);
+    assertDistinct(injector, 1, s, s, s, s);
+    assertDistinct(injector, 4, n, n, n, n);
+    assertDistinct(injector, 1, r, r, r, r);
+    assertDistinct(injector, 4, d, d, r, r, s, s, n);
+  }
+
+  public void assertDistinct(Injector injector, int expectedCount,  
Key<?>... keys) {
+    ImmutableSet.Builder<Object> builder = ImmutableSet.builder();
+    for (Key<?> k : keys) {
+      builder.add(injector.getInstance(k));
+    }
+    assertEquals(expectedCount, builder.build().size());
+  }
+
+  public void testToConstructorSpiData() throws NoSuchMethodException {
+    final Set<TypeLiteral<?>> heardTypes = Sets.newHashSet();
+
+    final Constructor<D> constructor = D.class.getConstructor(Stage.class);
+    final TypeListener listener = new TypeListener() {
+      public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
+        if (!heardTypes.add(type)) {
+          fail("Heard " + type + " multiple times!");
+        }
+      }
+    };
+
+    Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bind(Object.class).toConstructor(constructor);
+        bind(D.class).toConstructor(constructor);
+        bindListener(Matchers.any(), listener);
+      }
+    });
+
+    assertEquals(ImmutableSet.of(TypeLiteral.get(Stage.class),  
TypeLiteral.get(D.class)),
+        heardTypes);
+  }
+
+  public static class C<T> {
+    private Stage stage;
+    private T t;
+    @Inject T anotherT;
+
+    public C(Stage stage, T t) {
+      this.stage = stage;
+      this.t = t;
+    }
+
+    @Inject C() {}
    }

    public static class D {
      Stage stage;
      public D(Stage stage) {
+      this.stage = stage;
+    }
+  }
+
+  private static class E {
+    Stage stage;
+    private E(Stage stage) {
+      this.stage = stage;
+    }
+  }
+
+  @Singleton
+  public static class F {
+    Stage stage;
+    @Inject public F(Stage stage) {
        this.stage = stage;
      }
    }

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to