master moved from 41c1c297756b to 8859456e7c13

6 new revisions:

Revision: 883fe035ae3b
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:49:05 2014 UTC
Log: Make ServletScopes#scopeRequest slightly more efficient for larger see...
http://code.google.com/p/google-guice/source/detail?r=883fe035ae3b

Revision: 8ad60eb50961
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:49:46 2014 UTC
Log: Change LinkedBindingBuilder.toProvider(Provider) to accept a jsr330 pr...
http://code.google.com/p/google-guice/source/detail?r=8ad60eb50961

Revision: c33e73ccd3ca
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:50:34 2014 UTC
Log: Improve OutOfScopeException so that it tells you which key it was tryi...
http://code.google.com/p/google-guice/source/detail?r=c33e73ccd3ca

Revision: 10f305d9d432
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:51:17 2014 UTC
Log: This change removes final from fields annotated with @Inject. In addi...
http://code.google.com/p/google-guice/source/detail?r=10f305d9d432

Revision: 29ce12be8958
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:52:01 2014 UTC
Log: Add an SPI for @Provides methods (using the extensions SPI) so that us...
http://code.google.com/p/google-guice/source/detail?r=29ce12be8958

Revision: 8859456e7c13
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 17:58:41 2014 UTC
Log: Update MapBinder so it fails on duplicate bindings with a more descrip...
http://code.google.com/p/google-guice/source/detail?r=8859456e7c13

==============================================================================
Revision: 883fe035ae3b
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:49:05 2014 UTC
Log: Make ServletScopes#scopeRequest slightly more efficient for larger seed maps.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=61542674

http://code.google.com/p/google-guice/source/detail?r=883fe035ae3b

Modified:
 /extensions/servlet/src/com/google/inject/servlet/ServletScopes.java

=======================================
--- /extensions/servlet/src/com/google/inject/servlet/ServletScopes.java Fri Dec 6 22:05:17 2013 UTC +++ /extensions/servlet/src/com/google/inject/servlet/ServletScopes.java Mon Mar 10 16:49:05 2014 UTC
@@ -19,6 +19,7 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Maps.EntryTransformer;
 import com.google.inject.Binding;
 import com.google.inject.Injector;
 import com.google.inject.Key;
@@ -326,10 +327,13 @@

     // Copy the seed values into our local scope map.
     final Context context = new Context();
