Renaming PrivateEnvironment to PrivateElements. I don't love this name 'cause I don't like plural names for classes; it reminds me of Collections, which is a utility class rather than an instantiable type.

Adding PrivateElements.getInjector().

Fixing toStrings() for Bindings and InjectorImpl.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@750 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/AbstractProcessor.java b/src/com/google/inject/AbstractProcessor.java
index f8269b9..9f58364 100644
--- a/src/com/google/inject/AbstractProcessor.java
+++ b/src/com/google/inject/AbstractProcessor.java
@@ -22,7 +22,7 @@
 import com.google.inject.spi.InjectionRequest;
 import com.google.inject.spi.InterceptorBinding;
 import com.google.inject.spi.Message;
-import com.google.inject.spi.PrivateEnvironment;
+import com.google.inject.spi.PrivateElements;
 import com.google.inject.spi.ProviderLookup;
 import com.google.inject.spi.ScopeBinding;
 import com.google.inject.spi.StaticInjectionRequest;
@@ -104,7 +104,7 @@
     return false;
   }
 
-  public Boolean visitPrivateEnvironment(PrivateEnvironment privateEnvironment) {
+  public Boolean visitPrivateElements(PrivateElements privateElements) {
     return false;
   }
 }
diff --git a/src/com/google/inject/BindingProcessor.java b/src/com/google/inject/BindingProcessor.java
index e51a751..bb20c56 100644
--- a/src/com/google/inject/BindingProcessor.java
+++ b/src/com/google/inject/BindingProcessor.java
@@ -37,13 +37,12 @@
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.InstanceBinding;
 import com.google.inject.spi.LinkedKeyBinding;
-import com.google.inject.spi.PrivateEnvironment;
+import com.google.inject.spi.PrivateElements;
 import com.google.inject.spi.ProviderBinding;
 import com.google.inject.spi.ProviderInstanceBinding;
 import com.google.inject.spi.ProviderKeyBinding;
 import com.google.inject.spi.UntargettedBinding;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -57,13 +56,10 @@
   private final List<CreationListener> creationListeners = Lists.newArrayList();
   private final Initializer initializer;
   private final List<Runnable> uninitializedBindings = Lists.newArrayList();
-  private final Map<PrivateEnvironment, InjectorImpl> environmentToInjector;
 
-  BindingProcessor(Errors errors, Initializer initializer,
-      Map<PrivateEnvironment, InjectorImpl> environmentToInjector) {
+  BindingProcessor(Errors errors, Initializer initializer) {
     super(errors);
     this.initializer = initializer;
-    this.environmentToInjector = environmentToInjector;
   }
 
   @Override public <T> Boolean visitBinding(Binding<T> command) {
@@ -176,11 +172,11 @@
       }
 
       public Void visitExposed(ExposedBinding<? extends T> binding) {
-        PrivateEnvironment privateEnvironment = binding.getPrivateEnvironment();
-        ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateEnvironment);
+        PrivateElements privateElements = binding.getPrivateElements();
+        ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
         creationListeners.add(exposedKeyFactory);
         putBinding(new ExposedBindingImpl<T>(
-            injector, source, key, exposedKeyFactory, privateEnvironment));
+            injector, source, key, exposedKeyFactory, privateElements));
         return null;
       }
 
@@ -214,9 +210,9 @@
     }
   }
 
