Author: limpbizkit
Date: Thu Mar 26 15:01:18 2009
New Revision: 910

Modified:
    trunk/src/com/google/inject/ConstructorInjector.java
    trunk/src/com/google/inject/ConstructorInjectorStore.java
    trunk/src/com/google/inject/InjectorImpl.java
    trunk/src/com/google/inject/internal/Errors.java
    trunk/test/com/google/inject/AllTests.java
    trunk/test/com/google/inject/InjectableTypeListenerTest.java

Log:
Error handling. Now if InjectionListeners or InjectableTypeListeners fail,  
we include those errors in our pretty error report.

Modified: trunk/src/com/google/inject/ConstructorInjector.java
==============================================================================
--- trunk/src/com/google/inject/ConstructorInjector.java        (original)
+++ trunk/src/com/google/inject/ConstructorInjector.java        Thu Mar 26  
15:01:18 2009
@@ -95,7 +95,12 @@
        }

        for (InjectionListener<? super T> injectionListener :  
injectionListeners) {
-        injectionListener.afterInjection(t); // TODO: handle user  
exceptions here
+        try {
+          injectionListener.afterInjection(t);
+        } catch (RuntimeException e) {
+          throw errors.withSource(constructionProxy.getInjectionPoint())
+              .errorNotifyingInjectionListener(injectionListener,  
injectableType, e).toException();
+        }
        }

        return t;

Modified: trunk/src/com/google/inject/ConstructorInjectorStore.java
==============================================================================
--- trunk/src/com/google/inject/ConstructorInjectorStore.java   (original)
+++ trunk/src/com/google/inject/ConstructorInjectorStore.java   Thu Mar 26  
15:01:18 2009
@@ -64,8 +64,16 @@

    private <T> ConstructorInjector<T> createConstructor(TypeLiteral<T>  
type, 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();
+    }

-    InjectionPoint injectionPoint = InjectionPoint.forConstructorOf(type);
      ImmutableList<SingleParameterInjector<?>> constructorParameterInjectors
          =  
injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
      ImmutableList<SingleMemberInjector> memberInjectors =  
injector.injectors.get(type, errors);
@@ -83,8 +91,11 @@

      for (InjectableTypeListenerBinding typeListener :  
injectableTypeListenerBindings) {
        if (typeListener.getTypeMatcher().matches(type)) {
-        // TODO: wrap this user code in a better try/catch block
-        typeListener.getListener().hear(injectableType, encounter);
+        try {
+          typeListener.getListener().hear(injectableType, encounter);
+        } catch (RuntimeException e) {
+          errors.errorNotifyingTypeListener(typeListener, injectableType,  
e);
+        }
        }
      }

@@ -96,6 +107,8 @@
            injectionPoint, type, injectableMembers,  
proxyFactory.getInterceptors());
      }

+    errors.throwIfNewErrors(numErrorsBefore);
+
      return new ConstructorInjector<T>(proxyFactory.create(),  
constructorParameterInjectors,
          memberInjectors, encounter.getInjectionListeners(),  
injectableType);
    }
@@ -193,5 +206,9 @@
        return methodInterceptors;
      }
      /*end[AOP]*/
+
+    @Override public String toString() {
+      return type.toString();
+    }
    }
  }

Modified: trunk/src/com/google/inject/InjectorImpl.java
==============================================================================
--- trunk/src/com/google/inject/InjectorImpl.java       (original)
+++ trunk/src/com/google/inject/InjectorImpl.java       Thu Mar 26 15:01:18 2009
@@ -284,7 +284,7 @@
        return new ConvertedConstantBindingImpl<T>(this, key, converted,  
stringBinding);
      } catch (ErrorsException e) {
        throw e;
-    } catch (Exception e) {
+    } catch (RuntimeException e) {
        throw errors.conversionError(stringValue, source, type,  
matchingConverter, e)
            .toException();
      }

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    Thu Mar 26 15:01:18  
2009
@@ -24,6 +24,9 @@
  import com.google.inject.Scope;
  import com.google.inject.TypeLiteral;
  import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectableType;
