*** Reason for rollback ***

Causes an internal test to become flaky.

*** Original change description ***

Enhance WeakKeySet to auto evict keys and avoid calling toString on Keys.

This should fix https://code.google.com/p/google-guice/issues/detail?id=756.

-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=64181193
diff --git a/build.xml b/build.xml
index 09acb0d..203d504 100644
--- a/build.xml
+++ b/build.xml
@@ -105,7 +105,6 @@
         <pathelement location="lib/javax.inject.jar"/>
         <pathelement location="lib/aopalliance.jar"/>
         <pathelement location="lib/guava-16.0.1.jar"/>
-        <pathelement location="lib/build/guava-testlib-16.0.1.jar"/>
         <pathelement location="lib/build/junit.jar"/>
         <pathelement location="lib/build/servlet-api-2.5.jar"/>
         <pathelement location="lib/build/easymock.jar"/>
diff --git a/core/pom.xml b/core/pom.xml
index ffb78ab..e420035 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -29,12 +29,6 @@
       <artifactId>guava</artifactId>
       <version>16.0.1</version>
     </dependency>
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava-testlib</artifactId>
-      <version>16.0.1</version>
-      <scope>test</scope>
-    </dependency>
     <!--
      | CGLIB is embedded by default by the JarJar build profile
     -->
diff --git a/core/src/com/google/inject/internal/AbstractBindingProcessor.java b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
index e1a0bba..72dae2b 100644
--- a/core/src/com/google/inject/internal/AbstractBindingProcessor.java
+++ b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
@@ -98,7 +98,7 @@
     }
 
     // prevent the parent from creating a JIT binding for this key
-    injector.state.parent().blacklist(key, injector.state, binding.getSource());
+    injector.state.parent().blacklist(key, binding.getSource());
     injector.state.putBinding(key, binding);
   }
 
diff --git a/core/src/com/google/inject/internal/InheritingState.java b/core/src/com/google/inject/internal/InheritingState.java
index 06e0ec4..2d694cb 100644
--- a/core/src/com/google/inject/internal/InheritingState.java
+++ b/core/src/com/google/inject/internal/InheritingState.java
@@ -56,13 +56,12 @@
   /*end[AOP]*/
   private final List<TypeListenerBinding> typeListenerBindings = Lists.newArrayList();
   private final List<ProvisionListenerBinding> provisionListenerBindings = Lists.newArrayList(); 
-  private final WeakKeySet blacklistedKeys;
+  private final WeakKeySet blacklistedKeys = new WeakKeySet();
   private final Object lock;
 
   InheritingState(State parent) {
     this.parent = checkNotNull(parent, "parent");
     this.lock = (parent == State.NONE) ? this : parent.lock();
-    this.blacklistedKeys = new WeakKeySet(lock);
   }
 
   public State parent() {
@@ -155,9 +154,9 @@
     return result;
   }
 
-  public void blacklist(Key<?> key, State state, Object source) {
-    parent.blacklist(key, state, source);
-    blacklistedKeys.add(key, state, source);
+  public void blacklist(Key<?> key, Object source) {
+    parent.blacklist(key, source);
+    blacklistedKeys.add(key, source);
   }
 
   public boolean isBlacklisted(Key<?> key) {
diff --git a/core/src/com/google/inject/internal/InjectorImpl.java b/core/src/com/google/inject/internal/InjectorImpl.java
index 10bd9be..6faab97 100644
--- a/core/src/com/google/inject/internal/InjectorImpl.java
+++ b/core/src/com/google/inject/internal/InjectorImpl.java
@@ -791,7 +791,7 @@
     }
 
     BindingImpl<T> binding = createJustInTimeBinding(key, errors, jitDisabled, jitType);
-    state.parent().blacklist(key, state, binding.getSource());
+    state.parent().blacklist(key, binding.getSource());
     jitBindings.put(key, binding);
     return binding;
   }
diff --git a/core/src/com/google/inject/internal/State.java b/core/src/com/google/inject/internal/State.java
index 3c9e081..d824cc1 100644
--- a/core/src/com/google/inject/internal/State.java
+++ b/core/src/com/google/inject/internal/State.java
@@ -105,7 +105,7 @@
       return ImmutableList.of();
     }
 
