Revision: 1544
Author:   sberlin
Date:     Sun May  1 17:28:59 2011
Log: fix provider circular dependency detection to use the Key it is creating, not the Key it is fulfulling, to catch errors sooner.
http://code.google.com/p/google-guice/source/detail?r=1544

Modified:
 /trunk/core/src/com/google/inject/internal/BindingProcessor.java
 /trunk/core/src/com/google/inject/internal/BoundProviderFactory.java
 /trunk/core/src/com/google/inject/internal/InjectorImpl.java
/trunk/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
 /trunk/core/src/com/google/inject/internal/ProviderInternalFactory.java
 /trunk/core/test/com/google/inject/CircularDependencyTest.java

=======================================
--- /trunk/core/src/com/google/inject/internal/BindingProcessor.java Sat Apr 30 08:38:05 2011 +++ /trunk/core/src/com/google/inject/internal/BindingProcessor.java Sun May 1 17:28:59 2011
@@ -100,7 +100,7 @@
         Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
         Initializable<Provider<? extends T>> initializable = initializer
.<Provider<? extends T>>requestInjection(injector, provider, source, injectionPoints); - InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>( + InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(key, initializable, source, !injector.options.disableCircularProxies);
         InternalFactory<? extends T> scopedFactory
             = Scoping.scope(key, injector, factory, source, scoping);
@@ -112,7 +112,7 @@
       public Boolean visit(ProviderKeyBinding<? extends T> binding) {
         prepareBinding();
Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey(); - BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>( + BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(key, injector, providerKey, source, !injector.options.disableCircularProxies);
         bindingData.addCreationListener(boundProviderFactory);
         InternalFactory<? extends T> scopedFactory = Scoping.scope(
=======================================
--- /trunk/core/src/com/google/inject/internal/BoundProviderFactory.java Sat Apr 30 08:38:05 2011 +++ /trunk/core/src/com/google/inject/internal/BoundProviderFactory.java Sun May 1 17:28:59 2011
@@ -30,11 +30,12 @@
private InternalFactory<? extends javax.inject.Provider<? extends T>> providerFactory;

   BoundProviderFactory(
+      Key<T> key,
       InjectorImpl injector,
       Key<? extends javax.inject.Provider<? extends T>> providerKey,
       Object source,
       boolean allowProxy) {
-    super(source, allowProxy);
+    super(key, source, allowProxy);
     this.injector = injector;
     this.providerKey = providerKey;
   }
=======================================
--- /trunk/core/src/com/google/inject/internal/InjectorImpl.java Sat Apr 30 08:38:05 2011 +++ /trunk/core/src/com/google/inject/internal/InjectorImpl.java Sun May 1 17:28:59 2011
@@ -678,7 +678,7 @@
= getBindingOrThrow(providerKey, errors, JitLimitation.NEW_OR_EXISTING_JIT);

     InternalFactory<T> internalFactory =
- new ProviderInternalFactory<T>(providerKey, !options.disableCircularProxies) { + new ProviderInternalFactory<T>(key, providerKey, !options.disableCircularProxies) { public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked)
           throws ErrorsException {
         errors = errors.withSource(providerKey);
=======================================
--- /trunk/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java Sat Apr 30 08:38:05 2011 +++ /trunk/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java Sun May 1 17:28:59 2011
@@ -16,6 +16,7 @@

 package com.google.inject.internal;

+import com.google.inject.Key;
 import com.google.inject.Provider;
 import static com.google.inject.internal.util.Preconditions.checkNotNull;
 import com.google.inject.spi.Dependency;
@@ -32,8 +33,9 @@
   private final Initializable<Provider<? extends T>> initializable;

   public InternalFactoryToInitializableAdapter(
- Initializable<Provider<? extends T>> initializable, Object source, boolean allowProxy) {
-    super(source, allowProxy);
+      Key<T> key, Initializable<Provider<? extends T>> initializable,
+      Object source, boolean allowProxy) {
+    super(key, source, allowProxy);
     this.initializable = checkNotNull(initializable, "provider");
   }

=======================================
--- /trunk/core/src/com/google/inject/internal/ProviderInternalFactory.java Sat Apr 30 08:38:05 2011 +++ /trunk/core/src/com/google/inject/internal/ProviderInternalFactory.java Sun May 1 17:28:59 2011
@@ -21,6 +21,7 @@

 import javax.inject.Provider;

+import com.google.inject.Key;
 import com.google.inject.spi.Dependency;

 /**
@@ -31,10 +32,12 @@
  */
 abstract class ProviderInternalFactory<T> implements InternalFactory<T> {

+  private final Key<T> key;
   protected final Object source;
   private final boolean allowProxy;

-  ProviderInternalFactory(Object source, boolean allowProxy) {
+  ProviderInternalFactory(Key<T> key, Object source, boolean allowProxy) {
+    this.key = key;
     this.source = checkNotNull(source, "source");
     this.allowProxy = allowProxy;
   }
@@ -43,9 +46,13 @@
       InternalContext context, Dependency<?> dependency, boolean linked)
       throws ErrorsException {
Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType();
-    // we do not use 'this' as the key because for JIT provider bindings,
-    // 'this' is recreated on failures... the key suffices.
- ConstructionContext<T> constructionContext = context.getConstructionContext(dependency.getKey());
+
+ // Use the Key we are providing for as a unique key to locate the context. + // We cannot use dependency.getKey() because that is the Key of the type
+    // we are trying to fulfill (which may be different among different
+    // calls to us).  We also cannot use 'this', because the factory can
+    // be recreated different times during @ProvidedBy creations.
+ ConstructionContext<T> constructionContext = context.getConstructionContext(key);

     // We have a circular reference between constructors. Return a proxy.
     if (constructionContext.isConstructing()) {
=======================================
--- /trunk/core/test/com/google/inject/CircularDependencyTest.java Sat Apr 30 08:38:05 2011 +++ /trunk/core/test/com/google/inject/CircularDependencyTest.java Sun May 1 17:28:59 2011
@@ -16,6 +16,9 @@

 package com.google.inject;

+import java.util.ArrayList;
+import java.util.List;
+
 import junit.framework.TestCase;
 import static com.google.inject.Asserts.assertContains;

@@ -405,4 +408,35 @@
       return "G";
     }
   }
-}
+
+  /**
+   * Tests that ProviderInternalFactory can detect circular dependencies
+   * before it gets to Scopes.SINGLETON.  This is especially important
+   * because the failure in Scopes.SINGLETON doesn't have enough context to
+   * provide a decent error message.
+   */
+ public void testCircularDependenciesDetectedEarlyWhenDependenciesHaveDifferentTypes() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(Number.class).to(Integer.class);
+      }
+
+      @Provides @Singleton Integer provideInteger(List list) {
+        return new Integer(2);
+      }
+
+      @Provides List provideList(Integer integer) {
+        return new ArrayList();
+      }
+    });
+    try {
+      injector.getInstance(Number.class);
+      fail();
+    } catch(ProvisionException expected) {
+      assertContains(expected.getMessage(),
+ "Tried proxying " + Integer.class.getName() + " to support a circular dependency, ",
+          "but it is not an interface.");
+    }
+  }
+}

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