Author: limpbizkit
Date: Sat Jun 20 10:30:23 2009
New Revision: 1022

Modified:
    trunk/src/com/google/inject/internal/BindingProcessor.java
    trunk/src/com/google/inject/internal/ConstructionContext.java
    trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
    trunk/src/com/google/inject/internal/ConstructorInjectorStore.java
    trunk/src/com/google/inject/internal/InjectorImpl.java
    trunk/src/com/google/inject/spi/InjectionPoint.java
    trunk/test/com/google/inject/BindingTest.java

Log:
toConstructor() core implementation. This still requires test coverage, and  
maybe a review of the API.

Modified: trunk/src/com/google/inject/internal/BindingProcessor.java
==============================================================================
--- trunk/src/com/google/inject/internal/BindingProcessor.java  (original)
+++ trunk/src/com/google/inject/internal/BindingProcessor.java  Sat Jun 20  
10:30:23 2009
@@ -85,6 +85,18 @@
          ((BindingImpl<?>) command).getScoping(), injector, errors);

      command.acceptTargetVisitor(new BindingTargetVisitor<T, Void>() {
+      public Void visit(ConstructorBinding<? extends T> binding) {
+        try {
+          ConstructorBindingImpl<T> onInjector =  
ConstructorBindingImpl.create(injector, key,
+              binding.getConstructor(), source, scoping, errors);
+          scheduleInitialization(onInjector);
+          putBinding(onInjector);
+        } catch (ErrorsException e) {
+          errors.merge(e.getErrors());
+          putBinding(invalidBinding(injector, key, source));
+        }
+        return null;
+      }

        public Void visit(InstanceBinding<? extends T> binding) {
          Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
@@ -148,26 +160,15 @@
          }

          // This cast is safe after the preceeding check.
-        final BindingImpl<T> binding;
          try {
-          binding = injector.createUnitializedBinding(key, scoping,  
source, errors);
+          BindingImpl<T> binding = injector.createUnitializedBinding(key,  
scoping, source, errors);
+          scheduleInitialization(binding);
            putBinding(binding);
          } catch (ErrorsException e) {
            errors.merge(e.getErrors());
            putBinding(invalidBinding(injector, key, source));
-          return null;
          }

-        uninitializedBindings.add(new Runnable() {
-          public void run() {
-            try {
-              binding.getInjector().initializeBinding(binding,  
errors.withSource(source));
-            } catch (ErrorsException e) {
-              errors.merge(e.getErrors());
-            }
-          }
-        });
-
          return null;
        }

@@ -179,12 +180,20 @@
          throw new IllegalArgumentException("Cannot apply a non-module  
element");
        }

-      public Void visit(ConstructorBinding<? extends T> binding) {
+      public Void visit(ProviderBinding<? extends T> binding) {
          throw new IllegalArgumentException("Cannot apply a non-module  
element");
        }

-      public Void visit(ProviderBinding<? extends T> binding) {
-        throw new IllegalArgumentException("Cannot apply a non-module  
element");
+      private void scheduleInitialization(final BindingImpl<?> binding) {
+        uninitializedBindings.add(new Runnable() {
+          public void run() {
+            try {
+              binding.getInjector().initializeBinding(binding,  
errors.withSource(source));
+            } catch (ErrorsException e) {
+              errors.merge(e.getErrors());
+            }
+          }
+        });
        }
      });


Modified: trunk/src/com/google/inject/internal/ConstructionContext.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructionContext.java       
(original)
+++ trunk/src/com/google/inject/internal/ConstructionContext.java       Sat Jun 
 
20 10:30:23 2009
@@ -73,8 +73,7 @@
        invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>();
      }

-    DelegatingInvocationHandler<T> invocationHandler
-        = new DelegatingInvocationHandler<T>();
+    DelegatingInvocationHandler<T> invocationHandler = new  
DelegatingInvocationHandler<T>();
      invocationHandlers.add(invocationHandler);

      ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType);

Modified: trunk/src/com/google/inject/internal/ConstructorBindingImpl.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructorBindingImpl.java     
(original)
+++ trunk/src/com/google/inject/internal/ConstructorBindingImpl.java    Sat  
Jun 20 10:30:23 2009
@@ -18,13 +18,17 @@

  import com.google.inject.Binder;
  import com.google.inject.Key;
+import com.google.inject.ConfigurationException;
  import static com.google.inject.internal.Preconditions.checkState;
+import static com.google.inject.internal.Annotations.findScopeAnnotation;
  import com.google.inject.spi.BindingTargetVisitor;
  import com.google.inject.spi.ConstructorBinding;
  import com.google.inject.spi.Dependency;
  import com.google.inject.spi.InjectionPoint;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.annotation.Annotation;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
@@ -32,34 +36,78 @@
  final class ConstructorBindingImpl<T> extends BindingImpl<T> implements  
ConstructorBinding<T> {

    private final Factory<T> factory;
+  private final InjectionPoint constructorInjectionPoint;

    private ConstructorBindingImpl(InjectorImpl injector, Key<T> key, Object  
source,
-      InternalFactory<? extends T> scopedFactory, Scoping scoping,  
Factory<T> factory) {
+      InternalFactory<? extends T> scopedFactory, Scoping scoping,  
Factory<T> factory,
+      InjectionPoint constructorInjectionPoint) {
      super(injector, key, source, scopedFactory, scoping);
      this.factory = factory;
+    this.constructorInjectionPoint = constructorInjectionPoint;
    }

    public ConstructorBindingImpl(Key<T> key, Object source, Scoping scoping,
-      InjectionPoint constructorInjector, Set<InjectionPoint>  
injectionPoints) {
+      InjectionPoint constructorInjectionPoint, Set<InjectionPoint>  
injectionPoints) {
      super(source, key, scoping);
      this.factory = new Factory<T>();
      ConstructionProxy<T> constructionProxy
-        = new  
DefaultConstructionProxyFactory<T>(constructorInjector).create();
+        = new  
DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
+    this.constructorInjectionPoint = constructorInjectionPoint;
      factory.constructorInjector = new ConstructorInjector<T>(
          injectionPoints, constructionProxy, null, null);
    }

-  static <T> ConstructorBindingImpl<T> create(
-      InjectorImpl injector, Key<T> key, Object source, Scoping scoping) {
+  /**
+   * @param constructorInjector the constructor to use, or {...@code null} to  
use the default.
+   */
+  static <T> ConstructorBindingImpl<T> create(InjectorImpl injector,  
Key<T> key,
+      InjectionPoint constructorInjector, Object source, Scoping scoping,  
Errors errors)
+      throws ErrorsException {
+    int numErrors = errors.size();
+    Class<? super T> rawType = key.getTypeLiteral().getRawType();
+
+    // We can't inject abstract classes.
+    if (Modifier.isAbstract(rawType.getModifiers())) {
+      errors.missingImplementation(key);
+    }
+
+    // Error: Inner class.
+    if (Classes.isInnerClass(rawType)) {
+      errors.cannotInjectInnerClass(rawType);
+    }
+
+    // if no scope is specified, look for a scoping annotation on the  
concrete class
+    if (!scoping.isExplicitlyScoped()) {
+      Class<? extends Annotation> scopeAnnotation =  
findScopeAnnotation(errors, rawType);
+      if (scopeAnnotation != null) {
+        scoping =  
Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
+            injector, errors.withSource(rawType));
+      }
+    }
+
+    errors.throwIfNewErrors(numErrors);
+
      Factory<T> factoryFactory = new Factory<T>();
      InternalFactory<? extends T> scopedFactory
          = Scoping.scope(key, injector, factoryFactory, scoping);
+
+    // Find a constructor annotated @Inject
+    if (constructorInjector == null) {
+      try {
+        constructorInjector =  
InjectionPoint.forConstructorOf(key.getTypeLiteral());
+      } catch (ConfigurationException e) {
+        throw errors.merge(e.getErrorMessages()).toException();
+      }
+    }
+
      return new ConstructorBindingImpl<T>(
-        injector, key, source, scopedFactory, scoping, factoryFactory);
+        injector, key, source, scopedFactory, scoping, factoryFactory,  
constructorInjector);
    }

+  @SuppressWarnings("unchecked") // the result type always agrees with the  
ConstructorInjector type
    public void initialize(InjectorImpl injector, Errors errors) throws  
ErrorsException {
-    factory.constructorInjector =  
injector.constructors.get(getKey().getTypeLiteral(), errors);
+    factory.constructorInjector
+        = (ConstructorInjector<T>)  
injector.constructors.get(constructorInjectionPoint, errors);
    }

    public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V>  
visitor) {
@@ -93,12 +141,12 @@

    @Override protected BindingImpl<T> withScoping(Scoping scoping) {
      return new ConstructorBindingImpl<T>(
-        null, getKey(), getSource(), factory, scoping, factory);
+        null, getKey(), getSource(), factory, scoping, factory,  
constructorInjectionPoint);
    }

    @Override protected BindingImpl<T> withKey(Key<T> key) {
      return new ConstructorBindingImpl<T>(
-        null, key, getSource(), factory, getScoping(), factory);
+        null, key, getSource(), factory, getScoping(), factory,  
constructorInjectionPoint);
    }

    public void applyTo(Binder binder) {

Modified: trunk/src/com/google/inject/internal/ConstructorInjectorStore.java
==============================================================================
--- trunk/src/com/google/inject/internal/ConstructorInjectorStore.java   
(original)
+++ trunk/src/com/google/inject/internal/ConstructorInjectorStore.java  Sat  
Jun 20 10:30:23 2009
@@ -16,8 +16,6 @@

  package com.google.inject.internal;

-import com.google.inject.ConfigurationException;
-import com.google.inject.TypeLiteral;
  import static com.google.inject.internal.Iterables.concat;
  import com.google.inject.spi.InjectionPoint;

@@ -29,12 +27,12 @@
  final class ConstructorInjectorStore {
    private final InjectorImpl injector;

-  private final FailableCache<TypeLiteral<?>, ConstructorInjector<?>>   
cache
-      = new FailableCache<TypeLiteral<?>, ConstructorInjector<?>> () {
+  private final FailableCache<InjectionPoint, ConstructorInjector<?>>   
cache
+      = new FailableCache<InjectionPoint, ConstructorInjector<?>> () {
      @SuppressWarnings("unchecked")
-    protected ConstructorInjector<?> create(TypeLiteral<?> type, Errors  
errors)
+    protected ConstructorInjector<?> create(InjectionPoint  
constructorInjector, Errors errors)
          throws ErrorsException {
-      return createConstructor(type, errors);
+      return createConstructor(constructorInjector, errors);
      }
    };

@@ -45,26 +43,21 @@
    /**
     * Returns a new complete constructor injector with injection listeners  
registered.
     */
-  @SuppressWarnings("unchecked") // the ConstructorInjector type always  
agrees with the passed type
-  public <T> ConstructorInjector<T> get(TypeLiteral<T> key, Errors errors)  
throws ErrorsException {
-    return (ConstructorInjector<T>) cache.get(key, errors);
+  public ConstructorInjector<?> get(InjectionPoint constructorInjector,  
Errors errors)
+      throws ErrorsException {
+    return cache.get(constructorInjector, errors);
    }

-  private <T> ConstructorInjector<T> createConstructor(TypeLiteral<T>  
type, Errors errors)
+  private <T> ConstructorInjector<T> createConstructor(InjectionPoint  
injectionPoint, Errors errors)
        throws ErrorsException {
      int numErrorsBefore = errors.size();

-    InjectionPoint injectionPoint;
-    try {
-      injectionPoint = InjectionPoint.forConstructorOf(type);
-    } catch (ConfigurationException e) {
-      errors.merge(e.getErrorMessages());
-      throw errors.toException();
-    }
-
      SingleParameterInjector<?>[] constructorParameterInjectors
          =  
injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
-    MembersInjectorImpl<T> membersInjector =  
injector.membersInjectorStore.get(type, errors);
+
+    @SuppressWarnings("unchecked") // the injector type agrees with the  
injection point type
+    MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>)  
injector.membersInjectorStore
+        .get(injectionPoint.getDeclaringType(), errors);

      /*if[AOP]*/
      ImmutableList<MethodAspect> injectorAspects =  
injector.state.getMethodAspects();

Modified: trunk/src/com/google/inject/internal/InjectorImpl.java
==============================================================================
--- trunk/src/com/google/inject/internal/InjectorImpl.java      (original)
+++ trunk/src/com/google/inject/internal/InjectorImpl.java      Sat Jun 20  
10:30:23 2009
@@ -28,7 +28,6 @@
  import com.google.inject.Provider;
  import com.google.inject.ProvisionException;
  import com.google.inject.TypeLiteral;
-import static com.google.inject.internal.Annotations.findScopeAnnotation;
  import com.google.inject.spi.BindingTargetVisitor;
  import com.google.inject.spi.ConvertedConstantBinding;
  import com.google.inject.spi.Dependency;
@@ -36,10 +35,8 @@
  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.GenericArrayType;
  import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
  import java.util.Collections;
@@ -412,27 +409,7 @@
        return createProvidedByBinding(key, scoping, providedBy, errors);
      }

-    // We can't inject abstract classes.
-    // TODO: Method interceptors could actually enable us to implement
-    // abstract types. Should we remove this restriction?
-    if (Modifier.isAbstract(rawType.getModifiers())) {
-      throw errors.missingImplementation(key).toException();
-    }
-
-    // Error: Inner class.
-    if (Classes.isInnerClass(rawType)) {
-      throw errors.cannotInjectInnerClass(rawType).toException();
-    }
-
-    if (!scoping.isExplicitlyScoped()) {
-      Class<? extends Annotation> scopeAnnotation =  
findScopeAnnotation(errors, rawType);
-      if (scopeAnnotation != null) {
-        scoping =  
Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
-            this, errors.withSource(rawType));
-      }
-    }
-
-    return ConstructorBindingImpl.create(this, key, source, scoping);
+    return ConstructorBindingImpl.create(this, key, null, source, scoping,  
errors);
    }

    /**

Modified: trunk/src/com/google/inject/spi/InjectionPoint.java
==============================================================================
--- trunk/src/com/google/inject/spi/InjectionPoint.java (original)
+++ trunk/src/com/google/inject/spi/InjectionPoint.java Sat Jun 20 10:30:23  
2009
@@ -54,25 +54,30 @@

    private final boolean optional;
    private final Member member;
+  private final TypeLiteral<?> declaringType;
    private final ImmutableList<Dependency<?>> dependencies;

-  InjectionPoint(TypeLiteral<?> type, Method method) {
+  InjectionPoint(TypeLiteral<?> declaringType, Method method) {
      this.member = method;
+    this.declaringType = declaringType;

      Inject inject = method.getAnnotation(Inject.class);
      this.optional = inject.optional();

-    this.dependencies = forMember(method, type,  
method.getParameterAnnotations());
+    this.dependencies = forMember(method, declaringType,  
method.getParameterAnnotations());
    }

-  InjectionPoint(TypeLiteral<?> type, Constructor<?> constructor) {
+  InjectionPoint(TypeLiteral<?> declaringType, Constructor<?> constructor)  
{
      this.member = constructor;
+    this.declaringType = declaringType;
      this.optional = false;
-    this.dependencies = forMember(constructor, type,  
constructor.getParameterAnnotations());
+    this.dependencies = forMember(
+        constructor, declaringType, constructor.getParameterAnnotations());
    }

-  InjectionPoint(TypeLiteral<?> type, Field field) {
+  InjectionPoint(TypeLiteral<?> declaringType, Field field) {
      this.member = field;
+    this.declaringType = declaringType;

      Inject inject = field.getAnnotation(Inject.class);
      this.optional = inject.optional();
@@ -82,7 +87,7 @@
      Errors errors = new Errors(field);
      Key<?> key = null;
      try {
-      key = Annotations.getKey(type.getFieldType(field), field,  
annotations, errors);
+      key = Annotations.getKey(declaringType.getFieldType(field), field,  
annotations, errors);
      } catch (ErrorsException e) {
        errors.merge(e.getErrors());
      }
@@ -148,6 +153,15 @@
      return optional;
    }

+  /**
+   * Returns the generic type that defines this injection point. If the  
member exists on a
+   * parameterized type, the result will include more type information  
than the member's {...@link
+   * Member#getDeclaringClass() raw declaring class}.
+   */
+  public TypeLiteral<?> getDeclaringType() {
+    return declaringType;
+  }
+
    @Override public boolean equals(Object o) {
      return o instanceof InjectionPoint
          && member.equals(((InjectionPoint) o).member);
@@ -162,14 +176,13 @@
    }

    /**
-   * Returns a new injection point for the specified constructor. If any  
parameter of
-   * {...@code constructor} includes a type variable (such as {...@code  
List<T>}), prefer the overload
-   * that includes a type literal.
+   * Returns a new injection point for the specified constructor. If the  
declaring type of {...@code
+   * constructor} is parameterized (such as {...@code List<T>}), prefer the  
overload that includes a
+   * type literal.
     *
     * @param constructor any single constructor present on {...@code type}.
     */
    public static <T> InjectionPoint forConstructor(Constructor<T>  
constructor) {
-    // TODO: verify that constructor is valid? (defined on a non-abstract  
class, etc.)
      return new  
InjectionPoint(TypeLiteral.get(constructor.getDeclaringClass()),  
constructor);
    }