-    public void blacklist(Key<?> key, State state, Object source) {
+    public void blacklist(Key<?> key, Object source) {
     }
 
     public boolean isBlacklisted(Key<?> key) {
@@ -165,9 +165,9 @@
   /**
    * Forbids the corresponding injector from creating a binding to {@code key}. Child injectors
    * blacklist their bound keys on their parent injectors to prevent just-in-time bindings on the
-   * parent injector that would conflict and pass along their state to control the lifetimes.
+   * parent injector that would conflict.
    */
-  void blacklist(Key<?> key, State state, Object source);
+  void blacklist(Key<?> key, Object source);
 
   /**
    * Returns true if {@code key} is forbidden from being bound in this injector. This indicates that
diff --git a/core/src/com/google/inject/internal/WeakKeySet.java b/core/src/com/google/inject/internal/WeakKeySet.java
index 022aa4f..761cd35 100644
--- a/core/src/com/google/inject/internal/WeakKeySet.java
+++ b/core/src/com/google/inject/internal/WeakKeySet.java
@@ -16,86 +16,37 @@
 
 package com.google.inject.internal;
 
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.RemovalCause;
-import com.google.common.cache.RemovalListener;
-import com.google.common.cache.RemovalNotification;
-import com.google.common.collect.LinkedHashMultiset;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Multiset;
 import com.google.common.collect.Sets;
 import com.google.inject.Key;
 import com.google.inject.internal.util.SourceProvider;
 
-import java.lang.annotation.Annotation;
 import java.util.Map;
 import java.util.Set;
 
 /**
  * Minimal set that doesn't hold strong references to the contained keys.
  *
- * @author dweis@google.com (Daniel Weis)
+ * @author jessewilson@google.com (Jesse Wilson)
  */
 final class WeakKeySet {
 
-  /**
-   * The key for the Map is {@link Key} for most bindings, String for multibindings.
-   * <p>
-   * Reason being that multibinding Key's annotations hold a reference to their injector, implying
-   * we'd leak memory.
-   */
-  private Map<Object, Multiset<Object>> backingSet;
-  
-  /**
-   * This is already locked externally on add and getSources but we need it to handle clean up in
-   * the evictionCache's RemovalListener.
-   */
-  private final Object lock;
+  // TODO(user): Instead of relying on Key#toString(), consider maintaining a set of custom weak
+  // references for child injectors. On some actions, we can poll the ReferenceQueue and clear the
+  // relevant blacklisted values. This would allow us to avoid forcing the toString memoization on
+  // Key and fix the memory leak referenced in
+  // https://code.google.com/p/google-guice/issues/detail?id=756.
 
   /**
-   * Tracks child injector lifetimes and evicts blacklisted keys/sources after the child injector is
-   * garbage collected.
+   * We store strings rather than keys so we don't hold strong references.
+   *
+   * <p>One potential problem with this approach is that parent and child injectors cannot define
+   * keys whose class names are equal but class loaders are different. This shouldn't be an issue
+   * in practice.
    */
-  private final Cache<State, Set<KeyAndSource>> evictionCache = CacheBuilder.newBuilder()
-      .weakKeys()
-      .removalListener(
-          new RemovalListener<State, Set<KeyAndSource>>() {
-            @Override
-            public void onRemoval(RemovalNotification<State, Set<KeyAndSource>> notification) {
-              Preconditions.checkState(RemovalCause.COLLECTED.equals(notification.getCause()));
+  private Map<String, Set<Object>> backingSet;
 
-              cleanUpForCollectedState(notification.getValue());
-            }
-          })
-      .build();
-
-  /**
-   * There may be multiple child injectors blacklisting a certain key so only remove the source
-   * that's relevant.
-   */
-  private void cleanUpForCollectedState(Set<KeyAndSource> keysAndSources) {
-    synchronized (lock) {
-      
-      for (KeyAndSource keyAndSource : keysAndSources) {
-        Multiset<Object> set = backingSet.get(keyAndSource.mapKey);
-        if (set != null) {
-          set.remove(keyAndSource.source);
-          if (set.isEmpty()) {
-            backingSet.remove(keyAndSource.mapKey);
-          }
-        }
-      }
-    }
-  }
-
-  WeakKeySet(Object lock) {
-    this.lock = lock;
-  }
-
-  public void add(Key<?> key, State state, Object source) {
+  public void add(Key<?> key, Object source) {
     if (backingSet == null) {
       backingSet = Maps.newHashMap();
     }
@@ -104,74 +55,22 @@
     if (source instanceof Class || source == SourceProvider.UNKNOWN_SOURCE) {
       source = null;
     }
-    Object mapKey = toMapKey(key);
-    Multiset<Object> sources = backingSet.get(mapKey);
+    String k = key.toString();
+    Set<Object> sources = backingSet.get(k);
     if (sources == null) {
-      sources = LinkedHashMultiset.create();
-      backingSet.put(mapKey, sources);
+      sources = Sets.newLinkedHashSet();
+      backingSet.put(k, sources);
     }
-    Object convertedSource = Errors.convert(source);
-    sources.add(convertedSource);
-
-    // Avoid all the extra work if we can.
-    if (state.parent() != State.NONE) {
-      Set<KeyAndSource> keyAndSources = evictionCache.getIfPresent(state);
-      if (keyAndSources == null) {
-        evictionCache.put(state, keyAndSources = Sets.newHashSet());
-      }
-      keyAndSources.add(new KeyAndSource(mapKey, convertedSource));
-    }
+    sources.add(Errors.convert(source));
   }
 
   public boolean contains(Key<?> key) {
-    evictionCache.cleanUp();
-    return backingSet != null && backingSet.containsKey(key);
+    // avoid calling key.toString() if the backing set is empty. toString is expensive in aggregate,
+    // and most WeakKeySets are empty in practice (because they're used by top-level injectors)
+    return backingSet != null && backingSet.containsKey(key.toString());
   }
 
   public Set<Object> getSources(Key<?> key) {
-    evictionCache.cleanUp();
-    Multiset<Object> sources = backingSet.get(key);
-    return (sources == null) ? null : sources.elementSet();
-  }
-  
-  private static Object toMapKey(Key<?> key) {
-    Annotation annotation = key.getAnnotation();
-    if (annotation != null
-        // HACK: See comment on backingSet for more info. This is tested in MultibinderTest,
-        // MapBinderTest, and OptionalBinderTest in the multibinder test suite.
-        && "com.google.inject.multibindings.RealElement".equals(annotation.getClass().getName())) {
-      return key.toString();
-    }
-    return key;
-  }
-
-  private static final class KeyAndSource {
-    final Object mapKey;
-    final Object source;
-
-    KeyAndSource(Object mapKey, Object source) {
-      this.mapKey = mapKey;
-      this.source = source;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hashCode(mapKey, source);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) {
-        return true;
-      }
-
-      if (!(obj instanceof KeyAndSource)) {
-        return false;
-      }
-
-      KeyAndSource other = (KeyAndSource) obj;
-      return Objects.equal(mapKey, other.mapKey)
-          && Objects.equal(source, other.source);
-    }
+    return backingSet.get(key.toString());
   }
 }
diff --git a/core/test/com/google/inject/AllTests.java b/core/test/com/google/inject/AllTests.java
index c0fd13f..54f4dea 100644
--- a/core/test/com/google/inject/AllTests.java
+++ b/core/test/com/google/inject/AllTests.java
@@ -20,7 +20,6 @@
 import com.google.inject.internal.MoreTypesTest;
 import com.google.inject.internal.RehashableKeysTest;
 import com.google.inject.internal.UniqueAnnotationsTest;
-import com.google.inject.internal.WeakKeySetTest;
 import com.google.inject.internal.util.LineNumbersTest;
 import com.google.inject.matcher.MatcherTest;
 import com.google.inject.name.NamedEquivalanceTest;
@@ -107,7 +106,6 @@
     suite.addTestSuite(TypeLiteralInjectionTest.class);
     suite.addTestSuite(TypeLiteralTest.class);
     suite.addTestSuite(TypeLiteralTypeResolutionTest.class);
-    suite.addTestSuite(WeakKeySetTest.class);
 
     // internal
     suite.addTestSuite(LineNumbersTest.class);
diff --git a/core/test/com/google/inject/internal/WeakKeySetTest.java b/core/test/com/google/inject/internal/WeakKeySetTest.java
deleted file mode 100644
index c3b2df8..0000000
--- a/core/test/com/google/inject/internal/WeakKeySetTest.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/**
- * Copyright (C) 2014 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.internal;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.testing.GcFinalization;
-import com.google.inject.AbstractModule;
-import com.google.inject.Binding;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.Scope;
-import com.google.inject.TypeLiteral;
-import com.google.inject.internal.BindingImpl;
-import com.google.inject.internal.Errors;
-/*if[AOP]*/
-import com.google.inject.internal.MethodAspect;
-/*end[AOP]*/
-import com.google.inject.internal.State;
-import com.google.inject.internal.WeakKeySet;
-import com.google.inject.spi.ProvisionListenerBinding;
-import com.google.inject.spi.ScopeBinding;
-import com.google.inject.spi.TypeConverterBinding;
-import com.google.inject.spi.TypeListenerBinding;
-
-import junit.framework.TestCase;
-
-import java.lang.annotation.Annotation;
-import java.lang.ref.WeakReference;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Tests for {@link WeakKeySet}.
- * <p>
- * Multibinding specific tests can be found in MultibinderTest and MapBinderTest.
- * 
- * @author dweis@google.com (Daniel Weis)
- */
-public class WeakKeySetTest extends TestCase {
-
-  private WeakKeySet set;
-
-  @Override
-  protected void setUp() throws Exception {
-    set = new WeakKeySet(new Object());
-  }
-
-  public void testEviction() {
-    TestState state = new TestState();
-    Key<Integer> key = Key.get(Integer.class);
-    Object source = new Object();
-    
-    WeakReference<Key<Integer>> weakKeyRef = new WeakReference<Key<Integer>>(key);
-
-    set.add(key, state, source);
-    assertTrue(set.contains(key));
-    assertEquals(1, set.getSources(key).size());
-    assertTrue(set.getSources(key).contains(source));
-
-    state = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertFalse(set.contains(Key.get(Integer.class)));
-    assertNull(set.getSources(Key.get(Integer.class)));
-
-    // Ensure there are no hanging references.
-    key = null;
-    GcFinalization.awaitClear(weakKeyRef);
-  }
-  
-  public void testEviction_nullSource() {
-    TestState state = new TestState();
-    Key<Integer> key = Key.get(Integer.class);
-    Object source = null;
-    
-    WeakReference<Key<Integer>> weakKeyRef = new WeakReference<Key<Integer>>(key);
-
-    set.add(key, state, source);
-    assertTrue(set.contains(key));
-    assertEquals(1, set.getSources(key).size());
-    assertTrue(set.getSources(key).contains(source));
-
-    state = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertFalse(set.contains(Key.get(Integer.class)));
-    assertNull(set.getSources(Key.get(Integer.class)));
-
-    // Ensure there are no hanging references.
-    key = null;
-    GcFinalization.awaitClear(weakKeyRef);
-  }
-
-  public void testEviction_keyOverlap_2x() {
-    TestState state1 = new TestState();
-    TestState state2 = new TestState();
-    Key<Integer> key1 = Key.get(Integer.class);
-    Key<Integer> key2 = Key.get(Integer.class);
-    Object source1 = new Object();
-    Object source2 = new Object();
-
-    set.add(key1, state1, source1);
-    assertTrue(set.contains(key1));
-    assertEquals(1, set.getSources(key1).size());
-    assertTrue(set.getSources(key1).contains(source1));
-
-    set.add(key2, state2, source2);
-    assertTrue(set.contains(key2));
-    assertEquals(2, set.getSources(key2).size());
-    assertTrue(set.getSources(key2).containsAll(Arrays.asList(source1, source2)));
-
-    WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
-    WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
-    WeakReference<Object> weakSource1Ref = new WeakReference<Object>(source1);
-    WeakReference<Object> weakSource2Ref = new WeakReference<Object>(source2);
-
-    Key<Integer> key = key1 = key2 = Key.get(Integer.class);
-    state1 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertTrue(set.contains(key));
-    assertEquals(1, set.getSources(key).size());
-    assertTrue(set.getSources(key).contains(source2));
-    assertFalse(set.getSources(key).contains(source1));
-
-    source1 = source2 = null;
-    
-    GcFinalization.awaitClear(weakSource1Ref);
-    // Key1 will be referenced as the key in the sources backingSet and won't be
-    // GC'd.
-    
-    // Should not be GC'd until state2 goes away.
-    assertNotNull(weakSource2Ref.get());
-
-    state2 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertFalse(set.contains(key));
-    assertNull(set.getSources(key));
-
-    GcFinalization.awaitClear(weakKey2Ref);
-    GcFinalization.awaitClear(weakSource2Ref);
-    // Now that the backing set is emptied, key1 is released.
-    GcFinalization.awaitClear(weakKey1Ref);
-  }
-  
-  public void testNoEviction_keyOverlap_2x() {
-    TestState state1 = new TestState();
-    TestState state2 = new TestState();
-    Key<Integer> key1 = Key.get(Integer.class);
-    Key<Integer> key2 = Key.get(Integer.class);
-    Object source1 = new Object();
-    Object source2 = new Object();
-
-    set.add(key1, state1, source1);
-    assertTrue(set.contains(key1));
-    assertEquals(1, set.getSources(key1).size());
-    assertTrue(set.getSources(key1).contains(source1));
-
-    set.add(key2, state2, source2);
-    assertTrue(set.contains(key2));
-    assertEquals(2, set.getSources(key2).size());
-    assertTrue(set.getSources(key1).containsAll(Arrays.asList(source1, source2)));
-
-    WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
-    WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
-
-    Key<Integer> key = key1 = key2 = Key.get(Integer.class);
-
-    GcFinalization.awaitFullGc();
-
-    assertTrue(set.contains(key));
-    assertEquals(2, set.getSources(key).size());
-    assertTrue(set.getSources(key1).containsAll(Arrays.asList(source1, source2)));
-
-    // Ensure the keys don't get GC'd when states are still referenced. key1 will be present in the
-    // as the map key but key2 could be GC'd if the implementation does something wrong.
-    assertNotNull(weakKey1Ref.get());
-    assertNotNull(weakKey2Ref.get());
-  }
-
-  public void testEviction_keyAndSourceOverlap_null() {
-    TestState state1 = new TestState();
-    TestState state2 = new TestState();
-    Key<Integer> key1 = Key.get(Integer.class);
-    Key<Integer> key2 = Key.get(Integer.class);
-    Object source = null;
-
-    set.add(key1, state1, source);
-    assertTrue(set.contains(key1));
-    assertEquals(1, set.getSources(key1).size());
-    assertTrue(set.getSources(key1).contains(source));
-
-    set.add(key2, state2, source);
-    assertTrue(set.contains(key2));
-
-    // Same source so still only one value.
-    assertEquals(1, set.getSources(key2).size());
-    assertTrue(set.getSources(key1).contains(source));
-
-    WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
-    WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
-    WeakReference<Object> weakSourceRef = new WeakReference<Object>(source);
-
-    Key<Integer> key = key1 = key2 = Key.get(Integer.class);
-    state1 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertTrue(set.contains(key));
-
-    // Should still have a single source.
-    assertEquals(1, set.getSources(key).size());
-    assertTrue(set.getSources(key1).contains(source));
-    
-    source = null;
-
-    GcFinalization.awaitClear(weakSourceRef);
-    // Key1 will be referenced as the key in the sources backingSet and won't be
-    // GC'd.
-
-    state2 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertFalse(set.contains(key));
-    assertNull(set.getSources(key));
-
-    GcFinalization.awaitClear(weakKey2Ref);
-    GcFinalization.awaitClear(weakSourceRef);
-    // Now that the backing set is emptied, key1 is released.
-    GcFinalization.awaitClear(weakKey1Ref);
-  }
-  
-  public void testEviction_keyAndSourceOverlap_nonNull() {
-    TestState state1 = new TestState();
-    TestState state2 = new TestState();
-    Key<Integer> key1 = Key.get(Integer.class);
-    Key<Integer> key2 = Key.get(Integer.class);
-    Object source = new Object();
-
-    set.add(key1, state1, source);
-    assertTrue(set.contains(key1));
-    assertEquals(1, set.getSources(key1).size());
-    assertTrue(set.getSources(key1).contains(source));
-
-    set.add(key2, state2, source);
-    assertTrue(set.contains(key2));
-
-    // Same source so still only one value.
-    assertEquals(1, set.getSources(key2).size());
-    assertTrue(set.getSources(key1).contains(source));
-
-    WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
-    WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
-    WeakReference<Object> weakSourceRef = new WeakReference<Object>(source);
-
-    Key<Integer> key = key1 = key2 = Key.get(Integer.class);
-    state1 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertTrue(set.contains(key));
-
-    // Should still have a single source.
-    assertEquals(1, set.getSources(key).size());
-    assertTrue(set.getSources(key1).contains(source));
-    
-    source = null;
-
-    GcFinalization.awaitFullGc();
-    assertNotNull(weakSourceRef.get());
-    // Key1 will be referenced as the key in the sources backingSet and won't be
-    // GC'd.
-
-    state2 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertFalse(set.contains(key));
-    assertNull(set.getSources(key));
-
-    GcFinalization.awaitClear(weakKey2Ref);
-    GcFinalization.awaitClear(weakSourceRef);
-    // Now that the backing set is emptied, key1 is released.
-    GcFinalization.awaitClear(weakKey1Ref);
-  }
-
-  public void testEviction_keyOverlap_3x() {
-    TestState state1 = new TestState();
-    TestState state2 = new TestState();
-    TestState state3 = new TestState();
-    Key<Integer> key1 = Key.get(Integer.class);
-    Key<Integer> key2 = Key.get(Integer.class);
-    Key<Integer> key3 = Key.get(Integer.class);
-    Object source1 = new Object();
-    Object source2 = new Object();
-    Object source3 = new Object();
-
-    set.add(key1, state1, source1);
-    assertTrue(set.contains(key1));
-    assertEquals(1, set.getSources(key1).size());
-    assertTrue(set.getSources(key1).contains(source1));
-
-    set.add(key2, state2, source2);
-    assertTrue(set.contains(key2));
-    assertEquals(2, set.getSources(key2).size());
-    assertTrue(set.getSources(key1).containsAll(Arrays.asList(source1, source2)));
-
-    set.add(key3, state3, source3);
-    assertTrue(set.contains(key3));
-    assertEquals(3, set.getSources(key3).size());
-    assertTrue(set.getSources(key1).containsAll(Arrays.asList(source1, source2, source3)));
-
-    WeakReference<Key<Integer>> weakKey1Ref = new WeakReference<Key<Integer>>(key1);
-    WeakReference<Key<Integer>> weakKey2Ref = new WeakReference<Key<Integer>>(key2);
-    WeakReference<Key<Integer>> weakKey3Ref = new WeakReference<Key<Integer>>(key3);
-    WeakReference<Object> weakSource1Ref = new WeakReference<Object>(source1);
-    WeakReference<Object> weakSource2Ref = new WeakReference<Object>(source2);
-    WeakReference<Object> weakSource3Ref = new WeakReference<Object>(source3);
-
-    Key<Integer> key = key1 = key2 = key3 = Key.get(Integer.class);
-    state1 = null;
-
-    GcFinalization.awaitFullGc();
-
-    assertTrue(set.contains(key));
-    assertEquals(2, set.getSources(key).size());
-    assertTrue(set.getSources(key).containsAll(Arrays.asList(source2, source3)));
-
-    source1 = null;
-    // Key1 will be referenced as the key in the sources backingSet and won't be
-    // GC'd.
-    GcFinalization.awaitClear(weakSource1Ref);
-
-    state2 = null;
-    GcFinalization.awaitFullGc();
-
-    assertTrue(set.contains(key));
-    assertEquals(1, set.getSources(key).size());
-    assertTrue(set.getSources(key).contains(source3));
-
-    GcFinalization.awaitClear(weakKey2Ref);
-    
-    source2 = null;
-    GcFinalization.awaitClear(weakSource2Ref);
-    // Key1 will be referenced as the key in the sources backingSet and won't be
-    // GC'd.
-
-    state3 = null;
-    GcFinalization.awaitFullGc();
-
-    assertFalse(set.contains(Key.get(Integer.class)));
-    assertNull(set.getSources(Key.get(Integer.class)));
-
-    GcFinalization.awaitClear(weakKey3Ref);
-    source3 = null;
-    GcFinalization.awaitClear(weakSource3Ref);
-    // Now that the backing set is emptied, key1 is released.
-    GcFinalization.awaitClear(weakKey1Ref);
-  }
-
-  public void testWeakKeySet_integration() {
-    Injector parentInjector = Guice.createInjector(new AbstractModule() {
-          @Override protected void configure() {
-            bind(Integer.class).toInstance(4);
-          }
-        });
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-
-    Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        bind(String.class).toInstance("bar");
-      }
-    });
-    WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
-    assertBlacklisted(parentInjector, Key.get(String.class));
-    
-    // Clear the ref, GC, and ensure that we are no longer blacklisting.
-    childInjector = null;
-    GcFinalization.awaitClear(weakRef);
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-  }
-  
-  public void testWeakKeySet_integration_multipleChildren() {
-    Injector parentInjector = Guice.createInjector(new AbstractModule() {
-          @Override protected void configure() {
-            bind(Integer.class).toInstance(4);
-          }
-        });
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-    assertNotBlacklisted(parentInjector, Key.get(Long.class));
-
-    Injector childInjector1 = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        bind(String.class).toInstance("foo");
-      }
-    });
-    WeakReference<Injector> weakRef1 = new WeakReference<Injector>(childInjector1);
-    assertBlacklisted(parentInjector, Key.get(String.class));
-    assertNotBlacklisted(parentInjector, Key.get(Long.class));
-    
-    Injector childInjector2 = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        bind(Long.class).toInstance(6L);
-      }
-    });
-    WeakReference<Injector> weakRef2 = new WeakReference<Injector>(childInjector2);
-    assertBlacklisted(parentInjector, Key.get(String.class));
-    assertBlacklisted(parentInjector, Key.get(Long.class));
-    
-    // Clear ref1, GC, and ensure that we still blacklist.
-    childInjector1 = null;
-    GcFinalization.awaitClear(weakRef1);
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-    assertBlacklisted(parentInjector, Key.get(Long.class));
-
-    // Clear the ref, GC, and ensure that we are no longer blacklisting.
-    childInjector2 = null;
-    GcFinalization.awaitClear(weakRef2);
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-    assertNotBlacklisted(parentInjector, Key.get(Long.class));
-  }
-  
-  public void testWeakKeySet_integration_multipleChildren_overlappingKeys() {
-    Injector parentInjector = Guice.createInjector(new AbstractModule() {
-          @Override protected void configure() {
-            bind(Integer.class).toInstance(4);
-          }
-        });
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-
-    Injector childInjector1 = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        bind(String.class).toInstance("foo");
-      }
-    });
-    WeakReference<Injector> weakRef1 = new WeakReference<Injector>(childInjector1);
-    assertBlacklisted(parentInjector, Key.get(String.class));
-    
-    Injector childInjector2 = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        bind(String.class).toInstance("bar");
-      }
-    });
-    WeakReference<Injector> weakRef2 = new WeakReference<Injector>(childInjector2);
-    assertBlacklisted(parentInjector, Key.get(String.class));
-    
-    // Clear ref1, GC, and ensure that we still blacklist.
-    childInjector1 = null;
-    GcFinalization.awaitClear(weakRef1);
-    assertBlacklisted(parentInjector, Key.get(String.class));
-
-    // Clear the ref, GC, and ensure that we are no longer blacklisting.
-    childInjector2 = null;
-    GcFinalization.awaitClear(weakRef2);
-    assertNotBlacklisted(parentInjector, Key.get(String.class));
-  }
-  
-  private static void assertBlacklisted(Injector injector, Key<?> key) {
-    assertBlacklistState(injector, key, true);
-  }
-  
-  private static void assertNotBlacklisted(Injector injector, Key<?> key) {
-    assertBlacklistState(injector, key, false);
-  }
-
-  private static void assertBlacklistState(Injector injector, Key<?> key, boolean isBlacklisted) {
-    assertEquals(isBlacklisted, ((InjectorImpl) injector).state.isBlacklisted(key));
-  }
-  
-  private static class TestState implements State {
-    public State parent() {
-      return new TestState();
-    }
-
-    public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
-      return null;
-    }
-
-    public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
-      throw new UnsupportedOperationException();
-    }
-
-    public void putBinding(Key<?> key, BindingImpl<?> binding) {
-      throw new UnsupportedOperationException();
-    }
-
-    public ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation) {
-      return null;
-    }
-
-    public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) {
-      throw new UnsupportedOperationException();
-    }
-
-    public void addConverter(TypeConverterBinding typeConverterBinding) {
-      throw new UnsupportedOperationException();
-    }
-
-    public TypeConverterBinding getConverter(String stringValue, TypeLiteral<?> type, Errors errors,
-        Object source) {
-      throw new UnsupportedOperationException();
-    }
-
-    public Iterable<TypeConverterBinding> getConvertersThisLevel() {
-      return ImmutableSet.of();
-    }
-
-    /*if[AOP]*/
-    public void addMethodAspect(MethodAspect methodAspect) {
-      throw new UnsupportedOperationException();
-    }
-
-    public ImmutableList<MethodAspect> getMethodAspects() {
-      return ImmutableList.of();
-    }
-    /*end[AOP]*/
-
-    public void addTypeListener(TypeListenerBinding typeListenerBinding) {
-      throw new UnsupportedOperationException();
-    }
-
-    public List<TypeListenerBinding> getTypeListenerBindings() {
-      return ImmutableList.of();
-    }
-
-    public void addProvisionListener(ProvisionListenerBinding provisionListenerBinding) {
-      throw new UnsupportedOperationException();
-    }
-
-    public List<ProvisionListenerBinding> getProvisionListenerBindings() {
-      return ImmutableList.of();
-    }
-
-    public void blacklist(Key<?> key, State state, Object source) {
-    }
-
-    public boolean isBlacklisted(Key<?> key) {
-      return true;
-    }
-
-    public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
-      throw new UnsupportedOperationException();
-    }
-
-    public Object lock() {
-      throw new UnsupportedOperationException();
-    }
-
-    public Map<Class<? extends Annotation>, Scope> getScopes() {
-      return ImmutableMap.of();
-    }
-  }
-}
diff --git a/extensions/.gitignore b/extensions/.gitignore
deleted file mode 100644
index 567609b..0000000
--- a/extensions/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-build/
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java
index 70be342..ba0671d 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/MapBinderTest.java
@@ -31,7 +31,6 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-import com.google.common.testing.GcFinalization;
 import com.google.inject.AbstractModule;
 import com.google.inject.Binding;
 import com.google.inject.BindingAnnotation;
