InjectionRequests now expose their injection points (or throw an exception upon request)

Also added ConvertedConstantBinding.getSourceKey()

git-svn-id: https://google-guice.googlecode.com/svn/trunk@743 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/InjectionRequestProcessor.java b/src/com/google/inject/InjectionRequestProcessor.java
index 98bea85..c5b8b00 100644
--- a/src/com/google/inject/InjectionRequestProcessor.java
+++ b/src/com/google/inject/InjectionRequestProcessor.java
@@ -44,22 +44,22 @@
     this.initializer = initializer;
   }
 
-  @Override public Boolean visitStaticInjectionRequest(StaticInjectionRequest command) {
-    staticInjections.add(new StaticInjection(injector, command.getSource(), command.getType()));
+  @Override public Boolean visitStaticInjectionRequest(StaticInjectionRequest request) {
+    staticInjections.add(new StaticInjection(injector, request));
     return true;
   }
 
-  @Override public Boolean visitInjectionRequest(InjectionRequest command) {
+  @Override public Boolean visitInjectionRequest(InjectionRequest request) {
     Set<InjectionPoint> injectionPoints;
     try {
-      injectionPoints = InjectionPoint.forInstanceMethodsAndFields(
-          command.getInstance().getClass());
+      injectionPoints = request.getInjectionPoints();
     } catch (ConfigurationException e) {
       errors.merge(e.getErrorMessages());
       injectionPoints = e.getPartialValue();
     }
 
-    initializer.requestInjection(injector, command.getInstance(), command.getSource(), injectionPoints);
+    initializer.requestInjection(
+        injector, request.getInstance(), request.getSource(), injectionPoints);
     return true;
   }
 
@@ -79,20 +79,20 @@
   private class StaticInjection {
     final InjectorImpl injector;
     final Object source;
-    final Class<?> type;
+    final StaticInjectionRequest request;
     ImmutableList<SingleMemberInjector> memberInjectors;
 
-    public StaticInjection(InjectorImpl injector, Object source, Class type) {
+    public StaticInjection(InjectorImpl injector, StaticInjectionRequest request) {
       this.injector = injector;
-      this.source = source;
-      this.type = type;
+      this.source = request.getSource();
+      this.request = request;
     }
 
     void validate() {
       Errors errorsForMember = errors.withSource(source);
       Set<InjectionPoint> injectionPoints;
       try {
-        injectionPoints = InjectionPoint.forStaticMethodsAndFields(type);
+        injectionPoints = request.getInjectionPoints();
       } catch (ConfigurationException e) {
         errors.merge(e.getErrorMessages());
         injectionPoints = e.getPartialValue();
diff --git a/src/com/google/inject/InjectorImpl.java b/src/com/google/inject/InjectorImpl.java
index c767415..f020cec 100644
--- a/src/com/google/inject/InjectorImpl.java
+++ b/src/com/google/inject/InjectorImpl.java
@@ -309,15 +309,19 @@
       return value;
     }
 
+    public Key<String> getSourceKey() {
+      return originalBinding.getKey();
+    }
+
     public Set<Dependency<?>> getDependencies() {
-      return ImmutableSet.<Dependency<?>>of(Dependency.get(originalBinding.getKey()));
+      return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey()));
     }
 
     @Override public String toString() {
       return new ToStringBuilder(ConvertedConstantBinding.class)
           .add("key", getKey())
           .add("value", value)
-          .add("original", originalBinding)
+          .add("sourceKey", getSourceKey())
           .toString();
     }
   }
diff --git a/src/com/google/inject/spi/ConvertedConstantBinding.java b/src/com/google/inject/spi/ConvertedConstantBinding.java
index 6049f7d..6c78acb 100644
--- a/src/com/google/inject/spi/ConvertedConstantBinding.java
+++ b/src/com/google/inject/spi/ConvertedConstantBinding.java
@@ -17,6 +17,7 @@
 package com.google.inject.spi;
 
 import com.google.inject.Binding;
+import com.google.inject.Key;
 import java.util.Set;
 
 /**
@@ -34,6 +35,12 @@
   T getValue();
 
   /**
+   * Returns the key for the source binding. That binding can e retrieved from an injector using
+   * {@link com.google.inject.Injector#getBinding(Key) Injector.getBinding(key)}.
+   */
+  Key<String> getSourceKey();
+
+  /**
    * Returns a singleton set containing only the converted key.
    */
   Set<Dependency<?>> getDependencies();
diff --git a/src/com/google/inject/spi/InjectionPoint.java b/src/com/google/inject/spi/InjectionPoint.java
index 64ec59f..3cd7d8a 100644
--- a/src/com/google/inject/spi/InjectionPoint.java
+++ b/src/com/google/inject/spi/InjectionPoint.java
@@ -244,10 +244,11 @@
   }
 
   /**
-   * Returns all static method and field injection points on {@code type}. All fields are added
-   * first, and then all methods. Within the fields, supertype fields are added before subtype
-   * fields. Similarly, supertype methods are added before subtype methods.
+   * Returns all static method and field injection points on {@code type}.
    *
+   * @return a possibly empty set of injection points. The set has a specified iteration order. All
+   *      fields are returned and then all methods. Within the fields, supertype fields are returned
+   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
    *      a field with multiple binding annotations. The exception's {@link
    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
@@ -266,11 +267,13 @@
     }
     return result;
   }
+
   /**
-   * Returns all static method and field injection points on {@code type}. All fields are added
-   * first, and then all methods. Within the fields, supertype fields are added before subtype
-   * fields. Similarly, supertype methods are added before subtype methods.
+   * Returns all static method and field injection points on {@code type}.
    *
+   * @return a possibly empty set of injection points. The set has a specified iteration order. All
+   *      fields are returned and then all methods. Within the fields, supertype fields are returned
+   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
    *      a field with multiple binding annotations. The exception's {@link
    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
@@ -281,10 +284,11 @@
   }
 
   /**
-   * Returns all instance method and field injection points on {@code type}. All fields are added
-   * first, and then all methods. Within the fields, supertype fields are added before subtype
-   * fields. Similarly, supertype methods are added before subtype methods.
+   * Returns all instance method and field injection points on {@code type}.
    *
+   * @return a possibly empty set of injection points. The set has a specified iteration order. All
+   *      fields are returned and then all methods. Within the fields, supertype fields are returned
+   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
    *      a field with multiple binding annotations. The exception's {@link
    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
@@ -306,10 +310,11 @@
   }
 
   /**
-   * Returns all instance method and field injection points on {@code type}. All fields are added
-   * first, and then all methods. Within the fields, supertype fields are added before subtype
-   * fields. Similarly, supertype methods are added before subtype methods.
+   * Returns all instance method and field injection points on {@code type}.
    *
+   * @return a possibly empty set of injection points. The set has a specified iteration order. All
+   *      fields are returned and then all methods. Within the fields, supertype fields are returned
+   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
    * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
    *      a field with multiple binding annotations. The exception's {@link
    *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
diff --git a/src/com/google/inject/spi/InjectionRequest.java b/src/com/google/inject/spi/InjectionRequest.java
index 7fac33c..60349d5 100644
--- a/src/com/google/inject/spi/InjectionRequest.java
+++ b/src/com/google/inject/spi/InjectionRequest.java
@@ -17,6 +17,8 @@
 package com.google.inject.spi;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.inject.ConfigurationException;
+import java.util.Set;
 
 /**
  * A request to inject the instance fields and methods of an instance. Requests are created
@@ -45,6 +47,22 @@
     return instance;
   }
 
+  /**
+   * Returns the instance methods and fields of {@code instance} that will be injected to fulfill
+   * this request.
+   *
+   * @return a possibly empty set of injection points. The set has a specified iteration order. All
+   *      fields are returned and then all methods. Within the fields, supertype fields are returned
+   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
+   * @throws ConfigurationException if there is a malformed injection point on the class of {@code
+   *      instance}, such as a field with multiple binding annotations. The exception's {@link
+   *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
+   *      of the valid injection points.
+   */
+  public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException {
+    return InjectionPoint.forInstanceMethodsAndFields(instance.getClass());
+  }
+
   public <T> T acceptVisitor(ElementVisitor<T> visitor) {
     return visitor.visitInjectionRequest(this);
   }
diff --git a/src/com/google/inject/spi/StaticInjectionRequest.java b/src/com/google/inject/spi/StaticInjectionRequest.java
index d6b7c2b..a6fd446 100644
--- a/src/com/google/inject/spi/StaticInjectionRequest.java
+++ b/src/com/google/inject/spi/StaticInjectionRequest.java
@@ -16,11 +16,12 @@
 
 package com.google.inject.spi;
 
-
 import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.inject.ConfigurationException;
+import java.util.Set;
 
 /**
- * A request to inject the static fields and methods of type. Requests are created
+ * A request to inject the static fields and methods of a type. Requests are created
  * explicitly in a module using {@link com.google.inject.Binder#requestStaticInjection(Class[])
  * requestStaticInjection()} statements:
  * <pre>
@@ -46,6 +47,22 @@
     return type;
   }
 
+  /**
+   * Returns the static methods and fields of {@code type} that will be injected to fulfill this
+   * request.
+   *
+   * @return a possibly empty set of injection points. The set has a specified iteration order. All
+   *      fields are returned and then all methods. Within the fields, supertype fields are returned
+   *      before subtype fields. Similarly, supertype methods are returned before subtype methods.
+   * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
+   *      a field with multiple binding annotations. The exception's {@link
+   *      ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
+   *      of the valid injection points.
+   */
+  public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException {
+    return InjectionPoint.forStaticMethodsAndFields(type);
+  }
+
   public <T> T acceptVisitor(ElementVisitor<T> visitor) {
     return visitor.visitStaticInjectionRequest(this);
   }
diff --git a/test/com/google/inject/spi/SpiBindingsTest.java b/test/com/google/inject/spi/SpiBindingsTest.java
index 2c29cf4..aed6480 100644
--- a/test/com/google/inject/spi/SpiBindingsTest.java
+++ b/test/com/google/inject/spi/SpiBindingsTest.java
@@ -242,6 +242,7 @@
     binding.acceptTargetVisitor(new FailingTargetVisitor<Integer>() {
       @Override public Void visitConvertedConstant(ConvertedConstantBinding<Integer> binding) {
         assertEquals((Integer) 1, binding.getValue());
+        assertEquals(Key.get(String.class, Names.named("one")), binding.getSourceKey());
         return null;
       }
     });