@@ -187,7 +200,6 @@
            .throwConfigurationExceptionIfErrorsExist();
      }

-    // TODO: verify that constructor is valid? (defined on a non-abstract  
class, etc.)
      return new InjectionPoint(type, constructor);
    }


Modified: trunk/test/com/google/inject/BindingTest.java
==============================================================================
--- trunk/test/com/google/inject/BindingTest.java       (original)
+++ trunk/test/com/google/inject/BindingTest.java       Sat Jun 20 10:30:23 2009
@@ -21,6 +21,7 @@
  import java.util.Collection;
  import java.util.List;
  import java.util.concurrent.atomic.AtomicInteger;
+import java.lang.reflect.Constructor;
  import junit.framework.TestCase;

  /**
@@ -206,4 +207,30 @@
      @Inject TooManyConstructors(Injector i) {}
      @Inject TooManyConstructors() {}
    }
+
+  public void testToConstructorBindings() throws NoSuchMethodException {
+    final Constructor<C> constructor = C.class.getConstructor(Stage.class);
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bind(C.class).toConstructor(constructor);
+      }
+    });
+
+    assertEquals(Stage.DEVELOPMENT, injector.getInstance(C.class).stage);
+  }
+
+  public static class C {
+    private final Stage stage;
+
+    public C(Stage stage) {
+      this.stage = stage;
+    }
+
+    @Inject C() {
+      this.stage = null;
+    }
+  }
+
+
  }

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to