@@ -61,7 +60,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Collections;
@@ -873,7 +871,7 @@
     expected.put(1, 1);
     expected.put(2, 2);
     assertEquals(expected, s1);
-  }
+  }  
 
   public void testTwoMapBindersAreDistinct() {
     Injector injector = Guice.createInjector(new AbstractModule() {
@@ -910,32 +908,4 @@
     assertFalse(map2Binding.containsElement(a));
     assertTrue(map2Binding.containsElement(b));
   }
-
-  // Tests for com.google.inject.internal.WeakKeySet not leaking memory.
-  public void testWeakKeySet_integration_mapbinder() {
-    Key<Map<String, String>> mapKey = Key.get(new TypeLiteral<Map<String, String>>() {});
-    
-    Injector parentInjector = Guice.createInjector(new AbstractModule() {
-          @Override protected void configure() {
-            bind(String.class).toInstance("hi");
-          }
-        });
-    WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
-
-    Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        MapBinder<String, String> binder =
-            MapBinder.newMapBinder(binder(), String.class, String.class);
-        binder.addBinding("bar").toInstance("foo");
-      }
-    });
-    WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
-    WeakKeySetUtils.assertBlacklisted(parentInjector, mapKey);
-    
-    // Clear the ref, GC, and ensure that we are no longer blacklisting.
-    childInjector = null;
-    
-    GcFinalization.awaitClear(weakRef);
-    WeakKeySetUtils.assertNotBlacklisted(parentInjector, mapKey);
-  }
 }
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java
index d317525..9494e5e 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/MultibinderTest.java
@@ -34,7 +34,6 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import com.google.common.testing.GcFinalization;
 import com.google.inject.AbstractModule;
 import com.google.inject.Binding;
 import com.google.inject.BindingAnnotation;
