Author: limpbizkit
Date: Wed Apr  8 16:48:49 2009
New Revision: 927

Added:
    trunk/src/com/google/inject/TypeListenerBindingProcessor.java
       - copied, changed from r915,  
/trunk/src/com/google/inject/InjectableTypeListenerBindingProcessor.java
    trunk/src/com/google/inject/spi/TypeListenerBinding.java
       - copied, changed from r926,  
/trunk/src/com/google/inject/spi/InjectableTypeListenerBinding.java
    trunk/test/com/google/inject/TypeListenerTest.java
       - copied, changed from r926,  
/trunk/test/com/google/inject/InjectableTypeListenerTest.java
Removed:
    trunk/src/com/google/inject/InjectableTypeListenerBindingProcessor.java
    trunk/src/com/google/inject/spi/InjectableTypeListenerBinding.java
    trunk/test/com/google/inject/InjectableTypeListenerTest.java
Modified:
    trunk/guice.ipr
    trunk/src/com/google/inject/AbstractProcessor.java
    trunk/src/com/google/inject/EncounterImpl.java
    trunk/src/com/google/inject/InheritingState.java
    trunk/src/com/google/inject/InjectorShell.java
    trunk/src/com/google/inject/MembersInjectorImpl.java
    trunk/src/com/google/inject/MembersInjectorStore.java
    trunk/src/com/google/inject/ProxyFactory.java
    trunk/src/com/google/inject/State.java
    trunk/src/com/google/inject/internal/Errors.java
    trunk/src/com/google/inject/spi/DefaultElementVisitor.java
    trunk/src/com/google/inject/spi/ElementVisitor.java
    trunk/src/com/google/inject/spi/Elements.java
    trunk/src/com/google/inject/spi/InterceptorBinding.java
    trunk/src/com/google/inject/spi/ModuleWriter.java
    trunk/src/com/google/inject/spi/TypeEncounter.java
    trunk/src/com/google/inject/spi/TypeListener.java
    trunk/test/com/google/inject/AllTests.java
    trunk/test/com/google/inject/spi/ElementsTest.java

Log:
More listener changes:
  - we now support user-supplied MembersInjectors. These execute before  
InjectionListeners, enabling a two-phase injection
  - renamed InjectableTypeListenerBinding to TypeListenerBinding

Modified: trunk/guice.ipr
==============================================================================
--- trunk/guice.ipr     (original)
+++ trunk/guice.ipr     Wed Apr  8 16:48:49 2009
@@ -574,10 +574,10 @@
        <command  
command-class="de.frag.umlplugin.uml.command.AddClassCommand"  
psi-class="com.google.inject.spi.InjectableType" />
        <command  
command-class="de.frag.umlplugin.uml.command.AddClassCommand"  
psi-class="com.google.inject.spi.Element" />
        <command  
command-class="de.frag.umlplugin.uml.command.AddClassCommand"  
psi-class="com.google.inject.spi.BinderElement" />
-      <command  
command-class="de.frag.umlplugin.uml.command.AddClassCommand"  
psi-class="com.google.inject.spi.InjectableTypeListenerBinding" />
+      <command  
command-class="de.frag.umlplugin.uml.command.AddClassCommand"  
psi-class="com.google.inject.spi.TypeListenerBinding" />
        <command  
command-class="de.frag.umlplugin.uml.command.ConnectClassesCommand" />
        <command  
command-class="de.frag.umlplugin.uml.command.AddClassCommand"  
psi-class="com.google.inject.Binder" />
-      <command  
command-class="de.frag.umlplugin.uml.command.AddDependentClassesCommand"  
psi-class="com.google.inject.spi.InjectableTypeListenerBinding" />
+      <command  
command-class="de.frag.umlplugin.uml.command.AddDependentClassesCommand"  
psi-class="com.google.inject.spi.TypeListenerBinding" />
        <compartment-visibility />
      </diagram>
    </component>

Modified: trunk/src/com/google/inject/AbstractProcessor.java
==============================================================================
--- trunk/src/com/google/inject/AbstractProcessor.java  (original)
+++ trunk/src/com/google/inject/AbstractProcessor.java  Wed Apr  8 16:48:49  
2009
@@ -20,14 +20,14 @@
  import com.google.inject.spi.Element;
  import com.google.inject.spi.ElementVisitor;
  import com.google.inject.spi.InjectionRequest;
+import com.google.inject.spi.MembersInjectorLookup;
  import com.google.inject.spi.Message;
  import com.google.inject.spi.PrivateElements;
  import com.google.inject.spi.ProviderLookup;
  import com.google.inject.spi.ScopeBinding;
  import com.google.inject.spi.StaticInjectionRequest;
  import com.google.inject.spi.TypeConverterBinding;
-import com.google.inject.spi.MembersInjectorLookup;
-import com.google.inject.spi.InjectableTypeListenerBinding;
+import com.google.inject.spi.TypeListenerBinding;
  import java.util.Iterator;
  import java.util.List;

@@ -116,7 +116,7 @@
      return false;
    }

-  public Boolean visit(InjectableTypeListenerBinding binding) {
+  public Boolean visit(TypeListenerBinding binding) {
      return false;
    }
  }