+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 java.io.PrintWriter;
@@ -125,8 +128,8 @@
    }

    public Errors conversionError(String stringValue, Object source,
-      TypeLiteral<?> type, MatcherAndConverter matchingConverter,  
Exception cause) {
-    return addMessage(cause, "Error converting '%s' (bound at %s) to %s%n"
+      TypeLiteral<?> type, MatcherAndConverter matchingConverter,  
RuntimeException cause) {
+    return errorInUserCode(cause, "Error converting '%s' (bound at %s)  
to %s%n"
          + " using %s.%n"
          + " Reason: %s",
          stringValue, convert(source), type, matchingConverter, cause);
@@ -248,15 +251,29 @@
    }

    public Errors errorInjectingMethod(Throwable cause) {
-    return errorInUserCode("Error injecting method, %s", cause);
+    return errorInUserCode(cause, "Error injecting method, %s", cause);
+  }
+
+  public Errors errorNotifyingTypeListener(InjectableTypeListenerBinding  
listener,
+      InjectableType<?> injectableType, Throwable cause) {
+    return errorInUserCode(cause,
+        "Error notifying InjectableType.Listener %s (bound at %s) of %s.%n"
+        + " Reason: %s",
+        listener.getListener(), convert(listener.getSource()),  
injectableType, cause);
    }

    public Errors errorInjectingConstructor(Throwable cause) {
-    return errorInUserCode("Error injecting constructor, %s", cause);
+    return errorInUserCode(cause, "Error injecting constructor, %s",  
cause);
    }

    public Errors errorInProvider(RuntimeException runtimeException) {
-    return errorInUserCode("Error in custom provider, %s",  
runtimeException);
+    return errorInUserCode(runtimeException, "Error in custom  
provider, %s", runtimeException);
+  }
+
+  public Errors errorNotifyingInjectionListener(
+      InjectionListener listener, InjectableType<?> injectableType,  
RuntimeException cause) {
+    return errorInUserCode(cause, "Error notifying InjectionListener %s  
of %s.%n"
+        + " Reason: %s", listener, injectableType, cause);
    }

    public void exposedButNotBound(Key<?> key) {
@@ -275,13 +292,13 @@
      }
    }

-  public Errors errorInUserCode(String message, Throwable cause) {
+  public Errors errorInUserCode(Throwable cause, String messageFormat,  
Object... arguments) {
      Collection<Message> messages = getMessagesFromThrowable(cause);

      if (!messages.isEmpty()) {
        return merge(messages);
      } else {
-      return addMessage(cause, message, cause);
+      return addMessage(cause, messageFormat, arguments);
      }
    }


Modified: trunk/test/com/google/inject/AllTests.java
==============================================================================
--- trunk/test/com/google/inject/AllTests.java  (original)
+++ trunk/test/com/google/inject/AllTests.java  Thu Mar 26 15:01:18 2009
@@ -30,6 +30,7 @@
  import com.google.inject.spi.ModuleWriterTest;
  import com.google.inject.spi.ProviderMethodsTest;
  import com.google.inject.spi.SpiBindingsTest;
+import com.google.inject.spi.BindingTargetVisitorTest;
  import com.google.inject.util.ProvidersTest;
  import com.google.inject.util.TypesTest;
  import junit.framework.Test;
@@ -51,18 +52,18 @@
      suite.addTestSuite(BoundInstanceInjectionTest.class);
      suite.addTestSuite(BoundProviderTest.class);
      suite.addTestSuite(CircularDependencyTest.class);
-    suite.addTestSuite(TypeConversionTest.class);
-    // suite.addTestSuite(ErrorHandlingTest.class); not a testcase
+    // ErrorHandlingTest.class is not a testcase
      suite.addTestSuite(EagerSingletonTest.class);
      suite.addTestSuite(GenericInjectionTest.class);
      suite.addTestSuite(ImplicitBindingTest.class);
      suite.addTestSuite(InjectableTypeListenerTest.class);
-    suite.addTestSuite(InjectionPointTest.class);
      suite.addTestSuite(InjectorTest.class);
+    // IntegrationTest is AOP-only
      suite.addTestSuite(KeyTest.class);
      suite.addTestSuite(LoggerInjectionTest.class);
-    suite.addTestSuite(ModuleTest.class);
+    // MethodInterceptionTest is AOP-only
      suite.addTestSuite(ModulesTest.class);
+    suite.addTestSuite(ModuleTest.class);
      suite.addTestSuite(NullableInjectionPointTest.class);
      suite.addTestSuite(OptionalBindingTest.class);
      suite.addTestSuite(OverrideModuleTest.class);
@@ -70,29 +71,22 @@
      suite.addTestSuite(PrivateModuleTest.class);
      suite.addTestSuite(ProviderInjectionTest.class);
      suite.addTestSuite(ProvisionExceptionTest.class);
+    // ProxyFactoryTest is AOP-only
      suite.addTestSuite(ReflectionTest.class);
+    suite.addTestSuite(RequestInjectionTest.class);
      suite.addTestSuite(ScopesTest.class);
      suite.addTestSuite(SerializationTest.class);
-    suite.addTestSuite(RequestInjectionTest.class);
      suite.addTestSuite(SuperclassTest.class);
+    suite.addTestSuite(TypeConversionTest.class);
      suite.addTestSuite(TypeLiteralInjectionTest.class);
      suite.addTestSuite(TypeLiteralTest.class);
      suite.addTestSuite(TypeLiteralTypeResolutionTest.class);

-    // spi
-    suite.addTestSuite(ElementsTest.class);
-    suite.addTestSuite(HasDependenciesTest.class);
-    suite.addTestSuite(ProviderMethodsTest.class);
-    suite.addTestSuite(ModuleWriterTest.class);
-    suite.addTestSuite(ModuleRewriterTest.class);
-    suite.addTestSuite(SpiBindingsTest.class);
-
      // internal
      suite.addTestSuite(FinalizableReferenceQueueTest.class);
+    suite.addTestSuite(Jsr166HashMapTest.class);
      suite.addTestSuite(LineNumbersTest.class);
      suite.addTest(MapMakerTestSuite.suite());
-    suite.addTestSuite(Jsr166HashMapTest.class);
-    suite.addTestSuite(TypesTest.class);
      suite.addTestSuite(UniqueAnnotationsTest.class);

      // matcher
@@ -101,11 +95,22 @@
      // names
      suite.addTestSuite(NamesTest.class);

+    // spi
+    suite.addTestSuite(BindingTargetVisitorTest.class);
+    suite.addTestSuite(ElementsTest.class);
+    suite.addTestSuite(HasDependenciesTest.class);
+    suite.addTestSuite(InjectionPointTest.class);
+    suite.addTestSuite(ModuleRewriterTest.class);
+    suite.addTestSuite(ModuleWriterTest.class);
+    suite.addTestSuite(ProviderMethodsTest.class);
+    suite.addTestSuite(SpiBindingsTest.class);
+
      // tools
      // suite.addTestSuite(JmxTest.class); not a testcase

      // util
      suite.addTestSuite(ProvidersTest.class);
+    suite.addTestSuite(TypesTest.class);

      /*if[AOP]*/
      suite.addTestSuite(ProxyFactoryTest.class);

Modified: trunk/test/com/google/inject/InjectableTypeListenerTest.java
==============================================================================
--- trunk/test/com/google/inject/InjectableTypeListenerTest.java        
(original)
+++ trunk/test/com/google/inject/InjectableTypeListenerTest.java        Thu Mar 
26  
15:01:18 2009
@@ -25,6 +25,7 @@
  import com.google.inject.spi.InjectableType;
  import com.google.inject.spi.InjectableType.Encounter;
  import com.google.inject.spi.InjectionListener;
+import static com.google.inject.Asserts.assertContains;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.util.List;
@@ -131,9 +132,129 @@
      assertEquals("felibeep", c.beep());
    }

-  // TODO(jessewilson): injectableType.Listener throws test
+  public void testInjectableTypeListenerThrows() {
+    final InjectableType.Listener clumsyListener = new  
InjectableType.Listener() {
+      int failures = 0;

-  // TODO(jessewilson): injectionlistener throws test
+      public <I> void hear(InjectableType<I> injectableType, Encounter<I>  
encounter) {
+        throw new ClassCastException("whoops, failure #" + (++failures));
+      }
+
+      @Override public String toString() {
+        return "clumsy";
+      }
+    };
+
+    try {
+      Guice.createInjector(new AbstractModule() {
+        protected void configure() {
+          bindListener(any(), clumsyListener);
+          bind(B.class);
+          bind(C.class);
+        }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(),
+          "1) Error notifying InjectableType.Listener clumsy (bound at " +  
getClass().getName(),
+          ".configure(InjectableTypeListenerTest.java:",
+          "of " + B.class.getName(),
+          "Reason: java.lang.ClassCastException: whoops, failure #1",
+          "2) Error notifying InjectableType.Listener clumsy (bound at " +  
getClass().getName(),
+          ".configure(InjectableTypeListenerTest.java:",
+          "of " + C.class.getName(),
+          "Reason: java.lang.ClassCastException: whoops, failure #2");
+    }
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bindListener(any(), clumsyListener);
+      }
+    });
+    try {
+      injector.getProvider(B.class);
+      fail();
+    } catch (ConfigurationException expected) {
+      assertContains(expected.getMessage(),
+          "1) Error notifying InjectableType.Listener clumsy (bound at " +  
getClass().getName(),
+          ".configure(InjectableTypeListenerTest.java:",
+          "of " + B.class.getName(),
+          "Reason: java.lang.ClassCastException: whoops, failure #3");
+    }
+
+    // getting it again should yield the same exception #3
+    try {
+      injector.getInstance(B.class);
+      fail();
+    } catch (ConfigurationException expected) {
+      assertContains(expected.getMessage(),
+          "1) Error notifying InjectableType.Listener clumsy (bound at " +  
getClass().getName(),
+          ".configure(InjectableTypeListenerTest.java:",
+          "of " + B.class.getName(),
+          "Reason: java.lang.ClassCastException: whoops, failure #3");
+    }
+
+    // non-constructed types do not participate
+    assertSame(Stage.DEVELOPMENT, injector.getInstance(Stage.class));
+  }
+
+  public void testInjectionListenerThrows() {
+    final InjectionListener<Object> injectionListener = new  
InjectionListener<Object>() {
+      int failures = 0;
+
+      public void afterInjection(Object injectee) {
+        throw new ClassCastException("whoops, failure #" + (++failures));
+      }
+
+      @Override public String toString() {
+        return "goofy";
+      }
+    };
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        bindListener(any(), new InjectableType.Listener() {
+          public <I> void hear(InjectableType<I> injectableType,  
Encounter<I> encounter) {
+            encounter.register(injectionListener);
+          }
+        });
+        bind(B.class);
+      }
+    });
+
+    try {
+      injector.getInstance(A.class);
+      fail();
+    } catch (ProvisionException e) {
+      assertContains(e.getMessage(),
+          "1) Error notifying InjectionListener goofy of " +  
A.class.getName(),
+          " 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 notifying InjectionListener goofy of " +  
A.class.getName(),
+          " 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 notifying InjectionListener goofy of " +  
B.class.getName(),
+          " Reason: java.lang.ClassCastException: whoops, failure #3");
+    }
+
+    // non-constructed types do not participate
+    assertSame(Stage.DEVELOPMENT, injector.getInstance(Stage.class));
+  }

    static class A {
      @Inject Injector injector;

--~--~---------~--~----~------------~-------~--~----~
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