@@ -73,7 +72,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Collections;
@@ -1131,31 +1129,4 @@
     assertFalse(collector.optionalbinding.containsElement(b));
     assertTrue(collector.optionalbinding.containsElement(c));
   }
-  
-  // Tests for com.google.inject.internal.WeakKeySet not leaking memory.
-  public void testWeakKeySet_integration_multibinder() {
-    Key<Set<String>> setKey = Key.get(new TypeLiteral<Set<String>>() {});
-
-    Injector parentInjector = Guice.createInjector(new AbstractModule() {
-          @Override protected void configure() {
-            bind(String.class).toInstance("hi");
-          }
-        });
-    WeakKeySetUtils.assertNotBlacklisted(parentInjector, setKey);
-
-    Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
-      @Override protected void configure() {
-        Multibinder<String> binder = Multibinder.newSetBinder(binder(), String.class);
-        binder.addBinding().toInstance("foo");
-      }
-    });
-    WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
-    WeakKeySetUtils.assertBlacklisted(parentInjector, setKey);
-   
-    // Clear the ref, GC, and ensure that we are no longer blacklisting.
-    childInjector = null;
-   
-    GcFinalization.awaitClear(weakRef);
-    WeakKeySetUtils.assertNotBlacklisted(parentInjector, setKey);
-  }
 }
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
index 246c7a3..1393e0c 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
@@ -29,7 +29,6 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
-import com.google.common.testing.GcFinalization;
 import com.google.inject.AbstractModule;
 import com.google.inject.Binding;
 import com.google.inject.BindingAnnotation;