Modified: trunk/src/com/google/inject/EncounterImpl.java
==============================================================================
--- trunk/src/com/google/inject/EncounterImpl.java      (original)
+++ trunk/src/com/google/inject/EncounterImpl.java      Wed Apr  8 16:48:49 2009
@@ -36,6 +36,7 @@

    private final Errors errors;
    private final Lookups lookups;
+  private List<MembersInjector<? super T>> membersInjectors; // lazy
    private List<InjectionListener<? super T>> injectionListeners; // lazy
    private List<MethodAspect> aspects; // lazy
    private boolean valid = true;
@@ -55,13 +56,28 @@
          : ImmutableList.copyOf(aspects);
    }

+  public ImmutableList<MembersInjector<? super T>> getMembersInjectors() {
+    return membersInjectors == null
+        ? ImmutableList.<MembersInjector<? super T>>of()
+        : ImmutableList.copyOf(membersInjectors);
+  }
+
    public ImmutableList<InjectionListener<? super T>>  
getInjectionListeners() {
      return injectionListeners == null
          ? ImmutableList.<InjectionListener<? super T>>of()
          : ImmutableList.copyOf(injectionListeners);
    }

-  @SuppressWarnings("unchecked") // an InjectionListener<? super T> is an  
InjectionListener<T>
+  public void register(MembersInjector<? super T> membersInjector) {
+    checkState(valid, "Encounters may not be used after hear() returns.");
+
+    if (membersInjectors == null) {
+      membersInjectors = Lists.newArrayList();
+    }
+
+    membersInjectors.add(membersInjector);
+  }
+
    public void register(InjectionListener<? super T> injectionListener) {
      checkState(valid, "Encounters may not be used after hear() returns.");


Modified: trunk/src/com/google/inject/InheritingState.java
==============================================================================
--- trunk/src/com/google/inject/InheritingState.java    (original)
+++ trunk/src/com/google/inject/InheritingState.java    Wed Apr  8 16:48:49  
2009
@@ -22,7 +22,7 @@
  import com.google.inject.internal.Maps;
  import com.google.inject.internal.MatcherAndConverter;
  import static com.google.inject.internal.Preconditions.checkNotNull;
-import com.google.inject.spi.InjectableTypeListenerBinding;
+import com.google.inject.spi.TypeListenerBinding;
  import java.lang.annotation.Annotation;
  import java.util.ArrayList;
  import java.util.Collections;
@@ -45,7 +45,7 @@
    /*if[AOP]*/
    private final List<MethodAspect> methodAspects = Lists.newArrayList();
    /*end[AOP]*/
-  private final List<InjectableTypeListenerBinding> listenerBindings =  
Lists.newArrayList();
+  private final List<TypeListenerBinding> listenerBindings =  
Lists.newArrayList();
    private final WeakKeySet blacklistedKeys = new WeakKeySet();
    private final Object lock;

@@ -118,14 +118,14 @@
    }
    /*end[AOP]*/