-    for (Map.Entry<Key<?>, Object> entry : seedMap.entrySet()) {
- Object value = validateAndCanonicalizeValue(entry.getKey(), entry.getValue());
-      context.map.put(entry.getKey(), value);
-    }
+    Map<Key<?>, Object> validatedAndCanonicalizedMap =
+ Maps.transformEntries(seedMap, new EntryTransformer<Key<?>, Object, Object>() { + @Override public Object transformEntry(Key<?> key, Object value) {
+            return validateAndCanonicalizeValue(key, value);
+          }
+        });
+    context.map.putAll(validatedAndCanonicalizedMap);

     return new Callable<T>() {
       public T call() throws Exception {

==============================================================================
Revision: 8ad60eb50961
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:49:46 2014 UTC
Log: Change LinkedBindingBuilder.toProvider(Provider) to accept a jsr330 provider, in addition to the Guice Provider. This is an incompatible change for people who extend LinkedBindingBuilder, but not for people who use it.

This will allow people to switch to JSR330 types more easily.

LinkedBindingBuilder needs both toProvider(Provider) and toProvider(javax.inject.Provider) because precompiled jars (e.g, stuff in third_party, maven, etc..) that used toProvider(Provider) would otherwise throw a NoSuchMethodError.

I left the getProviderInstance method on ProviderInstanceBinding, otherwise
that would require anyone using the SPI method to change their code to accept
the weaker type.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=61966924

http://code.google.com/p/google-guice/source/detail?r=8ad60eb50961

Modified:
 /core/src/com/google/inject/Inject.java
 /core/src/com/google/inject/binder/LinkedBindingBuilder.java
 /core/src/com/google/inject/internal/BindingBuilder.java
 /core/src/com/google/inject/internal/BindingProcessor.java
/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
 /core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
 /core/src/com/google/inject/spi/ProviderInstanceBinding.java
 /core/test/com/google/inject/spi/ElementsTest.java
 /core/test/com/google/inject/spi/ProviderMethodsTest.java
 /core/test/com/google/inject/spi/SpiBindingsTest.java
 /extensions/grapher/src/com/google/inject/grapher/DefaultNodeCreator.java
/extensions/grapher/test/com/google/inject/grapher/ShortNameFactoryTest.java /extensions/multibindings/src/com/google/inject/multibindings/RealElement.java /extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java

=======================================
--- /core/src/com/google/inject/Inject.java     Wed Sep 18 17:57:35 2013 UTC
+++ /core/src/com/google/inject/Inject.java     Mon Mar 10 16:49:46 2014 UTC
@@ -38,7 +38,7 @@
  *
  * <li>Pre-constructed instances passed to {@link Injector#injectMembers},
* {@link com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and - * {@link com.google.inject.binder.LinkedBindingBuilder#toProvider(Provider)}. + * {@link com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}.
  * In this case all constructors are, of course, ignored.
  *
  * <li>Static fields and methods of classes which any {@link Module} has
=======================================
--- /core/src/com/google/inject/binder/LinkedBindingBuilder.java Fri Jul 8 00:34:16 2011 UTC +++ /core/src/com/google/inject/binder/LinkedBindingBuilder.java Mon Mar 10 16:49:46 2014 UTC
@@ -57,6 +57,13 @@
    * @see com.google.inject.Injector#injectMembers
    */
   ScopedBindingBuilder toProvider(Provider<? extends T> provider);
+
+  /**
+   * See the EDSL examples at {@link com.google.inject.Binder}.
+   *
+   * @see com.google.inject.Injector#injectMembers
+   */
+ ScopedBindingBuilder toProvider(javax.inject.Provider<? extends T> provider);

   /**
    * See the EDSL examples at {@link com.google.inject.Binder}.
=======================================
--- /core/src/com/google/inject/internal/BindingBuilder.java Wed Sep 18 17:55:21 2013 UTC +++ /core/src/com/google/inject/internal/BindingBuilder.java Mon Mar 10 16:49:46 2014 UTC
@@ -97,6 +97,10 @@
   }

   public BindingBuilder<T> toProvider(Provider<? extends T> provider) {
+    return toProvider((javax.inject.Provider<T>) provider);
+  }
+
+ public BindingBuilder<T> toProvider(javax.inject.Provider<? extends T> provider) {
     checkNotNull(provider, "provider");
     checkNotTargetted();

=======================================
--- /core/src/com/google/inject/internal/BindingProcessor.java Thu May 16 01:39:15 2013 UTC +++ /core/src/com/google/inject/internal/BindingProcessor.java Mon Mar 10 16:49:46 2014 UTC
@@ -53,7 +53,8 @@
     Class<?> rawType = command.getKey().getTypeLiteral().getRawType();
     if (Void.class.equals(rawType)) {
       if (command instanceof ProviderInstanceBinding
- && ((ProviderInstanceBinding) command).getProviderInstance() instanceof ProviderMethod) {
+          && ((ProviderInstanceBinding) command).getUserSuppliedProvider()
+              instanceof ProviderMethod) {
         errors.voidProviderMethod();
       } else {
         errors.missingConstantValues();
@@ -102,10 +103,11 @@
       @Override
       public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
         prepareBinding();
-        Provider<? extends T> provider = binding.getProviderInstance();
+ javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
         Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
-        Initializable<Provider<? extends T>> initializable = initializer
- .<Provider<? extends T>>requestInjection(injector, provider, null, source, injectionPoints); + Initializable<? extends javax.inject.Provider<? extends T>> initializable = + initializer.<javax.inject.Provider<? extends T>>requestInjection(
+                injector, provider, null, source, injectionPoints);
         // always visited with Binding<T>
         @SuppressWarnings("unchecked")
InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(
@@ -126,7 +128,7 @@
         @SuppressWarnings("unchecked")
BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>( injector, providerKey, source, !injector.options.disableCircularProxies, - injector.provisionListenerStore.get((ProviderKeyBinding<T>)binding)); + injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
         bindingData.addCreationListener(boundProviderFactory);
         InternalFactory<? extends T> scopedFactory = Scoping.scope(
key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping);
=======================================
--- /core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java Mon Feb 27 02:23:19 2012 UTC +++ /core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java Mon Mar 10 16:49:46 2014 UTC
@@ -18,7 +18,6 @@

 import static com.google.common.base.Preconditions.checkNotNull;

-import com.google.inject.Provider;
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.ProviderInstanceBinding;

@@ -31,10 +30,10 @@
final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFactory<T> {

   private final ProvisionListenerStackCallback<T> provisionCallback;
-  private final Initializable<Provider<? extends T>> initializable;
+ private final Initializable<? extends javax.inject.Provider<? extends T>> initializable;

   public InternalFactoryToInitializableAdapter(
-      Initializable<Provider<? extends T>> initializable,
+ Initializable<? extends javax.inject.Provider<? extends T>> initializable,
       Object source, boolean allowProxy,
       ProvisionListenerStackCallback<T> provisionCallback) {
     super(source, allowProxy);
=======================================
--- /core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java Wed Sep 18 17:55:21 2013 UTC +++ /core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java Mon Mar 10 16:49:46 2014 UTC
@@ -30,18 +30,19 @@
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.ProviderInstanceBinding;
 import com.google.inject.spi.ProviderWithExtensionVisitor;
+import com.google.inject.util.Providers;

 import java.util.Set;

 final class ProviderInstanceBindingImpl<T> extends BindingImpl<T>
     implements ProviderInstanceBinding<T> {

-  final Provider<? extends T> providerInstance;
+  final javax.inject.Provider<? extends T> providerInstance;
   final ImmutableSet<InjectionPoint> injectionPoints;

   public ProviderInstanceBindingImpl(InjectorImpl injector, Key<T> key,
Object source, InternalFactory<? extends T> internalFactory, Scoping scoping,
-      Provider<? extends T> providerInstance,
+      javax.inject.Provider<? extends T> providerInstance,
       Set<InjectionPoint> injectionPoints) {
     super(injector, key, source, internalFactory, scoping);
     this.providerInstance = providerInstance;
@@ -49,7 +50,7 @@
   }

public ProviderInstanceBindingImpl(Object source, Key<T> key, Scoping scoping, - Set<InjectionPoint> injectionPoints, Provider<? extends T> providerInstance) { + Set<InjectionPoint> injectionPoints, javax.inject.Provider<? extends T> providerInstance) {
     super(source, key, scoping);
     this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
     this.providerInstance = providerInstance;
@@ -66,6 +67,10 @@
   }

   public Provider<? extends T> getProviderInstance() {
+    return Providers.guicify(providerInstance);
+  }
+
+  public javax.inject.Provider<? extends T> getUserSuppliedProvider() {
     return providerInstance;
   }

@@ -99,7 +104,7 @@

   public void applyTo(Binder binder) {
     getScoping().applyTo(
- binder.withSource(getSource()).bind(getKey()).toProvider(getProviderInstance())); + binder.withSource(getSource()).bind(getKey()).toProvider(getUserSuppliedProvider()));
   }

   @Override
=======================================
--- /core/src/com/google/inject/spi/ProviderInstanceBinding.java Fri Jul 8 00:34:16 2011 UTC +++ /core/src/com/google/inject/spi/ProviderInstanceBinding.java Mon Mar 10 16:49:46 2014 UTC
@@ -31,9 +31,16 @@
public interface ProviderInstanceBinding<T> extends Binding<T>, HasDependencies {

   /**
-   * Returns the user-supplied, unscoped provider.
+ * If the user supplied a JSR330 binding, then this will wrap that one. To always return the
+   * user-supplied provider, use {@link #getUserSuppliedProvider}.
+   *
+   * @deprecated Use {@link #getUserSuppliedProvider} instead.
    */
+  @Deprecated
   Provider<? extends T> getProviderInstance();
+
+  /** Returns the user-supplied, unscoped provider. */
+  javax.inject.Provider<? extends T> getUserSuppliedProvider();

   /**
* Returns the field and method injection points of the provider, injected at injector-creation
=======================================
--- /core/test/com/google/inject/spi/ElementsTest.java Sat Oct 5 21:05:39 2013 UTC +++ /core/test/com/google/inject/spi/ElementsTest.java Mon Mar 10 16:49:46 2014 UTC
@@ -369,12 +369,28 @@
       public String get() {
         return "A";
       }
+    };
+
+ final javax.inject.Provider<Integer> intJavaxProvider = new javax.inject.Provider<Integer>() {
+      public Integer get() {
+        return 42;
+      }
+    };
+
+ final javax.inject.Provider<Double> doubleJavaxProvider = new javax.inject.Provider<Double>() {
+      @javax.inject.Inject String string;
+
+      public Double get() {
+        return 42.42;
+      }
     };

     checkModule(
         new AbstractModule() {
           protected void configure() {
             bind(String.class).toProvider(aProvider);
+            bind(Integer.class).toProvider(intJavaxProvider);
+            bind(Double.class).toProvider(doubleJavaxProvider);
             bind(List.class).toProvider(ListProvider.class);
             bind(Collection.class).toProvider(Key.get(ListProvider.class));
bind(Iterable.class).toProvider(new TypeLiteral<TProvider<List>>() {});
@@ -388,9 +404,51 @@
             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
               @Override public Void visit(
                   ProviderInstanceBinding<? extends T> binding) {
+                assertSame(aProvider, binding.getUserSuppliedProvider());
                 assertSame(aProvider, binding.getProviderInstance());
                 return null;
               }
+            });
+            return null;
+          }
+        },
+
+        new FailingElementVisitor() {
+          @Override public <T> Void visit(Binding<T> command) {
+            assertTrue(command instanceof ProviderInstanceBinding);
+            assertEquals(Key.get(Integer.class), command.getKey());
+            command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
+              @Override public Void visit(
+                  ProviderInstanceBinding<? extends T> binding) {
+ assertSame(intJavaxProvider, binding.getUserSuppliedProvider());
+                assertEquals(42, binding.getProviderInstance().get());
+                // we don't wrap this w/ dependencies if there were none.
+ assertFalse(binding.getProviderInstance() instanceof HasDependencies);
+                return null;
+              }
+            });
+            return null;
+          }
+        },
+
+        new FailingElementVisitor() {
+          @Override public <T> Void visit(Binding<T> command) {
+            assertTrue(command instanceof ProviderInstanceBinding);
+            assertEquals(Key.get(Double.class), command.getKey());
+            command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
+              @Override public Void visit(
+                  ProviderInstanceBinding<? extends T> binding) {
+ assertSame(doubleJavaxProvider, binding.getUserSuppliedProvider());
+                assertEquals(42.42, binding.getProviderInstance().get());
+                // we do wrap it with dependencies if there were some.
+ assertTrue(binding.getProviderInstance() instanceof HasDependencies);
+                Set<Dependency<?>> deps =
+ ((HasDependencies) binding.getProviderInstance()).getDependencies();
+                assertEquals(1, deps.size());
+                assertEquals(String.class,
+ deps.iterator().next().getKey().getTypeLiteral().getRawType());
+                return null;
+              }
             });
             return null;
           }
=======================================
--- /core/test/com/google/inject/spi/ProviderMethodsTest.java Sat Oct 5 21:04:53 2013 UTC +++ /core/test/com/google/inject/spi/ProviderMethodsTest.java Mon Mar 10 16:49:46 2014 UTC
@@ -30,7 +30,6 @@
 import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.Module;
-import com.google.inject.Provider;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
 import com.google.inject.internal.ProviderMethod;
@@ -354,9 +353,10 @@
         element instanceof ProviderInstanceBinding);

     ProviderInstanceBinding binding = (ProviderInstanceBinding) element;
-    Provider provider = binding.getProviderInstance();
+    javax.inject.Provider provider = binding.getUserSuppliedProvider();
     assertEquals(ProviderMethod.class, provider.getClass());
-    assertEquals(methodsObject, ((ProviderMethod) provider).getInstance());
+    assertEquals(methodsObject, ((ProviderMethod) provider).getInstance());
+    assertSame(provider, binding.getProviderInstance());
   }

   public void testVoidProviderMethods() {
=======================================
--- /core/test/com/google/inject/spi/SpiBindingsTest.java Sat Oct 5 21:05:39 2013 UTC +++ /core/test/com/google/inject/spi/SpiBindingsTest.java Mon Mar 10 16:49:46 2014 UTC
@@ -118,7 +118,7 @@
             binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
               @Override public Void visit(
                   ProviderInstanceBinding<? extends T> binding) {
-                assertSame(stringProvider, binding.getProviderInstance());
+ assertSame(stringProvider, binding.getUserSuppliedProvider());
                 return null;
               }
             });
@@ -359,7 +359,7 @@
bind(String.class).toProvider(new ProviderWithExtensionVisitor<String>() { public <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor,
               ProviderInstanceBinding<? extends B> binding) {
-            assertSame(this, binding.getProviderInstance());
+            assertSame(this, binding.getUserSuppliedProvider());
             // We can't always check for FailingSpiTargetVisitor,
             // because constructing the injector visits here, and we need
             // to process the binding as normal
=======================================
--- /extensions/grapher/src/com/google/inject/grapher/DefaultNodeCreator.java Fri Jul 22 21:14:53 2011 UTC +++ /extensions/grapher/src/com/google/inject/grapher/DefaultNodeCreator.java Mon Mar 10 16:49:46 2014 UTC
@@ -26,6 +26,7 @@
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.InstanceBinding;
 import com.google.inject.spi.ProviderInstanceBinding;
+
 import java.lang.reflect.Member;
 import java.util.Collection;
 import java.util.List;
@@ -120,7 +121,7 @@
      */
@Override public Collection<Node> visit(ProviderInstanceBinding<?> binding) { return ImmutableList.<Node>of(newInterfaceNode(binding), newInstanceNode(binding,
-          binding.getProviderInstance()));
+          binding.getUserSuppliedProvider()));
     }

     @Override public Collection<Node> visitOther(Binding<?> binding) {
=======================================
--- /extensions/grapher/test/com/google/inject/grapher/ShortNameFactoryTest.java Fri Jul 8 00:34:16 2011 UTC +++ /extensions/grapher/test/com/google/inject/grapher/ShortNameFactoryTest.java Mon Mar 10 16:49:46 2014 UTC
@@ -157,7 +157,7 @@
         new DefaultBindingTargetVisitor<Object, Void>() {
           @SuppressWarnings("unchecked") @Override
           public Void visit(ProviderInstanceBinding<?> binding) {
- methodHolder[0] = (ProviderMethod) binding.getProviderInstance(); + methodHolder[0] = (ProviderMethod) binding.getUserSuppliedProvider();
             return null;
           }
         });
=======================================
--- /extensions/multibindings/src/com/google/inject/multibindings/RealElement.java Wed Sep 18 17:55:21 2013 UTC +++ /extensions/multibindings/src/com/google/inject/multibindings/RealElement.java Mon Mar 10 16:49:46 2014 UTC
@@ -214,6 +214,10 @@
     }

public ScopedBindingBuilder toProvider(Provider<? extends T> provider) {
+      return toProvider((javax.inject.Provider<T>) provider);
+    }
+
+ public ScopedBindingBuilder toProvider(javax.inject.Provider<? extends T> provider) {
       delegate.toProvider(provider);
       annotation.targetType = TargetType.PROVIDER_INSTANCE;
       annotation.target = provider;
=======================================
--- /extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java Fri Dec 6 22:07:34 2013 UTC +++ /extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java Mon Mar 10 16:49:46 2014 UTC
@@ -135,7 +135,7 @@
           break;
         case PROVIDER_INSTANCE:
           if (value instanceof ProviderInstanceBinding
- && ((ProviderInstanceBinding) value).getProviderInstance().get().equals( + && ((ProviderInstanceBinding) value).getUserSuppliedProvider().get().equals(
                   result.v.instance)) {
             found = entry;
           }
@@ -376,7 +376,7 @@
           break;
         case PROVIDER_INSTANCE:
           if (item instanceof ProviderInstanceBinding
- && ((ProviderInstanceBinding) item).getProviderInstance().get().equals( + && ((ProviderInstanceBinding) item).getUserSuppliedProvider().get().equals(
                   result.instance)) {
             found = item;
           }

==============================================================================
Revision: c33e73ccd3ca
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:50:34 2014 UTC
Log: Improve OutOfScopeException so that it tells you which key it was trying to
get.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=62699406

http://code.google.com/p/google-guice/source/detail?r=c33e73ccd3ca

Modified:
 /extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java
/extensions/servlet/src/com/google/inject/servlet/InternalServletModule.java
 /extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
 /extensions/servlet/test/com/google/inject/servlet/ServletTest.java

=======================================
--- /extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java Sun May 27 17:39:27 2012 UTC +++ /extensions/servlet/src/com/google/inject/servlet/GuiceFilter.java Mon Mar 10 16:50:34 2014 UTC
@@ -19,7 +19,9 @@
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
 import com.google.inject.Inject;
+import com.google.inject.Key;
 import com.google.inject.OutOfScopeException;
+import com.google.inject.internal.Errors;

 import java.io.IOException;
 import java.lang.ref.WeakReference;
@@ -142,27 +144,27 @@
     }
   }

-  static HttpServletRequest getOriginalRequest() {
-    return getContext().getOriginalRequest();
+  static HttpServletRequest getOriginalRequest(Key<?> key) {
+    return getContext(key).getOriginalRequest();
   }

-  static HttpServletRequest getRequest() {
-    return getContext().getRequest();
+  static HttpServletRequest getRequest(Key<?> key) {
+    return getContext(key).getRequest();
   }

-  static HttpServletResponse getResponse() {
-    return getContext().getResponse();
+  static HttpServletResponse getResponse(Key<?> key) {
+    return getContext(key).getResponse();
   }

   static ServletContext getServletContext() {
     return servletContext.get();
   }

-  private static Context getContext() {
+  private static Context getContext(Key<?> key) {
     Context context = localContext.get();
     if (context == null) {
- throw new OutOfScopeException("Cannot access scoped object. Either we"
-          + " are not currently inside an HTTP Servlet request, or you may"
+ throw new OutOfScopeException("Cannot access scoped [" + Errors.convert(key) + + "]. Either we are not currently inside an HTTP Servlet request, or you may"
           + " have forgotten to apply " + GuiceFilter.class.getName()
           + " as a servlet filter for this request.");
     }
=======================================
--- /extensions/servlet/src/com/google/inject/servlet/InternalServletModule.java Thu May 31 23:54:44 2012 UTC +++ /extensions/servlet/src/com/google/inject/servlet/InternalServletModule.java Mon Mar 10 16:50:34 2014 UTC
@@ -20,6 +20,7 @@

 import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
+import com.google.inject.Key;
 import com.google.inject.Provider;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
@@ -102,15 +103,15 @@
   }

   @Provides @RequestScoped HttpServletRequest provideHttpServletRequest() {
-    return GuiceFilter.getRequest();
+    return GuiceFilter.getRequest(Key.get(HttpServletRequest.class));
   }

@Provides @RequestScoped HttpServletResponse provideHttpServletResponse() {
-    return GuiceFilter.getResponse();
+    return GuiceFilter.getResponse(Key.get(HttpServletResponse.class));
   }

   @Provides HttpSession provideHttpSession() {
-    return GuiceFilter.getRequest().getSession();
+    return GuiceFilter.getRequest(Key.get(HttpSession.class)).getSession();
   }

   @SuppressWarnings("unchecked") // defined by getParameterMap()
=======================================
--- /extensions/servlet/src/com/google/inject/servlet/ServletScopes.java Mon Mar 10 16:49:05 2014 UTC +++ /extensions/servlet/src/com/google/inject/servlet/ServletScopes.java Mon Mar 10 16:50:34 2014 UTC
@@ -103,7 +103,7 @@
           // {@code GuiceFilter.getRequest()}.
           //
           // This _correctly_ throws up if the thread is out of scope.
-          HttpServletRequest request = GuiceFilter.getOriginalRequest();
+          HttpServletRequest request = GuiceFilter.getOriginalRequest(key);
           if (REQUEST_CONTEXT_KEYS.contains(key)) {
// Don't store these keys as attributes, since they are handled by
             // GuiceFilter itself.
@@ -144,11 +144,11 @@
    * HTTP session scope.
    */
   public static final Scope SESSION = new Scope() {
-    public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
+ public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
       final String name = key.toString();
       return new Provider<T>() {
         public T get() {
-          HttpSession session = GuiceFilter.getRequest().getSession();
+          HttpSession session = GuiceFilter.getRequest(key).getSession();
           synchronized (session) {
             Object obj = session.getAttribute(name);
             if (NullObject.INSTANCE == obj) {
@@ -217,7 +217,8 @@

// Snapshot the seed map and add all the instances to our continuing HTTP request.
     final ContinuingHttpServletRequest continuingRequest =
-        new ContinuingHttpServletRequest(GuiceFilter.getRequest());
+        new ContinuingHttpServletRequest(
+            GuiceFilter.getRequest(Key.get(HttpServletRequest.class)));
     for (Map.Entry<Key<?>, Object> entry : seedMap.entrySet()) {
Object value = validateAndCanonicalizeValue(entry.getKey(), entry.getValue());
       continuingRequest.setAttribute(entry.getKey().toString(), value);
=======================================
--- /extensions/servlet/test/com/google/inject/servlet/ServletTest.java Mon Oct 31 20:34:04 2011 UTC +++ /extensions/servlet/test/com/google/inject/servlet/ServletTest.java Mon Mar 10 16:50:34 2014 UTC
@@ -16,6 +16,7 @@

 package com.google.inject.servlet;

+import static com.google.inject.Asserts.assertContains;
 import static com.google.inject.Asserts.reserialize;
import static com.google.inject.servlet.ServletTestUtils.newFakeHttpServletRequest; import static com.google.inject.servlet.ServletTestUtils.newFakeHttpServletResponse;
@@ -35,6 +36,11 @@
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.Provider;
+import com.google.inject.Provides;
+import com.google.inject.ProvisionException;
+import com.google.inject.internal.Errors;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
 import com.google.inject.servlet.ServletScopes.NullObject;
 import com.google.inject.util.Providers;

@@ -68,7 +74,6 @@
   private static final Key<Map<String, String[]>> REQ_PARAMS_KEY
       = new Key<Map<String, String[]>>(RequestParameters.class) {};

- private static final Key<InRequest> IN_REQUEST_KEY = Key.get(InRequest.class); private static final Key<InRequest> IN_REQUEST_NULL_KEY = Key.get(InRequest.class, Null.class); private static final Key<InSession> IN_SESSION_KEY = Key.get(InSession.class); private static final Key<InSession> IN_SESSION_NULL_KEY = Key.get(InSession.class, Null.class);
@@ -78,6 +83,39 @@
     //we need to clear the reference to the pipeline every test =(
     GuiceFilter.reset();
   }
+
+  public void testScopeExceptions() throws Exception {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      @Override protected void configure() {
+        install(new ServletModule());
+      }
+      @Provides @RequestScoped String provideString() { return "foo"; }
+      @Provides @SessionScoped Integer provideInteger() { return 1; }
+ @Provides @RequestScoped @Named("foo") String provideNamedString() { return "foo"; }
+    });
+
+    try {
+      injector.getInstance(String.class);
+      fail();
+    } catch(ProvisionException oose) {
+ assertContains(oose.getMessage(), "Cannot access scoped [java.lang.String].");
+    }
+
+    try {
+      injector.getInstance(Integer.class);
+      fail();
+    } catch(ProvisionException oose) {
+ assertContains(oose.getMessage(), "Cannot access scoped [java.lang.Integer].");
+    }
+
+    Key<?> key = Key.get(String.class, Names.named("foo"));
+    try {
+      injector.getInstance(key);
+      fail();
+    } catch(ProvisionException oose) {
+ assertContains(oose.getMessage(), "Cannot access scoped [" + Errors.convert(key) + "]");
+    }
+  }

   public void testRequestAndResponseBindings() throws Exception {
     final Injector injector = createInjector();
@@ -183,7 +221,7 @@
public void testRequestAndResponseBindings_matchesPassedParameters() throws Exception {
     final int[] filterInvoked = new int[1];
     final boolean[] servletInvoked = new boolean[1];
-    final Injector injector = createInjector(new ServletModule() {
+    createInjector(new ServletModule() {
       @Override protected void configureServlets() {
         final HttpServletRequest[] previousReq = new HttpServletRequest[1];
final HttpServletResponse[] previousResp = new HttpServletResponse[1];
@@ -340,8 +378,7 @@
     assertTrue(invoked[0]);
   }

-  public void testHttpSessionIsSerializable()
-      throws IOException, ClassNotFoundException, ServletException {
+  public void testHttpSessionIsSerializable() throws Exception {
     final Injector injector = createInjector();
     final HttpServletRequest request = newFakeHttpServletRequest();
     final HttpSession session = request.getSession();

==============================================================================
Revision: 10f305d9d432
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:51:17 2014 UTC
Log: This change removes final from fields annotated with @Inject. In addition to being discouraged due to weak semantics [1], it is incompatible with the standard javax.inject.Inject annotation [2].

Refactoring: https://code.google.com/p/error-prone/wiki/GuiceInjectOnFinalField

[1] https://code.google.com/p/google-guice/wiki/Injections#Field_Injection
[2] https://code.google.com/p/google-guice/wiki/JSR330
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=62760764

http://code.google.com/p/google-guice/source/detail?r=10f305d9d432

Modified:
/extensions/persist/src/com/google/inject/persist/jpa/JpaLocalTxnInterceptor.java

=======================================
--- /extensions/persist/src/com/google/inject/persist/jpa/JpaLocalTxnInterceptor.java Fri Jul 8 00:34:16 2011 UTC +++ /extensions/persist/src/com/google/inject/persist/jpa/JpaLocalTxnInterceptor.java Mon Mar 10 16:51:17 2014 UTC
@@ -33,11 +33,12 @@
  */
 class JpaLocalTxnInterceptor implements MethodInterceptor {

+  // TODO(gak): Move these args to the cxtor & make these final.
   @Inject
-  private final JpaPersistService emProvider = null;
+  private JpaPersistService emProvider = null;

   @Inject
-  private final UnitOfWork unitOfWork = null;
+  private UnitOfWork unitOfWork = null;

   @Transactional
   private static class Internal {}

==============================================================================
Revision: 29ce12be8958
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 16:52:01 2014 UTC
Log: Add an SPI for @Provides methods (using the extensions SPI) so that users can
do more analysis (with the enclosing instance, method, etc..).

Notably, this can let users write analysis that looks for @Provides methods
declared with @Nullable, and compare against injection points w/o @Nullable,
failing if so.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=62834918

http://code.google.com/p/google-guice/source/detail?r=29ce12be8958

Added:
 /core/src/com/google/inject/spi/ProvidesMethodBinding.java
 /core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java
Modified:
 /core/src/com/google/inject/internal/ProviderMethod.java
 /core/test/com/google/inject/spi/ProviderMethodsTest.java

=======================================
--- /dev/null
+++ /core/src/com/google/inject/spi/ProvidesMethodBinding.java Mon Mar 10 16:52:01 2014 UTC
@@ -0,0 +1,24 @@
+package com.google.inject.spi;
+
+import com.google.inject.Key;
+import com.google.inject.Provides;
+
+import java.lang.reflect.Method;
+
+/**
+ * An {@literal @}{@link Provides} binding.
+ *
+ * @since 4.0
+ * @author sa...@google.com (Sam Berlin)
+ */
+public interface ProvidesMethodBinding<T> extends HasDependencies {
+
+  /** Returns the method this binding uses. */
+  Method getMethod();
+
+  /** Returns the instance of the object the method is defined in. */
+  Object getEnclosingInstance();
+
+  /** Returns the key of the binding. */
+  Key<T> getKey();
+}
=======================================
--- /dev/null
+++ /core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java Mon Mar 10 16:52:01 2014 UTC
@@ -0,0 +1,21 @@
+package com.google.inject.spi;
+
+import com.google.inject.Provides;
+import com.google.inject.spi.BindingTargetVisitor;
+
+/**
+ * A visitor for the {@literal @}{@link Provides} bindings.
+ * <p>
+ * If your {@link BindingTargetVisitor} implements this interface, bindings created by using
+ * {@code @Provides} will be visited through this interface.
+ *
+ * @since 4.0
+ * @author sa...@google.com (Sam Berlin)
+ */
+public interface ProvidesMethodTargetVisitor<T, V> extends BindingTargetVisitor<T, V> {
+
+  /**
+ * Visits an {@link ProvidesMethodBinding} created with an {@literal @}{@link Provides} method.
+   */
+  V visit(ProvidesMethodBinding<? extends T> providesMethodBinding);
+}
=======================================
--- /core/src/com/google/inject/internal/ProviderMethod.java Fri Jul 8 00:34:16 2011 UTC +++ /core/src/com/google/inject/internal/ProviderMethod.java Mon Mar 10 16:52:01 2014 UTC
@@ -24,8 +24,13 @@
 import com.google.inject.PrivateBinder;
 import com.google.inject.Provider;
 import com.google.inject.internal.util.StackTraceElements;
+import com.google.inject.spi.BindingTargetVisitor;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.ProviderWithDependencies;
+import com.google.inject.spi.HasDependencies;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderWithExtensionVisitor;
+import com.google.inject.spi.ProvidesMethodBinding;
+import com.google.inject.spi.ProvidesMethodTargetVisitor;

 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
@@ -38,7 +43,8 @@
  *
  * @author jessewil...@google.com (Jesse Wilson)
  */
-public class ProviderMethod<T> implements ProviderWithDependencies<T> {
+public class ProviderMethod<T> implements ProviderWithExtensionVisitor<T>, HasDependencies,
+    ProvidesMethodBinding<T> {
   private final Key<T> key;
   private final Class<? extends Annotation> scopeAnnotation;
   private final Object instance;
@@ -76,6 +82,10 @@
   public Object getInstance() {
     return instance;
   }
+
+  public Object getEnclosingInstance() {
+    return instance;
+  }

   public void configure(Binder binder) {
     binder = binder.withSource(method);
@@ -114,6 +124,15 @@
   public Set<Dependency<?>> getDependencies() {
     return dependencies;
   }
+
+  @SuppressWarnings("unchecked")
+ public <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor,
+      ProviderInstanceBinding<? extends B> binding) {
+    if (visitor instanceof ProvidesMethodTargetVisitor) {
+      return ((ProvidesMethodTargetVisitor<T, V>)visitor).visit(this);
+    }
+    return visitor.visit(binding);
+  }

   @Override public String toString() {
     return "@Provides " + StackTraceElements.forMember(method).toString();
=======================================
--- /core/test/com/google/inject/spi/ProviderMethodsTest.java Mon Mar 10 16:49:46 2014 UTC +++ /core/test/com/google/inject/spi/ProviderMethodsTest.java Mon Mar 10 16:52:01 2014 UTC
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.AbstractModule;
 import com.google.inject.Binder;
+import com.google.inject.Binding;
 import com.google.inject.BindingAnnotation;
 import com.google.inject.CreationException;
 import com.google.inject.Guice;
@@ -403,4 +404,52 @@
       return 42;
     }
   }
+
+  public void testSpi() throws Exception {
+    Module m1 = new AbstractModule() {
+      @Override protected void configure() {}
+ @Provides @Named("foo") String provideFoo(Integer dep) { return "foo"; }
+    };
+    Module m2 = new AbstractModule() {
+      @Override protected void configure() {}
+      @Provides Integer provideInt(@Named("foo") String dep) { return 42; }
+    };
+    Injector injector = Guice.createInjector(m1, m2);
+
+    Binding<String> stringBinding =
+        injector.getBinding(Key.get(String.class, Names.named("foo")));
+    ProvidesMethodBinding<String> stringMethod =
+        stringBinding.acceptTargetVisitor(new BindingCapturer<String>());
+    assertEquals(m1, stringMethod.getEnclosingInstance());
+ assertEquals(m1.getClass().getDeclaredMethod("provideFoo", Integer.class),
+        stringMethod.getMethod());
+    assertEquals(((HasDependencies) stringBinding).getDependencies(),
+        stringMethod.getDependencies());
+ assertEquals(Key.get(String.class, Names.named("foo")), stringMethod.getKey());
+
+    Binding<Integer> intBinding = injector.getBinding(Integer.class);
+    ProvidesMethodBinding<Integer> intMethod =
+        intBinding.acceptTargetVisitor(new BindingCapturer<Integer>());
+    assertEquals(m2, intMethod.getEnclosingInstance());
+ assertEquals(m2.getClass().getDeclaredMethod("provideInt", String.class),
+        intMethod.getMethod());
+    assertEquals(((HasDependencies) intBinding).getDependencies(),
+        intMethod.getDependencies());
+    assertEquals(Key.get(Integer.class), intMethod.getKey());
+
+  }
+
+ private static class BindingCapturer<T> extends DefaultBindingTargetVisitor<T, ProvidesMethodBinding<T>>
+      implements ProvidesMethodTargetVisitor<T, ProvidesMethodBinding<T>> {
+
+    @SuppressWarnings("unchecked")
+    public ProvidesMethodBinding<T> visit(
+        ProvidesMethodBinding<? extends T> providesMethodBinding) {
+      return (ProvidesMethodBinding<T>)providesMethodBinding;
+    }
+
+ @Override protected ProvidesMethodBinding<T> visitOther(Binding<? extends T> binding) {
+      throw new IllegalStateException("unexpected visit of: " + binding);
+    }
+  }
 }

==============================================================================
Revision: 8859456e7c13
Author:   Sam Berlin <sa...@google.com>
Date:     Mon Mar 10 17:58:41 2014 UTC
Log: Update MapBinder so it fails on duplicate bindings with a more descriptive error message, including all the keys that had duplicates and where the duplicate bindings were bound. Example error message that has 'a' bound twice and 'b' bound twice:

1) Map injection failed due to duplicated key "a", from bindings at:
com.google.inject.multibindings.MapBinderTest.configure(MapBinderTest.java:337) (via modules: com.google.inject.multibindings.MapBinderTest$1Main -> com.google.inject.multibindings.MapBinderTest$1Module1) com.google.inject.multibindings.MapBinderTest.configure(MapBinderTest.java:344) (via modules: com.google.inject.multibindings.MapBinderTest$1Main -> com.google.inject.multibindings.MapBinderTest$1Module2)

 and key: "b", from bindings at:
com.google.inject.multibindings.MapBinderTest.configure(MapBinderTest.java:345) (via modules: com.google.inject.multibindings.MapBinderTest$1Main -> com.google.inject.multibindings.MapBinderTest$1Module2) com.google.inject.multibindings.MapBinderTest.configure(MapBinderTest.java:352) (via modules: com.google.inject.multibindings.MapBinderTest$1Main -> com.google.inject.multibindings.MapBinderTest$1Module3)

at com.google.inject.multibindings.MapBinder.initialize(MapBinder.java:380) at com.google.inject.multibindings.MapBinderTest.configure(MapBinderTest.java:357) (via modules: com.google.inject.multibindings.MapBinderTest$1Main -> com.google.inject.multibindings.MapBinder$RealMapBinder)
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=62865462

http://code.google.com/p/google-guice/source/detail?r=8859456e7c13

Modified:
/extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java /extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java

=======================================
--- /extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java Fri Dec 6 22:07:34 2013 UTC +++ /extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java Mon Mar 10 17:58:41 2014 UTC
@@ -25,11 +25,15 @@
 import static com.google.inject.util.Types.newParameterizedType;
 import static com.google.inject.util.Types.newParameterizedTypeWithOwner;

+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.LinkedHashMultimap;
 import com.google.inject.Binder;
 import com.google.inject.Binding;
 import com.google.inject.Inject;
@@ -38,6 +42,7 @@
 import com.google.inject.Module;
 import com.google.inject.Provider;
 import com.google.inject.TypeLiteral;
+import com.google.inject.internal.Errors;
 import com.google.inject.binder.LinkedBindingBuilder;
 import com.google.inject.multibindings.Multibinder.RealMultibinder;
 import com.google.inject.spi.BindingTargetVisitor;
@@ -302,7 +307,7 @@
    *
    * <p>We use a subclass to hide 'implements Module' from the public API.
    */
- private static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module { + static final class RealMapBinder<K, V> extends MapBinder<K, V> implements Module {
     private final TypeLiteral<K> keyType;
     private final TypeLiteral<V> valueType;
     private final Key<Map<K, V>> mapKey;
@@ -377,14 +382,39 @@

Map<K, Provider<V>> providerMapMutable = new LinkedHashMap<K, Provider<V>>(); List<Map.Entry<K, Binding<V>>> bindingsMutable = Lists.newArrayList();
+          Set<K> duplicateKeys = null;
           for (Entry<K, Provider<V>> entry : entrySetProvider.get()) {
Provider<V> previous = providerMapMutable.put(entry.getKey(), entry.getValue());
-            checkConfiguration(previous == null || permitDuplicates,
- "Map injection failed due to duplicated key \"%s\"", entry.getKey());
+            if (previous != null && !permitDuplicates) {
+              if (duplicateKeys == null) {
+                duplicateKeys = Sets.newHashSet();
+              }
+              duplicateKeys.add(entry.getKey());
+            }
ProviderMapEntry<K, V> providerEntry = (ProviderMapEntry<K, V>) entry;
             Key<V> valueKey = providerEntry.getValueKey();
bindingsMutable.add(Maps.immutableEntry(entry.getKey(), injector.getBinding(valueKey)));
           }
+          if (duplicateKeys != null) {
+            Multimap<K, String> dups = LinkedHashMultimap.create();
+            for (Map.Entry<K, Binding<V>> entry : bindingsMutable) {
+              if (duplicateKeys.contains(entry.getKey())) {
+ dups.put(entry.getKey(), "\t" + Errors.convert(entry.getValue().getSource()));
+              }
+            }
+ StringBuilder sb = new StringBuilder("Map injection failed due to duplicated key ");
+            boolean first = true;
+            for (K key : dups.keySet()) {
+              if (first) {
+                first = false;
+                sb.append("\"" + key + "\", from bindings at:\n");
+              } else {
+ sb.append("\n and key: \"" + key + "\", from bindings at:\n");
+              }
+              Joiner.on('\n').appendTo(sb, dups.get(key)).append("\n");
+            }
+            checkConfiguration(false, sb.toString());
+          }

           providerMap = ImmutableMap.copyOf(providerMapMutable);
           mapBindings = ImmutableList.copyOf(bindingsMutable);
=======================================
--- /extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java Fri Dec 6 22:07:34 2013 UTC +++ /extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java Mon Mar 10 17:58:41 2014 UTC
@@ -16,6 +16,7 @@

 package com.google.inject.multibindings;

+import static com.google.inject.Asserts.asModuleChain;
 import static com.google.inject.Asserts.assertContains;
 import static com.google.inject.multibindings.SpiUtils.VisitType.BOTH;
 import static com.google.inject.multibindings.SpiUtils.VisitType.MODULE;
@@ -40,6 +41,7 @@
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.Provider;
+import com.google.inject.Provides;
 import com.google.inject.ProvisionException;
 import com.google.inject.Stage;
 import com.google.inject.TypeLiteral;
@@ -82,7 +84,6 @@

private final TypeLiteral<String> stringType = TypeLiteral.get(String.class); private final TypeLiteral<Integer> intType = TypeLiteral.get(Integer.class); - private final TypeLiteral<Set<String>> stringSetType = new TypeLiteral<Set<String>>() {};

   public void testMapBinderAggregatesMultipleModules() {
     Module abc = new AbstractModule() {
@@ -326,6 +327,56 @@
assertMapVisitor(Key.get(mapOfString), stringType, stringType, setOf(module), MODULE, false, 0,
         instance("a", "A"), instance("a", "B"));
   }
+
+  public void testExhaustiveDuplicateErrorMessage() throws Exception {
+    class Module1 extends AbstractModule {
+      @Override protected void configure() {
+        MapBinder<String, Object> mapbinder =
+            MapBinder.newMapBinder(binder(), String.class, Object.class);
+        mapbinder.addBinding("a").to(String.class);
+      }
+    }
+    class Module2 extends AbstractModule {
+      @Override protected void configure() {
+        MapBinder<String, Object> mapbinder =
+            MapBinder.newMapBinder(binder(), String.class, Object.class);
+        mapbinder.addBinding("a").to(Integer.class);
+        mapbinder.addBinding("b").to(String.class);
+      }
+    }
+    class Module3 extends AbstractModule {
+      @Override protected void configure() {
+        MapBinder<String, Object> mapbinder =
+            MapBinder.newMapBinder(binder(), String.class, Object.class);
+        mapbinder.addBinding("b").to(Integer.class);
+      }
+    }
+    class Main extends AbstractModule {
+      @Override protected void configure() {
+        MapBinder.newMapBinder(binder(), String.class, Object.class);
+        install(new Module1());
+        install(new Module2());
+        install(new Module3());
+      }
+      @Provides String provideString() { return "foo"; }
+      @Provides Integer provideInt() { return 42; }
+    }
+    try {
+      Guice.createInjector(new Main());
+      fail();
+    } catch(CreationException ce) {
+      assertContains(ce.getMessage(),
+ "Map injection failed due to duplicated key \"a\", from bindings at:",
+          asModuleChain(Main.class, Module1.class),
+          asModuleChain(Main.class, Module2.class),
+          "and key: \"b\", from bindings at:",
+          asModuleChain(Main.class, Module2.class),
+          asModuleChain(Main.class, Module3.class),
+          "at " + Main.class.getName() + ".configure(",
+          asModuleChain(Main.class, MapBinder.RealMapBinder.class));
+      assertEquals(1, ce.getErrorMessages().size());
+    }
+  }

   public void testMapBinderMapPermitDuplicateElements() {
     Module ab = new AbstractModule() {

--
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to google-guice-dev+unsubscr...@googlegroups.com.
To post to this group, send email to google-guice-dev@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice-dev.
For more options, visit https://groups.google.com/d/optout.

Reply via email to