@@ -60,7 +59,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.util.List;
 import java.util.Map.Entry;
@@ -913,30 +911,6 @@
     assertEquals(2, i2.intValue());
   }
   
- // Tests for com.google.inject.internal.WeakKeySet not leaking memory.
- public void testWeakKeySet_integration() {   
-   Injector parentInjector = Guice.createInjector(new AbstractModule() {
-         @Override protected void configure() {
-           bind(String.class).toInstance("hi");
-         }
-       });
-   WeakKeySetUtils.assertNotBlacklisted(parentInjector, Key.get(Integer.class));
-
-   Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
-     @Override protected void configure() {
-       OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault().toInstance(4);
-     }
-   });
-   WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
-   WeakKeySetUtils.assertBlacklisted(parentInjector, Key.get(Integer.class));
-   
-   // Clear the ref, GC, and ensure that we are no longer blacklisting.
-   childInjector = null;
-   
-   GcFinalization.awaitClear(weakRef);
-   WeakKeySetUtils.assertNotBlacklisted(parentInjector, Key.get(Integer.class));
- }
-  
   @SuppressWarnings("unchecked") 
   private <V> Set<V> setOf(V... elements) {
     return ImmutableSet.copyOf(elements);
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/WeakKeySetUtils.java b/extensions/multibindings/test/com/google/inject/multibindings/WeakKeySetUtils.java
deleted file mode 100644
index 0dc5a8e..0000000
--- a/extensions/multibindings/test/com/google/inject/multibindings/WeakKeySetUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Copyright (C) 2014 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.multibindings;
-
-import com.google.inject.Injector;
-import com.google.inject.Key;
-
-import junit.framework.TestCase;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-/**
- * Utilities for verifying com.google.inject.internal.WeakKeySet is not leaking memory.
- * 
- * @author dweis@google.com (Daniel Weis)
- */
-final class WeakKeySetUtils {
-  
-  private WeakKeySetUtils() {}
-  
-  static void assertBlacklisted(Injector injector, Key<?> key) {
-    assertBlacklistState(injector, key, true);
-  }
- 
-  static void assertNotBlacklisted(Injector injector, Key<?> key) {
-    assertBlacklistState(injector, key, false);
-  }
-
-  private static final Field stateField;
-  private static final Method isBlacklistedMethod; 
-  static {
-    try {
-      stateField =
-          Class.forName("com.google.inject.internal.InjectorImpl").getDeclaredField("state");
-      stateField.setAccessible(true);
-      isBlacklistedMethod =
-          Class.forName("com.google.inject.internal.State").getMethod("isBlacklisted", Key.class);
-      isBlacklistedMethod.setAccessible(true);
-    } catch (Exception e) {
-      throw new Error(e);
-    }
-  }
-
-  private static void assertBlacklistState(Injector injector, Key<?> key, boolean isBlacklisted) {
-    try {
-      TestCase.assertEquals(
-          isBlacklisted,
-          ((Boolean) isBlacklistedMethod.invoke(stateField.get(injector), key)).booleanValue());
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-}
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 55ee9b8..1298e5d 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -55,16 +55,6 @@
       <scope>test</scope>
     </dependency>
     <!--
-     | Some extension tests depend on guava test libs which are not inherited
-     | from test scope.
-    -->
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava-testlib</artifactId>
-      <version>16.0.1</version>
-      <scope>test</scope>
-    </dependency>
-    <!--
      | Some extension tests depend on cglib which is not embedded
      | in an execution that doesn't include package.
     -->
diff --git a/lib/build/guava-testlib-16.0.1.jar b/lib/build/guava-testlib-16.0.1.jar
deleted file mode 100644
index 59150aa..0000000
--- a/lib/build/guava-testlib-16.0.1.jar
+++ /dev/null
Binary files differ