-  public void addInjectableTypeListener(InjectableTypeListenerBinding  
listenerBinding) {
+  public void addTypeListener(TypeListenerBinding listenerBinding) {
      listenerBindings.add(listenerBinding);
    }

-  public List<InjectableTypeListenerBinding>  
getInjectableTypeListenerBindings() {
-    List<InjectableTypeListenerBinding> parentBindings =  
parent.getInjectableTypeListenerBindings();
-    List<InjectableTypeListenerBinding> result
-        = new  
ArrayList<InjectableTypeListenerBinding>(parentBindings.size() + 1);
+  public List<TypeListenerBinding> getTypeListenerBindings() {
+    List<TypeListenerBinding> parentBindings =  
parent.getTypeListenerBindings();
+    List<TypeListenerBinding> result
+        = new ArrayList<TypeListenerBinding>(parentBindings.size() + 1);
      result.addAll(parentBindings);
      result.addAll(listenerBindings);
      return result;

Modified: trunk/src/com/google/inject/InjectorShell.java
==============================================================================
--- trunk/src/com/google/inject/InjectorShell.java      (original)
+++ trunk/src/com/google/inject/InjectorShell.java      Wed Apr  8 16:48:49 2009
@@ -33,9 +33,9 @@
  import com.google.inject.spi.Dependency;
  import com.google.inject.spi.Element;
  import com.google.inject.spi.Elements;
-import com.google.inject.spi.InjectableTypeListenerBinding;
  import com.google.inject.spi.InjectionPoint;
  import com.google.inject.spi.PrivateElements;
+import com.google.inject.spi.TypeListenerBinding;
  import java.util.List;
  import java.util.logging.Logger;

@@ -147,9 +147,8 @@
        injector.constructionProxyFactory = new  
DefaultConstructionProxyFactory();
        end[NO_AOP]*/

-      new InjectableTypeListenerBindingProcessor(errors).process(injector,  
elements);
-      List<InjectableTypeListenerBinding> listenerBindings
-          = injector.state.getInjectableTypeListenerBindings();
+      new TypeListenerBindingProcessor(errors).process(injector, elements);
+      List<TypeListenerBinding> listenerBindings =  
injector.state.getTypeListenerBindings();
        injector.membersInjectorStore = new MembersInjectorStore(injector,  
listenerBindings);
        stopwatch.resetAndLog("TypeListeners creation");


Modified: trunk/src/com/google/inject/MembersInjectorImpl.java
==============================================================================
--- trunk/src/com/google/inject/MembersInjectorImpl.java        (original)
+++ trunk/src/com/google/inject/MembersInjectorImpl.java        Wed Apr  8  
16:48:49 2009
@@ -33,16 +33,19 @@
    private final TypeLiteral<T> typeLiteral;
    private final InjectorImpl injector;
    private final ImmutableList<SingleMemberInjector> memberInjectors;
+  private final ImmutableList<MembersInjector<? super T>>  
userMembersInjectors;
    private final ImmutableList<InjectionListener<? super T>>  
injectionListeners;
    private final ImmutableList<MethodAspect> addedAspects;

    MembersInjectorImpl(InjectorImpl injector, TypeLiteral<T> typeLiteral,
        ImmutableList<SingleMemberInjector> memberInjectors,
+      ImmutableList<MembersInjector<? super T>> userMembersInjectors,
        ImmutableList<InjectionListener<? super T>> injectionListeners,
        ImmutableList<MethodAspect> addedAspects) {
      this.injector = injector;
      this.typeLiteral = typeLiteral;
      this.memberInjectors = memberInjectors;
+    this.userMembersInjectors = userMembersInjectors;
      this.injectionListeners = injectionListeners;
      this.addedAspects = addedAspects;
    }
@@ -92,6 +95,14 @@
    void injectMembers(T t, Errors errors, InternalContext context) {
      for (SingleMemberInjector injector : memberInjectors) {
        injector.inject(errors, context, t);
+    }
+
+    for (MembersInjector<? super T> userMembersInjector :  
userMembersInjectors) {
+      try {
+        userMembersInjector.injectMembers(t);
+      } catch (RuntimeException e) {
+        errors.errorInUserInjector(userMembersInjector, typeLiteral, e);
+      }
      }
    }


Modified: trunk/src/com/google/inject/MembersInjectorStore.java
==============================================================================
--- trunk/src/com/google/inject/MembersInjectorStore.java       (original)
+++ trunk/src/com/google/inject/MembersInjectorStore.java       Wed Apr  8  
16:48:49 2009
@@ -21,8 +21,8 @@
  import com.google.inject.internal.FailableCache;
  import com.google.inject.internal.ImmutableList;
  import com.google.inject.internal.Lists;
-import com.google.inject.spi.InjectableTypeListenerBinding;
  import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.TypeListenerBinding;
  import java.lang.reflect.Field;
  import java.util.List;
  import java.util.Set;
@@ -34,7 +34,7 @@
   */
  class MembersInjectorStore {
    private final InjectorImpl injector;
-  private final ImmutableList<InjectableTypeListenerBinding>  
injectableTypeListenerBindings;
+  private final ImmutableList<TypeListenerBinding> typeListenerBindings;

    private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache
        = new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
@@ -45,9 +45,9 @@
    };

    MembersInjectorStore(InjectorImpl injector,
-      List<InjectableTypeListenerBinding> injectableTypeListenerBindings) {
+      List<TypeListenerBinding> typeListenerBindings) {
      this.injector = injector;
-    this.injectableTypeListenerBindings =  
ImmutableList.copyOf(injectableTypeListenerBindings);
+    this.typeListenerBindings = ImmutableList.copyOf(typeListenerBindings);
    }

    /**
@@ -55,7 +55,7 @@
     * aren't any type listeners.
     */
    public boolean hasTypeListeners() {
-    return !injectableTypeListenerBindings.isEmpty();
+    return !typeListenerBindings.isEmpty();
    }

    /**
@@ -84,7 +84,7 @@
      errors.throwIfNewErrors(numErrorsBefore);

      EncounterImpl<T> encounter = new EncounterImpl<T>(errors,  
injector.lookups);
-    for (InjectableTypeListenerBinding typeListener :  
injectableTypeListenerBindings) {
+    for (TypeListenerBinding typeListener : typeListenerBindings) {
        if (typeListener.getTypeMatcher().matches(type)) {
          try {
            typeListener.getListener().hear(type, encounter);
@@ -96,8 +96,8 @@
      encounter.invalidate();
      errors.throwIfNewErrors(numErrorsBefore);

-    return new MembersInjectorImpl<T>(injector, type, injectors,  
encounter.getInjectionListeners(),
-        encounter.getAspects());
+    return new MembersInjectorImpl<T>(injector, type, injectors,  
encounter.getMembersInjectors(),
+        encounter.getInjectionListeners(), encounter.getAspects());
    }

    /**

Modified: trunk/src/com/google/inject/ProxyFactory.java
==============================================================================
--- trunk/src/com/google/inject/ProxyFactory.java       (original)
+++ trunk/src/com/google/inject/ProxyFactory.java       Wed Apr  8 16:48:49 2009
@@ -141,8 +141,7 @@
    }

    /**
-   * Returns the interceptors that apply to the constructed type. When  
InjectableType.Listeners
-   * add additional interceptors, this builder will be thrown out and  
another created.n
+   * Returns the interceptors that apply to the constructed type.
     */
    public ImmutableMap<Method, List<MethodInterceptor>> getInterceptors() {
      return interceptors;

Modified: trunk/src/com/google/inject/State.java
==============================================================================
--- trunk/src/com/google/inject/State.java      (original)
+++ trunk/src/com/google/inject/State.java      Wed Apr  8 16:48:49 2009
@@ -21,7 +21,7 @@
  import com.google.inject.internal.ImmutableList;
  import com.google.inject.internal.ImmutableSet;
  import com.google.inject.internal.MatcherAndConverter;
-import com.google.inject.spi.InjectableTypeListenerBinding;
+import com.google.inject.spi.TypeListenerBinding;
  import java.lang.annotation.Annotation;
  import java.util.List;
  import java.util.Map;
@@ -82,12 +82,11 @@
      }
      /*end[AOP]*/

-    public void addInjectableTypeListener(
-        InjectableTypeListenerBinding injectableTypeListenerBinding) {
+    public void addTypeListener(TypeListenerBinding typeListenerBinding) {
        throw new UnsupportedOperationException();
      }

-    public List<InjectableTypeListenerBinding>  
getInjectableTypeListenerBindings() {
+    public List<TypeListenerBinding> getTypeListenerBindings() {
        return ImmutableList.of();
      }

@@ -133,9 +132,9 @@
    List<MethodAspect> getMethodAspects();
    /*end[AOP]*/

-  void addInjectableTypeListener(InjectableTypeListenerBinding  
injectableTypeListenerBinding);
+  void addTypeListener(TypeListenerBinding typeListenerBinding);

-  List<InjectableTypeListenerBinding> getInjectableTypeListenerBindings();
+  List<TypeListenerBinding> getTypeListenerBindings();

    /**
     * Forbids the corresponding injector from creating a binding to {...@code  
key}. Child injectors

Copied: trunk/src/com/google/inject/TypeListenerBindingProcessor.java (from  
r915,  
/trunk/src/com/google/inject/InjectableTypeListenerBindingProcessor.java)
==============================================================================
---  
/trunk/src/com/google/inject/InjectableTypeListenerBindingProcessor.java        
 
(original)
+++ trunk/src/com/google/inject/TypeListenerBindingProcessor.java       Wed Apr 
  
8 16:48:49 2009
@@ -17,21 +17,21 @@
  package com.google.inject;

  import com.google.inject.internal.Errors;
-import com.google.inject.spi.InjectableTypeListenerBinding;
+import com.google.inject.spi.TypeListenerBinding;

  /**
   * Handles {...@link Binder#bindListener} commands.
   *
   * @author [email protected] (Jesse Wilson)
   */
-class InjectableTypeListenerBindingProcessor extends AbstractProcessor {
+class TypeListenerBindingProcessor extends AbstractProcessor {

-  InjectableTypeListenerBindingProcessor(Errors errors) {
+  TypeListenerBindingProcessor(Errors errors) {
      super(errors);
    }

-  @Override public Boolean visit(InjectableTypeListenerBinding binding) {
-    injector.state.addInjectableTypeListener(binding);
+  @Override public Boolean visit(TypeListenerBinding binding) {
+    injector.state.addTypeListener(binding);
      return true;
    }
  }

Modified: trunk/src/com/google/inject/internal/Errors.java
==============================================================================
--- trunk/src/com/google/inject/internal/Errors.java    (original)
+++ trunk/src/com/google/inject/internal/Errors.java    Wed Apr  8 16:48:49  
2009
@@ -19,15 +19,16 @@
  import com.google.inject.ConfigurationException;
  import com.google.inject.CreationException;
  import com.google.inject.Key;
+import com.google.inject.MembersInjector;
  import com.google.inject.Provider;
  import com.google.inject.ProvisionException;
  import com.google.inject.Scope;
  import com.google.inject.TypeLiteral;
  import com.google.inject.spi.Dependency;
-import com.google.inject.spi.InjectableTypeListenerBinding;
  import com.google.inject.spi.InjectionListener;
  import com.google.inject.spi.InjectionPoint;
  import com.google.inject.spi.Message;
+import com.google.inject.spi.TypeListenerBinding;
  import java.io.PrintWriter;
  import java.io.Serializable;
  import java.io.StringWriter;
@@ -253,7 +254,7 @@
      return errorInUserCode(cause, "Error injecting method, %s", cause);
    }

-  public Errors errorNotifyingTypeListener(InjectableTypeListenerBinding  
listener,
+  public Errors errorNotifyingTypeListener(TypeListenerBinding listener,
        TypeLiteral<?> type, Throwable cause) {
      return errorInUserCode(cause,
          "Error notifying TypeListener %s (bound at %s) of %s.%n"
@@ -269,10 +270,16 @@
      return errorInUserCode(runtimeException, "Error in custom  
provider, %s", runtimeException);
    }

+  public Errors errorInUserInjector(
+      MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException  
cause) {
+    return errorInUserCode(cause, "Error injecting %s using %s.%n"
+        + " Reason: %s", type, listener, cause);
+  }
+
    public Errors errorNotifyingInjectionListener(
-      InjectionListener listener, TypeLiteral<?> typeLiteral,  
RuntimeException cause) {
+      InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException  
cause) {
      return errorInUserCode(cause, "Error notifying InjectionListener %s  
of %s.%n"
-        + " Reason: %s", listener, typeLiteral, cause);
+        + " Reason: %s", listener, type, cause);
    }

    public void exposedButNotBound(Key<?> key) {

Modified: trunk/src/com/google/inject/spi/DefaultElementVisitor.java
==============================================================================
--- trunk/src/com/google/inject/spi/DefaultElementVisitor.java  (original)
+++ trunk/src/com/google/inject/spi/DefaultElementVisitor.java  Wed Apr  8  
16:48:49 2009
@@ -79,7 +79,7 @@
      return visitOther(lookup);
    }

-  public V visit(InjectableTypeListenerBinding binding) {
+  public V visit(TypeListenerBinding binding) {
      return visitOther(binding);
    }
  }

Modified: trunk/src/com/google/inject/spi/ElementVisitor.java
==============================================================================
--- trunk/src/com/google/inject/spi/ElementVisitor.java (original)
+++ trunk/src/com/google/inject/spi/ElementVisitor.java Wed Apr  8 16:48:49  
2009
@@ -85,5 +85,5 @@
    /**
     * Visit an injectable type listener binding.
     */
-  V visit(InjectableTypeListenerBinding binding);
+  V visit(TypeListenerBinding binding);
  }

Modified: trunk/src/com/google/inject/spi/Elements.java
==============================================================================
--- trunk/src/com/google/inject/spi/Elements.java       (original)
+++ trunk/src/com/google/inject/spi/Elements.java       Wed Apr  8 16:48:49 2009
@@ -189,7 +189,7 @@
      }

      public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,  
TypeListener listener) {
-      elements.add(new InjectableTypeListenerBinding(getSource(),  
listener, typeMatcher));
+      elements.add(new TypeListenerBinding(getSource(), listener,  
typeMatcher));
      }

      public void requestStaticInjection(Class<?>... types) {

Modified: trunk/src/com/google/inject/spi/InterceptorBinding.java
==============================================================================
--- trunk/src/com/google/inject/spi/InterceptorBinding.java     (original)
+++ trunk/src/com/google/inject/spi/InterceptorBinding.java     Wed Apr  8  
16:48:49 2009
@@ -34,7 +34,7 @@
   *         new MyTransactionInterceptor());</pre>
   *
   * or from an injectable type listener using {...@link  
TypeEncounter#bindInterceptor(Matcher,
- * org.aopalliance.intercept.MethodInterceptor[])  
InjectableType.Encounter.bindInterceptor()}.
+ * org.aopalliance.intercept.MethodInterceptor[])  
TypeEncounter.bindInterceptor()}.
   *
   * @author [email protected] (Jesse Wilson)
   * @since 2.0

Modified: trunk/src/com/google/inject/spi/ModuleWriter.java
==============================================================================
--- trunk/src/com/google/inject/spi/ModuleWriter.java   (original)
+++ trunk/src/com/google/inject/spi/ModuleWriter.java   Wed Apr  8 16:48:49  
2009
@@ -109,7 +109,7 @@
          return null;
        }

-      public Void visit(InjectableTypeListenerBinding element) {
+      public Void visit(TypeListenerBinding element) {
          writeBindListener(binder, element);
          return null;
        }
@@ -138,7 +138,7 @@
    }
    /*end[AOP]*/

-  protected void writeBindListener(Binder binder,  
InjectableTypeListenerBinding element) {
+  protected void writeBindListener(Binder binder, TypeListenerBinding  
element) {
      binder.withSource(element.getSource())
          .bindListener(element.getTypeMatcher(), element.getListener());
    }

Modified: trunk/src/com/google/inject/spi/TypeEncounter.java
==============================================================================
--- trunk/src/com/google/inject/spi/TypeEncounter.java  (original)
+++ trunk/src/com/google/inject/spi/TypeEncounter.java  Wed Apr  8 16:48:49  
2009
@@ -43,9 +43,8 @@

    /**
     * Records an exception for type {...@code I}, the full details of which  
will be logged, and the
-   * message of which will be presented to the user at a later time. If  
your
-   * InjectableTypeListener calls something that you worry may fail, you  
should catch the
-   * exception and pass it to this method.
+   * message of which will be presented to the user at a later time. If  
your type listener calls
+   * something that you worry may fail, you should catch the exception and  
pass it to this method.
     */
    void addError(Throwable t);

@@ -89,11 +88,14 @@
    <T> MembersInjector<T> getMembersInjector(Class<T> type);

    /**
-   * Registers an injection listener for type {...@code I}. Guice will notify  
the listener after
-   * injecting an instance of {...@code I}. The order in which Guice will  
invoke listeners is
-   * unspecified.
-   *
-   * @param listener for injections into instances of type {...@code I}
+   * Registers a members injector for type {...@code I}. Guice will use the  
members injector after its
+   * performed its own injections on an instance of {...@code I}.
+   */
+  void register(MembersInjector<? super I> membersInjector);
+
+  /**
+   * Registers an injection listener for type {...@code I}. Guice will notify  
the listener after all
+   * injections have been performed on an instance of {...@code I}.
     */
    void register(InjectionListener<? super I> listener);


Modified: trunk/src/com/google/inject/spi/TypeListener.java
==============================================================================
--- trunk/src/com/google/inject/spi/TypeListener.java   (original)
+++ trunk/src/com/google/inject/spi/TypeListener.java   Wed Apr  8 16:48:49  
2009
@@ -37,7 +37,7 @@
     *
     * @param type encountered by Guice
     * @param encounter context of this encounter, enables reporting errors,  
registering injection
-   *     listeners and binding method interceptors for injectableType
+   *     listeners and binding method interceptors for {...@code type}.
     *
     * @param <I> the injectable type
     */

Copied: trunk/src/com/google/inject/spi/TypeListenerBinding.java (from  
r926, /trunk/src/com/google/inject/spi/InjectableTypeListenerBinding.java)
==============================================================================
--- /trunk/src/com/google/inject/spi/InjectableTypeListenerBinding.java  
(original)
+++ trunk/src/com/google/inject/spi/TypeListenerBinding.java    Wed Apr  8  
16:48:49 2009
@@ -21,23 +21,21 @@
  import com.google.inject.matcher.Matcher;

  /**
- * Binds injectable types (picked using a Matcher) to an injectable type  
listener.
- * Registrations are created explicitly in a module using {...@link
- *  
com.google.inject.Binder#bindListener(com.google.inject.matcher.Matcher,  
TypeListener)}
- * statements:
+ * Binds types (picked using a Matcher) to an type listener. Registrations  
are created explicitly in
+ * a module using {...@link com.google.inject.Binder#bindListener(Matcher,  
TypeListener)} statements:
   *
   * <pre>
   *     register(only(new TypeLiteral&lt;PaymentService&lt;CreditCard>>()  
{}), listener);</pre>
   *
   * @author [email protected] (Jesse Wilson)
   */
-public final class InjectableTypeListenerBinding implements Element {
+public final class TypeListenerBinding implements Element {

-  final Object source;
-  final Matcher<? super TypeLiteral<?>> typeMatcher;
-  final TypeListener listener;
+  private final Object source;
+  private final Matcher<? super TypeLiteral<?>> typeMatcher;
+  private final TypeListener listener;

-  InjectableTypeListenerBinding(Object source, TypeListener listener,
+  TypeListenerBinding(Object source, TypeListener listener,
        Matcher<? super TypeLiteral<?>> typeMatcher) {
      this.source = source;
      this.listener = listener;

Modified: trunk/test/com/google/inject/AllTests.java
==============================================================================
--- trunk/test/com/google/inject/AllTests.java  (original)
+++ trunk/test/com/google/inject/AllTests.java  Wed Apr  8 16:48:49 2009
@@ -56,7 +56,7 @@
      suite.addTestSuite(EagerSingletonTest.class);
      suite.addTestSuite(GenericInjectionTest.class);
      suite.addTestSuite(ImplicitBindingTest.class);
-    suite.addTestSuite(InjectableTypeListenerTest.class);
+    suite.addTestSuite(TypeListenerTest.class);
      suite.addTestSuite(InjectorTest.class);
      // IntegrationTest is AOP-only
      suite.addTestSuite(KeyTest.class);

Copied: trunk/test/com/google/inject/TypeListenerTest.java (from r926,  
/trunk/test/com/google/inject/InjectableTypeListenerTest.java)
==============================================================================
--- /trunk/test/com/google/inject/InjectableTypeListenerTest.java       
(original)
+++ trunk/test/com/google/inject/TypeListenerTest.java  Wed Apr  8 16:48:49  
2009
@@ -23,6 +23,7 @@
  import com.google.inject.matcher.Matchers;
  import static com.google.inject.matcher.Matchers.any;
  import static com.google.inject.matcher.Matchers.only;
+import static com.google.inject.name.Names.named;
  import com.google.inject.spi.InjectionListener;
  import com.google.inject.spi.TypeEncounter;
  import com.google.inject.spi.TypeListener;
@@ -36,11 +37,12 @@
  /**
   * @author [email protected] (Jesse Wilson)
   */
-public class InjectableTypeListenerTest extends TestCase {
+public class TypeListenerTest extends TestCase {

-  private final Matcher<Object> onlyAbc = Matchers.only(new  
TypeLiteral<A>() {})
+  private final Matcher<Object> onlyAbcd = Matchers.only(new  
TypeLiteral<A>() {})
        .or(only(new TypeLiteral<B>() {}))
-      .or(only(new TypeLiteral<C>() {}));
+      .or(only(new TypeLiteral<C>() {}))
+      .or(only(new TypeLiteral<D>() {}));

    private static MethodInterceptor prefixInterceptor(final String prefix) {
      return new MethodInterceptor() {
@@ -50,7 +52,7 @@
      };
    }

-  final TypeListener failingInjectableTypeListener = new TypeListener() {
+  final TypeListener failingTypeListener = new TypeListener() {
      int failures = 0;

      public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
@@ -74,6 +76,18 @@
      }
    };

+  final MembersInjector<Object> failingMembersInjector = new  
MembersInjector<Object>() {
+    int failures = 0;
+
+    public void injectMembers(Object instance) {
+      throw new ClassCastException("whoops, failure #" + (++failures));
+    }
+
+    @Override public String toString() {
+      return "awkward";
+    }
+  };
+
    public void testTypeListenersAreFired() throws NoSuchMethodException {
      final AtomicInteger firedCount = new AtomicInteger();

@@ -86,7 +100,7 @@

      Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bindListener(onlyAbc, typeListener);
+        bindListener(onlyAbcd, typeListener);
          bind(A.class);
        }
      });
@@ -104,7 +118,7 @@

      Injector injector = Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bindListener(onlyAbc, new TypeListener() {
+        bindListener(onlyAbcd, new TypeListener() {
            public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
              encounter.register(injectionListener);
            }
@@ -139,7 +153,7 @@
          bindInterceptor(any(), buzz, prefixInterceptor("ka"));
          bindInterceptor(any(), any(), prefixInterceptor("fe"));

-        bindListener(onlyAbc, new TypeListener() {
+        bindListener(onlyAbcd, new TypeListener() {
            public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
              encounter.bindInterceptor(any(), prefixInterceptor("li"));
              encounter.bindInterceptor(buzz, prefixInterceptor("no"));
@@ -154,11 +168,11 @@
      assertEquals("felibeep", c.beep());
    }

-  public void testInjectableTypeListenerThrows() {
+  public void testTypeListenerThrows() {
      try {
        Guice.createInjector(new AbstractModule() {
          protected void configure() {
-          bindListener(onlyAbc, failingInjectableTypeListener);
+          bindListener(onlyAbcd, failingTypeListener);
            bind(B.class);
            bind(C.class);
          }
@@ -167,18 +181,18 @@
      } catch (CreationException expected) {
        assertContains(expected.getMessage(),
            "1) Error notifying TypeListener clumsy (bound at " +  
getClass().getName(),
-          ".configure(InjectableTypeListenerTest.java:",
+          ".configure(TypeListenerTest.java:",
            "of " + B.class.getName(),
            "Reason: java.lang.ClassCastException: whoops, failure #1",
            "2) Error notifying TypeListener clumsy (bound at " +  
getClass().getName(),
-          ".configure(InjectableTypeListenerTest.java:",
+          ".configure(TypeListenerTest.java:",
            "of " + C.class.getName(),
            "Reason: java.lang.ClassCastException: whoops, failure #2");
      }

      Injector injector = Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bindListener(onlyAbc, failingInjectableTypeListener);
+        bindListener(onlyAbcd, failingTypeListener);
        }
      });
      try {
@@ -187,7 +201,7 @@
      } catch (ConfigurationException expected) {
        assertContains(expected.getMessage(),
            "1) Error notifying TypeListener clumsy (bound at " +  
getClass().getName(),
-          ".configure(InjectableTypeListenerTest.java:",
+          ".configure(TypeListenerTest.java:",
            "of " + B.class.getName(),
            "Reason: java.lang.ClassCastException: whoops, failure #3");
      }
@@ -199,19 +213,19 @@
      } catch (ConfigurationException expected) {
        assertContains(expected.getMessage(),
            "1) Error notifying TypeListener clumsy (bound at " +  
getClass().getName(),
-          ".configure(InjectableTypeListenerTest.java:",
+          ".configure(TypeListenerTest.java:",
            "of " + B.class.getName(),
            "Reason: java.lang.ClassCastException: whoops, failure #3");
      }

-    // non-constructed types do not participate
+    // non-injected types do not participate
      assertSame(Stage.DEVELOPMENT, injector.getInstance(Stage.class));
    }

    public void testInjectionListenerThrows() {
      Injector injector = Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bindListener(onlyAbc, new TypeListener() {
+        bindListener(onlyAbcd, new TypeListener() {
            public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
              encounter.register(failingInjectionListener);
            }
@@ -250,23 +264,23 @@
            " Reason: java.lang.ClassCastException: whoops, failure #3");
      }

-    // non-constructed types do not participate
+    // non-injected types do not participate
      assertSame(Stage.DEVELOPMENT, injector.getInstance(Stage.class));
    }

-  public void testInjectMembersInjectableTypeListenerFails() {
+  public void testInjectMembersTypeListenerFails() {
      try {
        Guice.createInjector(new AbstractModule() {
          protected void configure() {
            getMembersInjector(A.class);
-          bindListener(onlyAbc, failingInjectableTypeListener);
+          bindListener(onlyAbcd, failingTypeListener);
          }
        });
        fail();
      } catch (CreationException expected) {
        assertContains(expected.getMessage(),
            "1) Error notifying TypeListener clumsy (bound at ",
-           
InjectableTypeListenerTest.class.getName(), 
".configure(InjectableTypeListenerTest.java:",
+           
TypeListenerTest.class.getName(), ".configure(TypeListenerTest.java:",
            "of " + A.class.getName(),
            " Reason: java.lang.ClassCastException: whoops, failure #1");
      }
@@ -285,7 +299,7 @@

      Injector injector = Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bindListener(onlyAbc, new TypeListener() {
+        bindListener(onlyAbcd, new TypeListener() {
            public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
              typeEncounters.incrementAndGet();
              encounter.register((InjectionListener) listener);
@@ -397,6 +411,102 @@
      injector.getInstance(C.class);
    }

+  public void testMembersInjector() {
+    final MembersInjector<D> membersInjector = new MembersInjector<D>() {
+      public void injectMembers(D instance) {
+        instance.userInjected++;
+        assertEquals(instance.guiceInjected, instance.userInjected);
+      }
+    };
+
+    final InjectionListener<D> injectionListener = new  
InjectionListener<D>() {
+      public void afterInjection(D injectee) {
+        assertTrue(injectee.userInjected > 0);
+        injectee.listenersNotified++;
+        assertEquals(injectee.guiceInjected, injectee.listenersNotified);
+      }
+    };
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bindListener(onlyAbcd, new TypeListener() {
+          public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
+            encounter.register((MembersInjector) membersInjector);
+            encounter.register((InjectionListener) injectionListener);
+          }
+        });
+
+        D boundThreeTimes = new D();
+         
bind(D.class).annotatedWith(named("i")).toInstance(boundThreeTimes);
+         
bind(D.class).annotatedWith(named("ii")).toInstance(boundThreeTimes);
+         
bind(D.class).annotatedWith(named("iii")).toInstance(boundThreeTimes);
+      }
+    });
+
+    D boundThreeTimes = injector.getInstance(Key.get(D.class,  
named("iii")));
+    boundThreeTimes.assertAllCounts(1);
+
+    D getInstance = injector.getInstance(D.class);
+    getInstance.assertAllCounts(1);
+
+    D memberInjection = new D();
+    injector.injectMembers(memberInjection);
+    memberInjection.assertAllCounts(1);
+
+    injector.injectMembers(memberInjection);
+    injector.injectMembers(memberInjection);
+    memberInjection.assertAllCounts(3);
+
+    injector.getMembersInjector(D.class).injectMembers(memberInjection);
+    memberInjection.assertAllCounts(4);
+  }
+
+  public void testMembersInjectorThrows() {
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bindListener(onlyAbcd, new TypeListener() {
+          public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
+            encounter.register(failingMembersInjector);
+          }
+        });
+        bind(B.class);
+      }
+    });
+
+    try {
+      injector.getInstance(A.class);
+      fail();
+    } catch (ProvisionException e) {
+      assertContains(e.getMessage(),
+          "1) Error injecting " + A.class.getName() + " using awkward.",
+          "Reason: java.lang.ClassCastException: whoops, failure #1");
+    }
+
+    // second time through should be a new cause (#2)
+    try {
+      injector.getInstance(A.class);
+      fail();
+    } catch (ProvisionException e) {
+      assertContains(e.getMessage(),
+          "1) Error injecting " + A.class.getName() + " using awkward.",
+          "Reason: java.lang.ClassCastException: whoops, failure #2");
+    }
+
+    // we should get errors for all types, but only on getInstance()
+    Provider<B> bProvider = injector.getProvider(B.class);
+    try {
+      bProvider.get();
+      fail();
+    } catch (ProvisionException e) {
+      assertContains(e.getMessage(),
+          "1) Error injecting " + B.class.getName() + " using awkward.",
+          "Reason: java.lang.ClassCastException: whoops, failure #3");
+    }
+
+    // non-injected types do not participate
+    assertSame(Stage.DEVELOPMENT, injector.getInstance(Stage.class));
+  }
+
    /**
     * We had a bug where we weren't notifying of types encountered for  
member injection when those
     * types had no members to be injected. Constructed types are always  
injected because they always
@@ -407,7 +517,7 @@

      Guice.createInjector(new AbstractModule() {
        protected void configure() {
-        bindListener(onlyAbc, new TypeListener() {
+        bindListener(onlyAbcd, new TypeListener() {
            public <I> void hear(TypeLiteral<I> type, TypeEncounter<I>  
encounter) {
              notificationCount.incrementAndGet();
            }
@@ -489,6 +599,22 @@

      public String beep() {
        return "beep";
+    }
+  }
+
+  static class D {
+    int guiceInjected = 0;
+    int userInjected = 0;
+    int listenersNotified = 0;
+
+    @Inject void guiceInjected() {
+      guiceInjected++;
+    }
+
+    void assertAllCounts(int expected) {
+      assertEquals(expected, guiceInjected);
+      assertEquals(expected, userInjected);
+      assertEquals(expected, listenersNotified);
      }
    }
  }

Modified: trunk/test/com/google/inject/spi/ElementsTest.java
==============================================================================
--- trunk/test/com/google/inject/spi/ElementsTest.java  (original)
+++ trunk/test/com/google/inject/spi/ElementsTest.java  Wed Apr  8 16:48:49  
2009
@@ -606,7 +606,7 @@
          },

          new FailingElementVisitor() {
-          @Override public Void visit(InjectableTypeListenerBinding  
binding) {
+          @Override public Void visit(TypeListenerBinding binding) {
              assertSame(typeMatcher, binding.getTypeMatcher());
              assertSame(listener, binding.getListener());
              return 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