-  public void runCreationListeners(Map<PrivateEnvironment, InjectorImpl> privateInjectors) {
+  public void runCreationListeners() {
     for (CreationListener creationListener : creationListeners) {
-      creationListener.notify(privateInjectors, errors);
+      creationListener.notify(errors);
     }
   }
 
@@ -249,7 +245,7 @@
   private boolean isOkayDuplicate(Binding<?> original, BindingImpl<?> binding) {
     if (original instanceof ExposedBindingImpl) {
       ExposedBindingImpl exposed = (ExposedBindingImpl) original;
-      InjectorImpl exposedFrom = environmentToInjector.get(exposed.getPrivateEnvironment());
+      InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector();
       return (exposedFrom == binding.getInjector());
     }
     return false;
@@ -271,6 +267,6 @@
   // TODO(jessewilson): fix BuiltInModule, then add Stage
 
   interface CreationListener {
-    void notify(Map<PrivateEnvironment, InjectorImpl> privateInjectors, Errors errors);
+    void notify(Errors errors);
   }
 }
diff --git a/src/com/google/inject/BoundProviderFactory.java b/src/com/google/inject/BoundProviderFactory.java
index 8941750..6528a9b 100644
--- a/src/com/google/inject/BoundProviderFactory.java
+++ b/src/com/google/inject/BoundProviderFactory.java
@@ -22,8 +22,6 @@
 import com.google.inject.internal.InternalContext;
 import com.google.inject.internal.InternalFactory;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.PrivateEnvironment;
-import java.util.Map;
 
 /**
  * Delegates to a custom factory which is also bound in the injector.
@@ -44,7 +42,7 @@
     this.source = source;
   }
 
-  public void notify(Map<PrivateEnvironment, InjectorImpl> privateInjectors, Errors errors) {
+  public void notify(Errors errors) {
     try {
       providerFactory = injector.getInternalFactory(providerKey, errors.withSource(source));
     } catch (ErrorsException e) {
diff --git a/src/com/google/inject/ClassBindingImpl.java b/src/com/google/inject/ClassBindingImpl.java
index 8805583..5c5fd5b 100644
--- a/src/com/google/inject/ClassBindingImpl.java
+++ b/src/com/google/inject/ClassBindingImpl.java
@@ -69,8 +69,8 @@
   @Override public String toString() {
     return new ToStringBuilder(ConstructorBinding.class)
         .add("key", getKey())
-        .add("scope", getScoping())
         .add("source", getSource())
+        .add("scope", getScoping())
         .toString();
   }
 }
diff --git a/src/com/google/inject/ExposedKeyFactory.java b/src/com/google/inject/ExposedKeyFactory.java
index 0ecff01..c08786c 100644
--- a/src/com/google/inject/ExposedKeyFactory.java
+++ b/src/com/google/inject/ExposedKeyFactory.java
@@ -22,23 +22,29 @@
 import com.google.inject.internal.InternalContext;
 import com.google.inject.internal.InternalFactory;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.PrivateEnvironment;
-import java.util.Map;
+import com.google.inject.spi.PrivateElements;
 
+/**
+ * This factory exists in a parent injector. When invoked, it retrieves its value from a child
+ * injector.
+ */
 class ExposedKeyFactory<T> implements InternalFactory<T>, BindingProcessor.CreationListener {
   private final Key<T> key;
-  private final PrivateEnvironment privateEnvironment;
+  private final PrivateElements privateElements;
   private BindingImpl<T> delegate;
 
-  public ExposedKeyFactory(Key<T> key, PrivateEnvironment privateEnvironment) {
+  public ExposedKeyFactory(Key<T> key, PrivateElements privateElements) {
     this.key = key;
-    this.privateEnvironment = privateEnvironment;
+    this.privateElements = privateElements;
   }
 
-  public void notify(Map<PrivateEnvironment, InjectorImpl> privateInjectors, Errors errors) {
-    InjectorImpl privateInjector = privateInjectors.get(privateEnvironment);
+  public void notify(Errors errors) {
+    InjectorImpl privateInjector = (InjectorImpl) privateElements.getInjector();
     BindingImpl<T> explicitBinding = privateInjector.state.getExplicitBinding(key);
 
+    // validate that the child injector has its own factory. If the getInternalFactory() returns
+    // this, then that child injector doesn't have a factory (and getExplicitBinding has returned
+    // its parent's binding instead
     if (explicitBinding.getInternalFactory() == this) {
       errors.withSource(explicitBinding.getSource()).exposedButNotBound(key);
       return;
diff --git a/src/com/google/inject/FactoryProxy.java b/src/com/google/inject/FactoryProxy.java
index 761450a..d56d7ef 100644
--- a/src/com/google/inject/FactoryProxy.java
+++ b/src/com/google/inject/FactoryProxy.java
@@ -23,8 +23,6 @@
 import com.google.inject.internal.InternalFactory;
 import com.google.inject.internal.ToStringBuilder;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.PrivateEnvironment;
-import java.util.Map;
 
 /**
  * A placeholder which enables us to swap in the real factory once the injector is created.
@@ -45,7 +43,7 @@
     this.source = source;
   }
 
-  public void notify(Map<PrivateEnvironment, InjectorImpl> privateInjectors, final Errors errors) {
+  public void notify(final Errors errors) {
     try {
       targetFactory = injector.getInternalFactory(targetKey, errors.withSource(source));
     } catch (ErrorsException e) {
diff --git a/src/com/google/inject/InjectorBuilder.java b/src/com/google/inject/InjectorBuilder.java
index d7203f5..b1a59a2 100644
--- a/src/com/google/inject/InjectorBuilder.java
+++ b/src/com/google/inject/InjectorBuilder.java
@@ -18,14 +18,12 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
 import com.google.inject.internal.BindingImpl;
 import com.google.inject.internal.Errors;
 import com.google.inject.internal.ErrorsException;
 import com.google.inject.internal.InternalContext;
 import com.google.inject.internal.Stopwatch;
 import com.google.inject.spi.Dependency;
-import com.google.inject.spi.PrivateEnvironment;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -60,14 +58,13 @@
   private final Initializer initializer = new Initializer();
   private final BindingProcessor bindingProcesor;
   private final InjectionRequestProcessor injectionRequestProcessor;
-  private final Map<PrivateEnvironment, InjectorImpl> environmentToInjector = Maps.newHashMap();
 
   private final InjectorShell.Builder shellBuilder = new InjectorShell.Builder();
   private List<InjectorShell> shells;
 
   InjectorBuilder() {
     injectionRequestProcessor = new InjectionRequestProcessor(errors, initializer);
-    bindingProcesor = new BindingProcessor(errors, initializer, environmentToInjector);
+    bindingProcesor = new BindingProcessor(errors, initializer);
   }
 
   /**
@@ -102,8 +99,7 @@
     // Synchronize while we're building up the bindings and other injector state. This ensures that
     // the JIT bindings in the parent injector don't change while we're being built
     synchronized (shellBuilder.lock()) {
-      shells = shellBuilder.build(
-          initializer, bindingProcesor, environmentToInjector, stopwatch, errors);
+      shells = shellBuilder.build(initializer, bindingProcesor, stopwatch, errors);
       stopwatch.resetAndLog("Injector construction");
 
       initializeStatically();
@@ -132,7 +128,7 @@
     injectionRequestProcessor.process(shells);
     stopwatch.resetAndLog("Collecting injection requests");
 
-    bindingProcesor.runCreationListeners(environmentToInjector);
+    bindingProcesor.runCreationListeners();
     stopwatch.resetAndLog("Binding validation");
 
     injectionRequestProcessor.validate();
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index 52dc7d4..40f01a0 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -45,6 +45,7 @@
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.ProviderBinding;
+import com.google.inject.spi.ProviderKeyBinding;
 import com.google.inject.util.Providers;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
@@ -229,6 +230,13 @@
     public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) {
       return visitor.visitProviderBinding(this);
     }
+
+    @Override public String toString() {
+      return new ToStringBuilder(ProviderKeyBinding.class)
+          .add("key", getKey())
+          .add("providedKey", getProvidedKey())
+          .toString();
+    }
   }
 
   /**
@@ -320,8 +328,8 @@
     @Override public String toString() {
       return new ToStringBuilder(ConvertedConstantBinding.class)
           .add("key", getKey())
-          .add("value", value)
           .add("sourceKey", getSourceKey())
+          .add("value", value)
           .toString();
     }
   }
@@ -867,7 +875,7 @@
 
   public String toString() {
     return new ToStringBuilder(Injector.class)
-        .add("bindings", state.getExplicitBindingsThisLevel())
+        .add("bindings", state.getExplicitBindingsThisLevel().values())
         .toString();
   }
 }
diff --git a/src/com/google/inject/InjectorShell.java b/src/com/google/inject/InjectorShell.java
index b03bcab..365f1c1 100644
--- a/src/com/google/inject/InjectorShell.java
+++ b/src/com/google/inject/InjectorShell.java
@@ -25,6 +25,7 @@
 import com.google.inject.internal.ErrorsException;
 import com.google.inject.internal.InternalContext;
 import com.google.inject.internal.InternalFactory;
+import com.google.inject.internal.PrivateElementsImpl;
 import com.google.inject.internal.ProviderInstanceBindingImpl;
 import com.google.inject.internal.Scoping;
 import com.google.inject.internal.SourceProvider;
@@ -33,9 +34,8 @@
 import com.google.inject.spi.Element;
 import com.google.inject.spi.Elements;
 import com.google.inject.spi.InjectionPoint;
-import com.google.inject.spi.PrivateEnvironment;
+import com.google.inject.spi.PrivateElements;
 import java.util.List;
-import java.util.Map;
 import java.util.logging.Logger;
 
 /**
@@ -48,16 +48,16 @@
 
   private final List<Element> elements;
   private final InjectorImpl injector;
-  private final PrivateEnvironment privateEnvironment;
+  private final PrivateElements privateElements;
 
   private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
-    this.privateEnvironment = builder.privateEnvironment;
+    this.privateElements = builder.privateElements;
     this.elements = elements;
     this.injector = injector;
   }
 
-  PrivateEnvironment getPrivateEnvironment() {
-    return privateEnvironment;
+  PrivateElements getPrivateElements() {
+    return privateElements;
   }
 
   InjectorImpl getInjector() {
@@ -79,7 +79,7 @@
     private Stage stage;
 
     /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */
-    private PrivateEnvironment privateEnvironment;
+    private PrivateElementsImpl privateElements;
 
     Builder parent(InjectorImpl parent) {
       this.parent = parent;
@@ -92,9 +92,9 @@
       return this;
     }
 
-    Builder privateEnvironment(PrivateEnvironment privateEnvironment) {
-      this.privateEnvironment = privateEnvironment;
-      this.elements.addAll(privateEnvironment.getElements());
+    Builder privateElements(PrivateElements privateElements) {
+      this.privateElements = (PrivateElementsImpl) privateElements;
+      this.elements.addAll(privateElements.getElements());
       return this;
     }
 
@@ -115,15 +115,14 @@
      * primary injector will be first in the returned list.
      */
     List<InjectorShell> build(Initializer initializer, BindingProcessor bindingProcessor,
-        Map<PrivateEnvironment, InjectorImpl> environmentToInjector,
         Stopwatch stopwatch, Errors errors) {
       checkState(stage != null, "Stage not initialized");
-      checkState(privateEnvironment == null || parent != null, "PrivateEnvironment with no parent");
+      checkState(privateElements == null || parent != null, "PrivateElements with no parent");
       checkState(state != null, "no state. Did you remember to lock() ?");
 
       InjectorImpl injector = new InjectorImpl(parent, state, initializer);
-      if (privateEnvironment != null) {
-        environmentToInjector.put(privateEnvironment, injector);
+      if (privateElements != null) {
+        privateElements.initInjector(injector);
       }
 
       // bind Stage and Singleton if this is a top-level injector
@@ -157,11 +156,10 @@
       injectorShells.add(new InjectorShell(this, elements, injector));
 
       // recursively build child shells
-      PrivateEnvironmentProcessor processor = new PrivateEnvironmentProcessor(errors, stage);
+      PrivateElementProcessor processor = new PrivateElementProcessor(errors, stage);
       processor.process(injector, elements);
       for (Builder builder : processor.getInjectorShellBuilders()) {
-        injectorShells.addAll(
-            builder.build(initializer, bindingProcessor, environmentToInjector, stopwatch, errors));
+        injectorShells.addAll(builder.build(initializer, bindingProcessor, stopwatch, errors));
       }
       stopwatch.resetAndLog("Private environment creation");
 
diff --git a/src/com/google/inject/PrivateEnvironmentProcessor.java b/src/com/google/inject/PrivateElementProcessor.java
similarity index 80%
rename from src/com/google/inject/PrivateEnvironmentProcessor.java
rename to src/com/google/inject/PrivateElementProcessor.java
index 438fe67..1e4fff2 100644
--- a/src/com/google/inject/PrivateEnvironmentProcessor.java
+++ b/src/com/google/inject/PrivateElementProcessor.java
@@ -18,7 +18,7 @@
 
 import com.google.common.collect.Lists;
 import com.google.inject.internal.Errors;
-import com.google.inject.spi.PrivateEnvironment;
+import com.google.inject.spi.PrivateElements;
 import java.util.List;
 
 /**
@@ -26,21 +26,21 @@
  *
  * @author jessewilson@google.com (Jesse Wilson)
  */
-class PrivateEnvironmentProcessor extends AbstractProcessor {
+class PrivateElementProcessor extends AbstractProcessor {
 
   private final Stage stage;
   private final List<InjectorShell.Builder> injectorShellBuilders = Lists.newArrayList();
 
-  PrivateEnvironmentProcessor(Errors errors, Stage stage) {
+  PrivateElementProcessor(Errors errors, Stage stage) {
     super(errors);
     this.stage = stage;
   }
 
-  @Override public Boolean visitPrivateEnvironment(PrivateEnvironment privateEnvironment) {
+  @Override public Boolean visitPrivateElements(PrivateElements privateElements) {
     InjectorShell.Builder builder = new InjectorShell.Builder()
         .parent(injector)
         .stage(stage)
-        .privateEnvironment(privateEnvironment);
+        .privateElements(privateElements);
     injectorShellBuilders.add(builder);
     return true;
   }
diff --git a/src/com/google/inject/internal/BindingBuilder.java b/src/com/google/inject/internal/BindingBuilder.java
index 5f65855..4c3cacd 100644
--- a/src/com/google/inject/internal/BindingBuilder.java
+++ b/src/com/google/inject/internal/BindingBuilder.java
@@ -28,7 +28,7 @@
 import com.google.inject.spi.Element;
 import com.google.inject.spi.InjectionPoint;
 import com.google.inject.spi.Message;
-import com.google.inject.spi.PrivateEnvironment;
+import com.google.inject.spi.PrivateElements;
 import java.lang.annotation.Annotation;
 import java.util.List;
 import java.util.Set;
@@ -131,13 +131,13 @@
     return this;
   }
 
-  public ExposureBuilder<T> usingKeyFrom(PrivateEnvironment privateEnvironment) {
+  public ExposureBuilder<T> usingKeyFrom(PrivateElements privateElements) {
     checkNotTargetted();
     checkNotScoped();
 
     BindingImpl<T> base = getBinding();
     ExposedBindingImpl<T> exposedBinding = new ExposedBindingImpl<T>(
-        base.getSource(), base.getKey(), base.getScoping(), privateEnvironment);
+        base.getSource(), base.getKey(), base.getScoping(), privateElements);
     setBinding(exposedBinding);
 
     return new ExposureBuilder<T>(this, exposedBinding);
diff --git a/src/com/google/inject/internal/ExposedBindingImpl.java b/src/com/google/inject/internal/ExposedBindingImpl.java
index 74a9198..c82a6eb 100644
--- a/src/com/google/inject/internal/ExposedBindingImpl.java
+++ b/src/com/google/inject/internal/ExposedBindingImpl.java
@@ -22,23 +22,23 @@
 import com.google.inject.spi.BindingTargetVisitor;
 import com.google.inject.spi.Dependency;
 import com.google.inject.spi.ExposedBinding;
-import com.google.inject.spi.PrivateEnvironment;
+import com.google.inject.spi.PrivateElements;
 import java.util.Set;
 
 public class ExposedBindingImpl<T> extends BindingImpl<T> implements ExposedBinding<T> {
 
-  private final PrivateEnvironment privateEnvironment;
+  private final PrivateElements privateElements;
 
   public ExposedBindingImpl(Injector injector, Object source, Key<T> key,
-      InternalFactory<T> factory, PrivateEnvironment privateEnvironment) {
+      InternalFactory<T> factory, PrivateElements privateElements) {
     super(injector, key, source, factory, Scoping.UNSCOPED);
-    this.privateEnvironment = privateEnvironment;
+    this.privateElements = privateElements;
   }
 
   public ExposedBindingImpl(Object source, Key<T> key, Scoping scoping,
-      PrivateEnvironment privateEnvironment) {
+      PrivateElements privateElements) {
     super(source, key, scoping);
-    this.privateEnvironment = privateEnvironment;
+    this.privateElements = privateElements;
   }
 
   public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
@@ -49,23 +49,23 @@
     return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
   }
 
-  public PrivateEnvironment getPrivateEnvironment() {
-    return privateEnvironment;
+  public PrivateElements getPrivateElements() {
+    return privateElements;
   }
 
   public BindingImpl<T> withScoping(Scoping scoping) {
-    return new ExposedBindingImpl<T>(getSource(), getKey(), scoping, privateEnvironment);
+    return new ExposedBindingImpl<T>(getSource(), getKey(), scoping, privateElements);
   }
 
   public ExposedBindingImpl<T> withKey(Key<T> key) {
-    return new ExposedBindingImpl<T>(getSource(), key, getScoping(), privateEnvironment);
+    return new ExposedBindingImpl<T>(getSource(), key, getScoping(), privateElements);
   }
 
   @Override public String toString() {
     return new ToStringBuilder(ExposedBinding.class)
         .add("key", getKey())
-        .add("privateEnvironment", privateEnvironment)
         .add("source", getSource())
+        .add("privateElements", privateElements)
         .toString();
   }
 }
diff --git a/src/com/google/inject/internal/InstanceBindingImpl.java b/src/com/google/inject/internal/InstanceBindingImpl.java
index 23db481..bb87f44 100644
--- a/src/com/google/inject/internal/InstanceBindingImpl.java
+++ b/src/com/google/inject/internal/InstanceBindingImpl.java
@@ -84,8 +84,8 @@
   @Override public String toString() {
     return new ToStringBuilder(InstanceBinding.class)
         .add("key", getKey())
-        .add("instance", instance)
         .add("source", getSource())
+        .add("instance", instance)
         .toString();
   }
 }
diff --git a/src/com/google/inject/internal/LinkedBindingImpl.java b/src/com/google/inject/internal/LinkedBindingImpl.java
index 956115b..01485ba 100644
--- a/src/com/google/inject/internal/LinkedBindingImpl.java
+++ b/src/com/google/inject/internal/LinkedBindingImpl.java
@@ -56,9 +56,9 @@
   @Override public String toString() {
     return new ToStringBuilder(LinkedKeyBinding.class)
         .add("key", getKey())
-        .add("target", targetKey)
-        .add("scope", getScoping())
         .add("source", getSource())
+        .add("scope", getScoping())
+        .add("target", targetKey)
         .toString();
   }
 }
diff --git a/src/com/google/inject/internal/LinkedProviderBindingImpl.java b/src/com/google/inject/internal/LinkedProviderBindingImpl.java
index 855c41f..fe3a39f 100644
--- a/src/com/google/inject/internal/LinkedProviderBindingImpl.java
+++ b/src/com/google/inject/internal/LinkedProviderBindingImpl.java
@@ -59,9 +59,9 @@
   @Override public String toString() {
     return new ToStringBuilder(ProviderKeyBinding.class)
         .add("key", getKey())
-        .add("provider", providerKey)
-        .add("scope", getScoping())
         .add("source", getSource())
+        .add("scope", getScoping())
+        .add("provider", providerKey)
         .toString();
   }
 }
diff --git a/src/com/google/inject/spi/PrivateEnvironment.java b/src/com/google/inject/internal/PrivateElementsImpl.java
similarity index 74%
rename from src/com/google/inject/spi/PrivateEnvironment.java
rename to src/com/google/inject/internal/PrivateElementsImpl.java
index 1cf7319..675d073 100644
--- a/src/com/google/inject/spi/PrivateEnvironment.java
+++ b/src/com/google/inject/internal/PrivateElementsImpl.java
@@ -14,26 +14,27 @@
  * limitations under the License.
  */
 
-package com.google.inject.spi;
+package com.google.inject.internal;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.internal.BindingBuilder.ExposureBuilder;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.ElementVisitor;
+import com.google.inject.spi.PrivateElements;
 import java.util.List;
 import java.util.Set;
 
 /**
- * A private environment whose configuration information is hidden from the enclosing environment
- * by default. See {@link com.google.inject.PrivateModule PrivateModule} for details.
- *
  * @author jessewilson@google.com (Jesse Wilson)
- * @since 2.0
  */
-public final class PrivateEnvironment implements Element {
+public final class PrivateElementsImpl implements PrivateElements {
 
   /*
    * This class acts as both a value object and as a builder. When getElements() is called, an
@@ -51,8 +52,9 @@
 
   /** lazily instantiated */
   private ImmutableSet<Key<?>> exposedKeys;
+  private Injector injector;
 
-  PrivateEnvironment(Object source) {
+  public PrivateElementsImpl(Object source) {
     this.source = checkNotNull(source, "source");
   }
 
@@ -60,9 +62,6 @@
     return source;
   }
 
-  /**
-   * Returns the configuration information in this private environment.
-   */
   public List<Element> getElements() {
     if (elements == null) {
       elements = ImmutableList.copyOf(elementsMutable);
@@ -72,9 +71,15 @@
     return elements;
   }
 
-  /**
-   * Returns the unique exposed keys for these private elements.
-   */
+  public Injector getInjector() {
+    return injector;
+  }
+
+  public void initInjector(Injector injector) {
+    checkState(this.injector == null, "injector already initialized");
+    this.injector = checkNotNull(injector, "injector");
+  }
+
   public Set<Key<?>> getExposedKeys() {
     if (exposedKeys == null) {
       Set<Key<?>> exposedKeysMutable = Sets.newLinkedHashSet();
@@ -89,14 +94,14 @@
   }
 
   public <T> T acceptVisitor(ElementVisitor<T> visitor) {
-    return visitor.visitPrivateEnvironment(this);
+    return visitor.visitPrivateElements(this);
   }
 
-  List<Element> getElementsMutable() {
+  public List<Element> getElementsMutable() {
     return elementsMutable;
   }
 
-  void addExposureBuilder(ExposureBuilder<?> exposureBuilder) {
+  public void addExposureBuilder(ExposureBuilder<?> exposureBuilder) {
     exposureBuilders.add(exposureBuilder);
   }
 }
diff --git a/src/com/google/inject/internal/ProviderInstanceBindingImpl.java b/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
index cb48359..a937a9b 100644
--- a/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
+++ b/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
@@ -81,9 +81,9 @@
   public String toString() {
     return new ToStringBuilder(ProviderInstanceBinding.class)
         .add("key", getKey())
-        .add("provider", providerInstance)
-        .add("scope", getScoping())
         .add("source", getSource())
+        .add("scope", getScoping())
+        .add("provider", providerInstance)
         .toString();
   }
 }
diff --git a/src/com/google/inject/spi/DefaultElementVisitor.java b/src/com/google/inject/spi/DefaultElementVisitor.java
index 9ab49ab..f97ac0b 100644
--- a/src/com/google/inject/spi/DefaultElementVisitor.java
+++ b/src/com/google/inject/spi/DefaultElementVisitor.java
@@ -69,7 +69,7 @@
     return visitElement(staticInjectionRequest);
   }
 
-  public V visitPrivateEnvironment(PrivateEnvironment privateEnvironment) {
-    return visitElement(privateEnvironment);
+  public V visitPrivateElements(PrivateElements privateElements) {
+    return visitElement(privateElements);
   }
 }
diff --git a/src/com/google/inject/spi/ElementVisitor.java b/src/com/google/inject/spi/ElementVisitor.java
index 19b1e8a..c10f44c 100644
--- a/src/com/google/inject/spi/ElementVisitor.java
+++ b/src/com/google/inject/spi/ElementVisitor.java
@@ -72,5 +72,5 @@
   /**
    * Visit a collection of configuration elements for a private environment.
    */
-  V visitPrivateEnvironment(PrivateEnvironment privateEnvironment);
+  V visitPrivateElements(PrivateElements privateElements);
 }
diff --git a/src/com/google/inject/spi/Elements.java b/src/com/google/inject/spi/Elements.java
index f1726ce..ebabfc9 100644
--- a/src/com/google/inject/spi/Elements.java
+++ b/src/com/google/inject/spi/Elements.java
@@ -39,6 +39,7 @@
 import com.google.inject.internal.BindingBuilder;
 import com.google.inject.internal.ConstantBindingBuilderImpl;
 import com.google.inject.internal.Errors;
+import com.google.inject.internal.PrivateElementsImpl;
 import com.google.inject.internal.ProviderMethodsModule;
 import com.google.inject.internal.SourceProvider;
 import com.google.inject.matcher.Matcher;
@@ -116,7 +117,7 @@
 
     /** The binder where exposed bindings will be created */
     private final RecordingBinder parent;
-    private final PrivateEnvironment privateEnvironment;
+    private final PrivateElementsImpl privateElements;
 
     private RecordingBinder(Stage stage) {
       this.stage = stage;
@@ -127,7 +128,7 @@
           Elements.class, RecordingBinder.class, AbstractModule.class,
           ConstantBindingBuilderImpl.class, AbstractBindingBuilder.class, BindingBuilder.class);
       this.parent = null;
-      this.privateEnvironment = null;
+      this.privateElements = null;
     }
 
     /** Creates a recording binder that's backed by {@code prototype}. */
@@ -141,18 +142,18 @@
       this.source = source;
       this.sourceProvider = sourceProvider;
       this.parent = prototype.parent;
-      this.privateEnvironment = prototype.privateEnvironment;
+      this.privateElements = prototype.privateElements;
     }
 
     /** Creates a private recording binder. */
-    private RecordingBinder(RecordingBinder parent, PrivateEnvironment privateEnvironment) {
+    private RecordingBinder(RecordingBinder parent, PrivateElementsImpl privateElements) {
       this.stage = parent.stage;
       this.modules = Sets.newHashSet();
-      this.elements = privateEnvironment.getElementsMutable();
+      this.elements = privateElements.getElementsMutable();
       this.source = parent.source;
       this.sourceProvider = parent.sourceProvider;
       this.parent = parent;
-      this.privateEnvironment = privateEnvironment;
+      this.privateElements = privateElements;
     }
 
     public void bindInterceptor(
@@ -273,9 +274,9 @@
     }
 
     public PrivateBinder newPrivateBinder() {
-      PrivateEnvironment privateEnvironment = new PrivateEnvironment(getSource());
-      elements.add(privateEnvironment);
-      return new RecordingBinder(this, privateEnvironment);
+      PrivateElementsImpl privateElements = new PrivateElementsImpl(getSource());
+      elements.add(privateElements);
+      return new RecordingBinder(this, privateElements);
     }
 
     public void expose(Key<?> key) {
@@ -291,7 +292,7 @@
     }
 
     private <T> AnnotatedElementBuilder exposeInternal(Key<T> key) {
-      if (privateEnvironment == null) {
+      if (privateElements == null) {
         addError("Cannot expose %s on a standard binder. "
             + "Exposed bindings are only applicable to private binders.", key);
         return new AnnotatedElementBuilder() {
@@ -303,8 +304,8 @@
       BindingBuilder<T> exposeBinding = new BindingBuilder<T>(
           this, parent.elements, getSource(), key);
 
-      BindingBuilder.ExposureBuilder<T> builder = exposeBinding.usingKeyFrom(privateEnvironment);
-      privateEnvironment.addExposureBuilder(builder);
+      BindingBuilder.ExposureBuilder<T> builder = exposeBinding.usingKeyFrom(privateElements);
+      privateElements.addExposureBuilder(builder);
       return builder;
     }
 
diff --git a/src/com/google/inject/spi/ExposedBinding.java b/src/com/google/inject/spi/ExposedBinding.java
index f220595..fe26071 100644
--- a/src/com/google/inject/spi/ExposedBinding.java
+++ b/src/com/google/inject/spi/ExposedBinding.java
@@ -29,6 +29,6 @@
   /**
    * Returns the enclosed environment that holds the original binding.
    */
-  PrivateEnvironment getPrivateEnvironment();
+  PrivateElements getPrivateElements();
 
 }
\ No newline at end of file
diff --git a/src/com/google/inject/spi/ModuleWriter.java b/src/com/google/inject/spi/ModuleWriter.java
index 6731129..1b29a40 100644
--- a/src/com/google/inject/spi/ModuleWriter.java
+++ b/src/com/google/inject/spi/ModuleWriter.java
@@ -40,7 +40,7 @@
  */
 public class ModuleWriter {
 
-  private final Map<PrivateEnvironment, PrivateBinder> environmentToBinder = Maps.newHashMap();
+  private final Map<PrivateElements, PrivateBinder> environmentToBinder = Maps.newHashMap();
 
   /**
    * Returns a module that executes the specified elements using this executing visitor.
@@ -102,8 +102,8 @@
         return null;
       }
 
-      public Void visitPrivateEnvironment(PrivateEnvironment privateEnvironment) {
-        writePrivateElements(binder, privateEnvironment);
+      public Void visitPrivateElements(PrivateElements privateElements) {
+        writePrivateElements(binder, privateElements);
         return null;
       }
     };
@@ -153,7 +153,7 @@
    * Writes the elements of the private environment to a new private binder and {@link
    * #setPrivateBinder associates} the two.
    */
-  protected void writePrivateElements(Binder binder, PrivateEnvironment element) {
+  protected void writePrivateElements(Binder binder, PrivateElements element) {
     PrivateBinder privateBinder = binder.withSource(element.getSource()).newPrivateBinder();
     setPrivateBinder(element, privateBinder);
     apply(privateBinder, element.getElements());
@@ -188,7 +188,7 @@
       }
 
       public ScopedBindingBuilder visitExposed(ExposedBinding<? extends T> binding) {
-        PrivateBinder privateBinder = getPrivateBinder(binding.getPrivateEnvironment());
+        PrivateBinder privateBinder = getPrivateBinder(binding.getPrivateElements());
         privateBinder.withSource(binding.getSource()).expose(key);
         return null;
       }
@@ -208,20 +208,20 @@
     });
   }
 
-  /** Associates {@code binder} with {@code privateEnvironment}. */
-  protected void setPrivateBinder(PrivateEnvironment privateEnvironment, PrivateBinder binder) {
-    checkArgument(!environmentToBinder.containsKey(privateEnvironment),
-        "A private binder already exists for %s", privateEnvironment);
-    environmentToBinder.put(privateEnvironment, binder);
+  /** Associates {@code binder} with {@code privateElements}. */
+  protected void setPrivateBinder(PrivateElements privateElements, PrivateBinder binder) {
+    checkArgument(!environmentToBinder.containsKey(privateElements),
+        "A private binder already exists for %s", privateElements);
+    environmentToBinder.put(privateElements, binder);
   }
 
   /**
-   * Returns the {@code binder} accociated with {@code privateEnvironment}. This can be used to
+   * Returns the {@code binder} accociated with {@code privateElements}. This can be used to
    * expose bindings to the enclosing environment.
    */
-  protected PrivateBinder getPrivateBinder(PrivateEnvironment privateEnvironment) {
-    PrivateBinder privateBinder = environmentToBinder.get(privateEnvironment);
-    checkArgument(privateBinder != null, "No private binder for %s", privateEnvironment);
+  protected PrivateBinder getPrivateBinder(PrivateElements privateElements) {
+    PrivateBinder privateBinder = environmentToBinder.get(privateElements);
+    checkArgument(privateBinder != null, "No private binder for %s", privateElements);
     return privateBinder;
   }
 
diff --git a/src/com/google/inject/spi/PrivateElements.java b/src/com/google/inject/spi/PrivateElements.java
new file mode 100644
index 0000000..ec08872
--- /dev/null
+++ b/src/com/google/inject/spi/PrivateElements.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2008 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.spi;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A private collection of elements that are hidden from the enclosing injector or module by
+ * default. See {@link com.google.inject.PrivateModule PrivateModule} for details.
+ *
+ * @author jessewilson@google.com (Jesse Wilson)
+ * @since 2.0
+ */
+public interface PrivateElements extends Element {
+
+  /**
+   * Returns the configuration information in this private environment.
+   */
+  List<Element> getElements();
+
+  /**
+   * Returns the child injector that hosts these private elements, or null if the elements haven't
+   * been used to create an injector.
+   */
+  Injector getInjector();
+
+  /**
+   * Returns the unique exposed keys for these private elements.
+   */
+  Set<Key<?>> getExposedKeys();
+}
diff --git a/test/com/google/inject/PrivateModuleTest.java b/test/com/google/inject/PrivateModuleTest.java
index 3beca2a..23d4d2e 100644
--- a/test/com/google/inject/PrivateModuleTest.java
+++ b/test/com/google/inject/PrivateModuleTest.java
@@ -16,10 +16,15 @@
 
 package com.google.inject;
 
+import com.google.common.collect.ImmutableSet;
 import static com.google.inject.Asserts.assertContains;
 import com.google.inject.binder.PrivateBinder;
 import com.google.inject.name.Named;
+import com.google.inject.name.Names;
 import static com.google.inject.name.Names.named;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.ExposedBinding;
+import com.google.inject.spi.PrivateElements;
 import junit.framework.TestCase;
 
 /**
@@ -420,4 +425,24 @@
   }
 
   interface C {}
+
+  public void testSpiAccess() {
+    Injector injector = Guice.createInjector(new PrivateModule() {
+          public void configurePrivateBindings() {
+            bind(String.class).annotatedWith(named("a")).toInstance("private");
+            bind(String.class).annotatedWith(named("b")).toInstance("exposed");
+            expose(String.class).annotatedWith(named("b"));
+          }
+        });
+
+    ExposedBinding<?> binding
+        = (ExposedBinding<?>) injector.getBinding(Key.get(String.class, Names.named("b")));
+    assertEquals(ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class))),
+        binding.getDependencies());
+    PrivateElements privateElements = binding.getPrivateElements();
+    assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class, named("b"))),
+        privateElements.getExposedKeys());
+    Injector privateInjector = privateElements.getInjector();
+    assertEquals("private", privateInjector.getInstance(Key.get(String.class, Names.named("a"))));
+  }
 }
diff --git a/test/com/google/inject/spi/ElementsTest.java b/test/com/google/inject/spi/ElementsTest.java
index f91f736..183c74e 100644
--- a/test/com/google/inject/spi/ElementsTest.java
+++ b/test/com/google/inject/spi/ElementsTest.java
@@ -718,7 +718,7 @@
         },
 
         new FailingElementVisitor() {
-          @Override public Void visitPrivateEnvironment(PrivateEnvironment one) {
+          @Override public Void visitPrivateElements(PrivateElements one) {
             assertEquals(collections, one.getExposedKeys());
             checkElements(one.getElements(),
                 new FailingElementVisitor() {
@@ -738,7 +738,7 @@
             assertEquals(arrayList, binding.getKey());
             binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
               @Override public Void visitExposed(ExposedBinding<? extends T> binding) {
-                assertEquals(collections, binding.getPrivateEnvironment().getExposedKeys());
+                assertEquals(collections, binding.getPrivateElements().getExposedKeys());
                 return null;
               }
             });
@@ -752,7 +752,7 @@
             assertEquals(collection, binding.getKey());
             binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
               @Override public Void visitExposed(ExposedBinding<? extends T> binding) {
-                assertEquals(collections, binding.getPrivateEnvironment().getExposedKeys());
+                assertEquals(collections, binding.getPrivateElements().getExposedKeys());
                 return null;
               }
             });
@@ -761,7 +761,7 @@
         },
 
         new FailingElementVisitor() {
-          @Override public Void visitPrivateEnvironment(PrivateEnvironment two) {
+          @Override public Void visitPrivateElements(PrivateElements two) {
             assertEquals(ab, two.getExposedKeys());
             assertEquals("1 ElementsTest.java", two.getSource());
             checkElements(two.getElements(),
@@ -784,7 +784,7 @@
             assertEquals("2 ElementsTest.java", binding.getSource());
             binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
               @Override public Void visitExposed(ExposedBinding<? extends T> binding) {
-                assertEquals(ab, binding.getPrivateEnvironment().getExposedKeys());
+                assertEquals(ab, binding.getPrivateElements().getExposedKeys());
                 return null;
               }
             });
@@ -799,7 +799,7 @@
             assertEquals("2 ElementsTest.java", binding.getSource());
             binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
               @Override public Void visitExposed(ExposedBinding<? extends T> binding) {
-                assertEquals(ab, binding.getPrivateEnvironment().getExposedKeys());
+                assertEquals(ab, binding.getPrivateElements().getExposedKeys());
                 return null;
               }
             });