Revision: 1427
Author: sber...@gmail.com
Date: Fri Nov 26 17:56:53 2010
Log: add more tests for @CheckedProvides methods, fix bug exposed with @Exposed methods, cleanup class names & javadoc.
http://code.google.com/p/google-guice/source/detail?r=1427

Added:
/trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java /trunk/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderMethodsModuleTest.java
Deleted:
/trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java
Modified:
/trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java

=======================================
--- /dev/null
+++ /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethod.java Fri Nov 26 17:56:53 2010
@@ -0,0 +1,154 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.throwingproviders;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Set;
+
+import com.google.inject.Binder;
+import com.google.inject.Exposed;
+import com.google.inject.Key;
+import com.google.inject.PrivateBinder;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.ScopedBindingBuilder;
+import com.google.inject.internal.util.ImmutableSet;
+import com.google.inject.internal.util.StackTraceElements;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.HasDependencies;
+import com.google.inject.throwingproviders.ThrowingProviderBinder.SecondaryBinder;
+
+/**
+ * A provider that invokes a method and returns its result.
+ *
+ * @author sa...@google.com (Sam Berlin)
+ */
+class CheckedProviderMethod<T> implements CheckedProvider<T>, HasDependencies {
+  private final Key<T> key;
+  private final Class<? extends Annotation> scopeAnnotation;
+  private final Object instance;
+  private final Method method;
+  private final ImmutableSet<Dependency<?>> dependencies;
+  private final List<Provider<?>> parameterProviders;
+  private final boolean exposed;
+  private final Class<? extends CheckedProvider> checkedProvider;
+  private final List<TypeLiteral<?>> exceptionTypes;
+
+  CheckedProviderMethod(
+      Key<T> key,
+      Method method,
+      Object instance,
+      ImmutableSet<Dependency<?>> dependencies,
+      List<Provider<?>> parameterProviders,
+      Class<? extends Annotation> scopeAnnotation,
+      Class<? extends CheckedProvider> checkedProvider,
+      List<TypeLiteral<?>> exceptionTypes) {
+    this.key = key;
+    this.scopeAnnotation = scopeAnnotation;
+    this.instance = instance;
+    this.dependencies = dependencies;
+    this.method = method;
+    this.parameterProviders = parameterProviders;
+    this.exposed = method.isAnnotationPresent(Exposed.class);
+    this.checkedProvider = checkedProvider;
+    this.exceptionTypes = exceptionTypes;
+
+    method.setAccessible(true);
+  }
+
+  void configure(Binder binder) {
+    binder = binder.withSource(method);
+
+    SecondaryBinder<?> sbinder =
+      ThrowingProviderBinder.create(binder)
+        .bind(checkedProvider, key.getTypeLiteral().getType());
+    if(key.getAnnotation() != null) {
+      sbinder = sbinder.annotatedWith(key.getAnnotation());
+    } else if(key.getAnnotationType() != null) {
+      sbinder = sbinder.annotatedWith(key.getAnnotationType());
+    }
+    ScopedBindingBuilder sbbuilder = sbinder.toProviderMethod(this);
+    if(scopeAnnotation != null) {
+      sbbuilder.in(scopeAnnotation);
+    }
+
+    if (exposed) {
+ // the cast is safe 'cause the only binder we have implements PrivateBinder. If there's a + // misplaced @Exposed, calling this will add an error to the binder's error queue
+      ((PrivateBinder) binder).expose(sbinder.getKey());
+    }
+
+    // Validate the exceptions in the method match the exceptions
+    // in the CheckedProvider.
+    for(TypeLiteral<?> exType : exceptionTypes) {
+      Class<?> exActual = exType.getRawType();
+      // Ignore runtime exceptions & errors.
+ if(RuntimeException.class.isAssignableFrom(exActual) || Error.class.isAssignableFrom(exActual)) {
+        continue;
+      }
+
+      boolean notAssignable = true;
+ for(Class<? extends Throwable> exExpected : sbinder.getExceptionTypes()) {
+        if (exExpected.isAssignableFrom(exActual)) {
+          notAssignable = false;
+          break;
+        }
+      }
+      if(notAssignable) {
+        binder.addError(
+ "%s is not compatible with the exceptions (%s) declared in the CheckedProvider interface (%s)",
+            exActual, sbinder.getExceptionTypes(), checkedProvider);
+      }
+    }
+  }
+
+  public T get() throws Exception {
+    Object[] parameters = new Object[parameterProviders.size()];
+    for (int i = 0; i < parameters.length; i++) {
+      parameters[i] = parameterProviders.get(i).get();
+    }
+
+    try {
+      // We know this cast is safe becase T is the method's return type.
+      @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" })
+      T result = (T) method.invoke(instance, parameters);
+      return result;
+    } catch (IllegalAccessException e) {
+      throw new AssertionError(e);
+    } catch (InvocationTargetException e) {
+      Throwable t = e.getCause();
+      if(t instanceof Exception) {
+        throw (Exception)t;
+      } else if(t instanceof Error) {
+        throw (Error)t;
+      } else {
+        throw new IllegalStateException(t);
+      }
+    }
+  }
+
+  public Set<Dependency<?>> getDependencies() {
+    return dependencies;
+  }
+
+  @Override public String toString() {
+ return "@CheckedProvides " + StackTraceElements.forMember(method).toString();
+  }
+}
=======================================
--- /dev/null
+++ /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProviderMethodsModule.java Fri Nov 26 17:56:53 2010
@@ -0,0 +1,152 @@
+/**
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.throwingproviders;
+
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.Annotations;
+import com.google.inject.internal.Errors;
+import com.google.inject.internal.UniqueAnnotations;
+import com.google.inject.internal.util.ImmutableSet;
+import com.google.inject.internal.util.Lists;
+import static com.google.inject.internal.util.Preconditions.checkNotNull;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.Message;
+import com.google.inject.util.Modules;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * Creates bindings to methods annotated with {...@literal @}...@link CheckedProvides}. Use the scope
+ * and binding annotations on the provider method to configure the binding.
+ *
+ * @author sa...@google.com (Sam Berlin)
+ */
+final class CheckedProviderMethodsModule implements Module {
+  private final Object delegate;
+  private final TypeLiteral<?> typeLiteral;
+
+  private CheckedProviderMethodsModule(Object delegate) {
+    this.delegate = checkNotNull(delegate, "delegate");
+    this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
+  }
+
+  /**
+ * Returns a module which creates bindings for provider methods from the given module.
+   */
+  static Module forModule(Module module) {
+ // avoid infinite recursion, since installing a module always installs itself
+    if (module instanceof CheckedProviderMethodsModule) {
+      return Modules.EMPTY_MODULE;
+    }
+
+    return new CheckedProviderMethodsModule(module);
+  }
+
+  public synchronized void configure(Binder binder) {
+ for (CheckedProviderMethod<?> throwingProviderMethod : getProviderMethods(binder)) {
+      throwingProviderMethod.configure(binder);
+    }
+  }
+
+  List<CheckedProviderMethod<?>> getProviderMethods(Binder binder) {
+    List<CheckedProviderMethod<?>> result = Lists.newArrayList();
+ for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
+      for (Method method : c.getDeclaredMethods()) {
+        CheckedProvides checkedProvides =
+          (CheckedProvides)method.getAnnotation(CheckedProvides.class);
+        if(checkedProvides != null) {
+ result.add(createProviderMethod(binder, method, checkedProvides.value()));
+        }
+      }
+    }
+    return result;
+  }
+
+ <T> CheckedProviderMethod<T> createProviderMethod(Binder binder, final Method method,
+      Class<? extends CheckedProvider> throwingProvider) {
+    binder = binder.withSource(method);
+    Errors errors = new Errors(method);
+
+    // prepare the parameter providers
+    List<Dependency<?>> dependencies = Lists.newArrayList();
+    List<Provider<?>> parameterProviders = Lists.newArrayList();
+ List<TypeLiteral<?>> parameterTypes = typeLiteral.getParameterTypes(method);
+    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+    for (int i = 0; i < parameterTypes.size(); i++) {
+ Key<?> key = getKey(errors, parameterTypes.get(i), method, parameterAnnotations[i]);
+      if(key.equals(Key.get(Logger.class))) {
+        // If it was a Logger, change the key to be unique & bind it to a
+        // provider that provides a logger with a proper name.
+ // This solves issue 482 (returning a new anonymous logger on every call exhausts memory) + Key<Logger> loggerKey = Key.get(Logger.class, UniqueAnnotations.create());
+        binder.bind(loggerKey).toProvider(new LogProvider(method));
+        key = loggerKey;
+      }
+      dependencies.add(Dependency.get(key));
+      parameterProviders.add(binder.getProvider(key));
+    }
+
+    @SuppressWarnings("unchecked") // Define T as the method's return type.
+ TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method); + List<TypeLiteral<?>> exceptionTypes = typeLiteral.getExceptionTypes(method);
+
+ Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
+    Class<? extends Annotation> scopeAnnotation
+        = Annotations.findScopeAnnotation(errors, method.getAnnotations());
+
+    for (Message message : errors.getMessages()) {
+      binder.addError(message);
+    }
+
+ return new CheckedProviderMethod<T>(key, method, delegate, ImmutableSet.copyOf(dependencies), + parameterProviders, scopeAnnotation, throwingProvider, exceptionTypes);
+  }
+
+ <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) { + Annotation bindingAnnotation = Annotations.findBindingAnnotation(errors, member, annotations); + return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation);
+  }
+
+  @Override public boolean equals(Object o) {
+    return o instanceof CheckedProviderMethodsModule
+        && ((CheckedProviderMethodsModule) o).delegate == delegate;
+  }
+
+  @Override public int hashCode() {
+    return delegate.hashCode();
+  }
+
+  /** A provider that returns a logger based on the method name. */
+  private static final class LogProvider implements Provider<Logger> {
+    private final String name;
+
+    public LogProvider(Method method) {
+ this.name = method.getDeclaringClass().getName() + "." + method.getName();
+    }
+
+    public Logger get() {
+      return Logger.getLogger(name);
+    }
+  }
+}
=======================================
--- /dev/null
+++ /trunk/extensions/throwingproviders/test/com/google/inject/throwingproviders/CheckedProviderMethodsModuleTest.java Fri Nov 26 17:56:53 2010
@@ -0,0 +1,181 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+
+package com.google.inject.throwingproviders;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.BindingAnnotation;
+import com.google.inject.Exposed;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.PrivateModule;
+import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.BindException;
+import java.rmi.RemoteException;
+
+/**
+ * Test methods for {...@link CheckedProviderMethodsModule}.
+ */
+public class CheckedProviderMethodsModuleTest extends TestCase {
+
+  private final TypeLiteral<RpcProvider<String>> rpcProviderOfString
+      = new TypeLiteral<RpcProvider<String>>() { };
+  private final TypeLiteral<RpcProvider<Integer>> rpcProviderOfInteger
+      = new TypeLiteral<RpcProvider<Integer>>() { };
+  private final TypeLiteral<RpcProvider<Long>> rpcProviderOfLong
+      = new TypeLiteral<RpcProvider<Long>>() { };
+  private final TypeLiteral<RpcProvider<Float>> rpcProviderOfFloat
+      = new TypeLiteral<RpcProvider<Float>>() { };
+ private final TypeLiteral<RpcProvider<Pair<Double, String>>> rpcProviderOfPair
+      = new TypeLiteral<RpcProvider<Pair<Double, String>>>() { };
+
+  private final TestScope testScope = new TestScope();
+
+  interface RpcProvider<T> extends CheckedProvider<T> {
+    T get() throws RemoteException, BindException;
+  }
+
+  @Retention(RetentionPolicy.RUNTIME)
+  @BindingAnnotation
+  @interface TestAnnotation {
+  }
+
+  class TestModule extends AbstractModule {
+
+    private int nextIntToReturn = 100;
+
+    @Override
+    protected void configure() {
+      bindScope(TestScope.Scoped.class, testScope);
+      install(ThrowingProviderBinder.forModule(this));
+      install(new TestPrivateModule());
+    }
+
+    @CheckedProvides(RpcProvider.class)
+    String getSomeStringFromServer() {
+      return "Works";
+    }
+
+    @CheckedProvides(RpcProvider.class) @TestScope.Scoped
+    int getSomeIntegerFromServer() {
+      return nextIntToReturn;
+    }
+
+    @CheckedProvides(RpcProvider.class) @TestAnnotation
+    long getSomeLongFromServer() {
+      return 0xffL;
+    }
+
+    @Provides
+    double getSomeDouble() {
+      return 2.0d;
+    }
+
+    @CheckedProvides(RpcProvider.class)
+    Pair<Double, String> getSomePair(Double input) {
+      return new Pair<Double, String>(input * 2, "foo");
+    }
+
+    @CheckedProvides(RpcProvider.class)
+    float getFloat() throws BindException {
+      throw new BindException("foo");
+    }
+
+    void setNextIntToReturn(int next) {
+      nextIntToReturn = next;
+    }
+  }
+
+  class TestPrivateModule extends PrivateModule {
+
+    @Override
+    protected void configure() {
+      install(ThrowingProviderBinder.forModule(this));
+    }
+
+    @CheckedProvides(RpcProvider.class) @Named("fruit") @Exposed
+    String provideApples() {
+      return "apple";
+    }
+  }
+
+
+ public void testNoAnnotationNoScope() throws BindException, RemoteException {
+    Injector injector = Guice.createInjector(new TestModule());
+    RpcProvider<String> provider = injector
+        .getInstance(Key.get(rpcProviderOfString));
+    assertEquals("Works", provider.get());
+  }
+
+  public void testWithScope() throws BindException, RemoteException {
+    TestModule testModule = new TestModule();
+    Injector injector = Guice.createInjector(testModule);
+    RpcProvider<Integer> provider = injector
+        .getInstance(Key.get(rpcProviderOfInteger));
+
+    assertEquals((Integer)100, provider.get());
+    testModule.setNextIntToReturn(120);
+    assertEquals((Integer)100, provider.get());
+    testScope.beginNewScope();
+    assertEquals((Integer)120, provider.get());
+  }
+
+  public void testWithAnnotation() throws BindException, RemoteException {
+    TestModule testModule = new TestModule();
+    Injector injector = Guice.createInjector(testModule);
+    RpcProvider<Long> provider = injector
+        .getInstance(Key.get(rpcProviderOfLong, TestAnnotation.class));
+    assertEquals((Long)0xffL, provider.get());
+  }
+
+ public void testWithInjectedParameters() throws BindException, RemoteException {
+    TestModule testModule = new TestModule();
+    Injector injector = Guice.createInjector(testModule);
+    RpcProvider<Pair<Double, String>> provider = injector
+        .getInstance(Key.get(rpcProviderOfPair));
+    Pair<Double, String> pair = provider.get();
+    assertEquals(pair.first, 4.0d);
+  }
+
+  public void testWithThrownException() {
+    TestModule testModule = new TestModule();
+    Injector injector = Guice.createInjector(testModule);
+    RpcProvider<Float> provider = injector
+        .getInstance(Key.get(rpcProviderOfFloat));
+    try {
+      provider.get();
+      fail();
+    } catch (RemoteException e) {
+      fail();
+    } catch (BindException e) {
+      // good
+    }
+  }
+
+  public void testExposedMethod() throws BindException, RemoteException {
+    TestModule testModule = new TestModule();
+    Injector injector = Guice.createInjector(testModule);
+    RpcProvider<String> provider = injector
+        .getInstance(Key.get(rpcProviderOfString, Names.named("fruit")));
+    assertEquals("apple", provider.get());
+
+  }
+
+  private static class Pair<A, B> {
+       A first;
+       B second;
+
+       Pair(A a, B b) {
+        this.first= a;
+        this.second = b;
+       }
+  }
+}
=======================================
--- /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethod.java Wed Nov 17 06:27:41 2010
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * Copyright (C) 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.throwingproviders;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Set;
-
-import com.google.inject.Binder;
-import com.google.inject.Exposed;
-import com.google.inject.Key;
-import com.google.inject.PrivateBinder;
-import com.google.inject.Provider;
-import com.google.inject.TypeLiteral;
-import com.google.inject.binder.ScopedBindingBuilder;
-import com.google.inject.internal.util.ImmutableSet;
-import com.google.inject.internal.util.StackTraceElements;
-import com.google.inject.spi.Dependency;
-import com.google.inject.spi.HasDependencies;
-import com.google.inject.throwingproviders.ThrowingProviderBinder.SecondaryBinder;
-
-/**
- * A provider that invokes a method and returns its result.
- *
- * @author sa...@google.com (Sam Berlin)
- */
-class ThrowingProviderMethod<T> implements CheckedProvider<T>, HasDependencies {
-  private final Key<T> key;
-  private final Class<? extends Annotation> scopeAnnotation;
-  private final Object instance;
-  private final Method method;
-  private final ImmutableSet<Dependency<?>> dependencies;
-  private final List<Provider<?>> parameterProviders;
-  private final boolean exposed;
-  private final Class<? extends CheckedProvider> checkedProvider;
-  private final List<TypeLiteral<?>> exceptionTypes;
-
-  ThrowingProviderMethod(
-      Key<T> key,
-      Method method,
-      Object instance,
-      ImmutableSet<Dependency<?>> dependencies,
-      List<Provider<?>> parameterProviders,
-      Class<? extends Annotation> scopeAnnotation,
-      Class<? extends CheckedProvider> checkedProvider,
-      List<TypeLiteral<?>> exceptionTypes) {
-    this.key = key;
-    this.scopeAnnotation = scopeAnnotation;
-    this.instance = instance;
-    this.dependencies = dependencies;
-    this.method = method;
-    this.parameterProviders = parameterProviders;
-    this.exposed = method.isAnnotationPresent(Exposed.class);
-    this.checkedProvider = checkedProvider;
-    this.exceptionTypes = exceptionTypes;
-
-    method.setAccessible(true);
-  }
-
-  public Key<T> getKey() {
-    return key;
-  }
-
-  public Method getMethod() {
-    return method;
-  }
-
-  public void configure(Binder binder) {
-    binder = binder.withSource(method);
-
-    SecondaryBinder<?> sbinder =
-      ThrowingProviderBinder.create(binder)
-        .bind(checkedProvider, key.getTypeLiteral().getType());
-    if(key.getAnnotation() != null) {
-      sbinder = sbinder.annotatedWith(key.getAnnotation());
-    } else if(key.getAnnotationType() != null) {
-      sbinder = sbinder.annotatedWith(key.getAnnotationType());
-    }
-    ScopedBindingBuilder sbbuilder = sbinder.toProviderMethod(this);
-    if(scopeAnnotation != null) {
-      sbbuilder.in(scopeAnnotation);
-    }
-
-    if (exposed) {
- // the cast is safe 'cause the only binder we have implements PrivateBinder. If there's a - // misplaced @Exposed, calling this will add an error to the binder's error queue
-      ((PrivateBinder) binder).expose(key);
-    }
-
-    // Validate the exceptions in the method match the exceptions
-    // in the CheckedProvider.
-    for(TypeLiteral<?> exType : exceptionTypes) {
-      Class<?> exActual = exType.getRawType();
-      // Ignore runtime exceptions & errors.
- if(RuntimeException.class.isAssignableFrom(exActual) || Error.class.isAssignableFrom(exActual)) {
-        continue;
-      }
-
-      boolean notAssignable = true;
- for(Class<? extends Throwable> exExpected : sbinder.getExceptionTypes()) {
-        if (exExpected.isAssignableFrom(exActual)) {
-          notAssignable = false;
-          break;
-        }
-      }
-      if(notAssignable) {
-        binder.addError(
- "%s is not compatible with the exceptions (%s) declared in the CheckedProvider interface (%s)",
-            exActual, sbinder.getExceptionTypes(), checkedProvider);
-      }
-    }
-  }
-
-  public T get() throws Exception {
-    Object[] parameters = new Object[parameterProviders.size()];
-    for (int i = 0; i < parameters.length; i++) {
-      parameters[i] = parameterProviders.get(i).get();
-    }
-
-    try {
-      // We know this cast is safe becase T is the method's return type.
-      @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" })
-      T result = (T) method.invoke(instance, parameters);
-      return result;
-    } catch (IllegalAccessException e) {
-      throw new AssertionError(e);
-    } catch (InvocationTargetException e) {
-      Throwable t = e.getCause();
-      if(t instanceof Exception) {
-        throw (Exception)t;
-      } else if(t instanceof Error) {
-        throw (Error)t;
-      } else {
-        throw new IllegalStateException(t);
-      }
-    }
-  }
-
-  public Set<Dependency<?>> getDependencies() {
-    return dependencies;
-  }
-
-  @Override public String toString() {
- return "@CheckedProvides " + StackTraceElements.forMember(method).toString();
-  }
-}
=======================================
--- /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderMethodsModule.java Wed Nov 17 06:27:41 2010
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * Copyright (C) 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.throwingproviders;
-
-import com.google.inject.Binder;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.Provider;
-import com.google.inject.TypeLiteral;
-import com.google.inject.internal.Annotations;
-import com.google.inject.internal.Errors;
-import com.google.inject.internal.UniqueAnnotations;
-import com.google.inject.internal.util.ImmutableSet;
-import com.google.inject.internal.util.Lists;
-import static com.google.inject.internal.util.Preconditions.checkNotNull;
-import com.google.inject.spi.Dependency;
-import com.google.inject.spi.Message;
-import com.google.inject.util.Modules;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.logging.Logger;
-
-/**
- * Creates bindings to methods annotated with {...@literal @}...@link CheckedProvides}. Use the scope
- * and binding annotations on the provider method to configure the binding.
- *
- * @author sa...@google.com (Sam Berlin)
- */
-final class ThrowingProviderMethodsModule implements Module {
-  private final Object delegate;
-  private final TypeLiteral<?> typeLiteral;
-
-  private ThrowingProviderMethodsModule(Object delegate) {
-    this.delegate = checkNotNull(delegate, "delegate");
-    this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
-  }
-
-  /**
- * Returns a module which creates bindings for provider methods from the given module.
-   */
-  static Module forModule(Module module) {
- // avoid infinite recursion, since installing a module always installs itself
-    if (module instanceof ThrowingProviderMethodsModule) {
-      return Modules.EMPTY_MODULE;
-    }
-
-    return new ThrowingProviderMethodsModule(module);
-  }
-
-  public synchronized void configure(Binder binder) {
- for (ThrowingProviderMethod<?> throwingProviderMethod : getProviderMethods(binder)) {
-      throwingProviderMethod.configure(binder);
-    }
-  }
-
-  List<ThrowingProviderMethod<?>> getProviderMethods(Binder binder) {
-    List<ThrowingProviderMethod<?>> result = Lists.newArrayList();
- for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
-      for (Method method : c.getDeclaredMethods()) {
-        CheckedProvides checkedProvides =
-          (CheckedProvides)method.getAnnotation(CheckedProvides.class);
-        if(checkedProvides != null) {
- result.add(createProviderMethod(binder, method, checkedProvides.value()));
-        }
-      }
-    }
-    return result;
-  }
-
- <T> ThrowingProviderMethod<T> createProviderMethod(Binder binder, final Method method,
-      Class<? extends CheckedProvider> throwingProvider) {
-    binder = binder.withSource(method);
-    Errors errors = new Errors(method);
-
-    // prepare the parameter providers
-    List<Dependency<?>> dependencies = Lists.newArrayList();
-    List<Provider<?>> parameterProviders = Lists.newArrayList();
- List<TypeLiteral<?>> parameterTypes = typeLiteral.getParameterTypes(method);
-    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
-    for (int i = 0; i < parameterTypes.size(); i++) {
- Key<?> key = getKey(errors, parameterTypes.get(i), method, parameterAnnotations[i]);
-      if(key.equals(Key.get(Logger.class))) {
-        // If it was a Logger, change the key to be unique & bind it to a
-        // provider that provides a logger with a proper name.
- // This solves issue 482 (returning a new anonymous logger on every call exhausts memory) - Key<Logger> loggerKey = Key.get(Logger.class, UniqueAnnotations.create());
-        binder.bind(loggerKey).toProvider(new LogProvider(method));
-        key = loggerKey;
-      }
-      dependencies.add(Dependency.get(key));
-      parameterProviders.add(binder.getProvider(key));
-    }
-
-    @SuppressWarnings("unchecked") // Define T as the method's return type.
- TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method); - List<TypeLiteral<?>> exceptionTypes = typeLiteral.getExceptionTypes(method);
-
- Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
-    Class<? extends Annotation> scopeAnnotation
-        = Annotations.findScopeAnnotation(errors, method.getAnnotations());
-
-    for (Message message : errors.getMessages()) {
-      binder.addError(message);
-    }
-
- return new ThrowingProviderMethod<T>(key, method, delegate, ImmutableSet.copyOf(dependencies), - parameterProviders, scopeAnnotation, throwingProvider, exceptionTypes);
-  }
-
- <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) { - Annotation bindingAnnotation = Annotations.findBindingAnnotation(errors, member, annotations); - return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation);
-  }
-
-  @Override public boolean equals(Object o) {
-    return o instanceof ThrowingProviderMethodsModule
-        && ((ThrowingProviderMethodsModule) o).delegate == delegate;
-  }
-
-  @Override public int hashCode() {
-    return delegate.hashCode();
-  }
-
-  /** A provider that returns a logger based on the method name. */
-  private static final class LogProvider implements Provider<Logger> {
-    private final String name;
-
-    public LogProvider(Method method) {
- this.name = method.getDeclaringClass().getName() + "." + method.getName();
-    }
-
-    public Logger get() {
-      return Logger.getLogger(name);
-    }
-  }
-}
=======================================
--- /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java Wed Nov 17 06:27:41 2010 +++ /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/CheckedProvides.java Fri Nov 26 17:56:53 2010
@@ -23,9 +23,13 @@
 import java.lang.annotation.Target;

 /**
- * Annotates methods of a {...@link Module} to create a provider method binding that can throw - * exceptions. The method's return type is bound to it's returned value. Guice will pass
- * dependencies to the method as parameters.
+ * Annotates methods of a {...@link Module} to create a {...@link CheckedProvider} + * method binding that can throw exceptions. The method's return type is bound
+ * to a {...@link CheckedProvider} that can be injected. Guice will pass
+ * dependencies to the method as parameters. Install {...@literal @}CheckedProvides
+ * methods by using
+ * {...@link ThrowingProviderBinder#forModule(com.google.inject.Module)} on the
+ * module where the methods are declared.
  *
  * @author sa...@google.com (Sam Berlin)
  * @since 3.0
=======================================
--- /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java Wed Nov 17 06:27:41 2010 +++ /trunk/extensions/throwingproviders/src/com/google/inject/throwingproviders/ThrowingProviderBinder.java Fri Nov 26 17:56:53 2010
@@ -89,7 +89,7 @@
    * @since 3.0
    */
   public static Module forModule(Module module) {
-    return ThrowingProviderMethodsModule.forModule(module);
+    return CheckedProviderMethodsModule.forModule(module);
   }

   public <P extends CheckedProvider> SecondaryBinder<P>
@@ -100,11 +100,13 @@
   public class SecondaryBinder<P extends CheckedProvider> {
     private final Class<P> interfaceType;
     private final Type valueType;
-    private Class<? extends Annotation> annotationType;
-    private Annotation annotation;
     private final List<Class<? extends Throwable>> exceptionTypes;
     private final boolean valid;

+    private Class<? extends Annotation> annotationType;
+    private Annotation annotation;
+    private Key<P> interfaceKey;
+
     public SecondaryBinder(Class<P> interfaceType, Type valueType) {
       this.interfaceType = checkNotNull(interfaceType, "interfaceType");
       this.valueType = checkNotNull(valueType, "valueType");
@@ -114,12 +116,16 @@
       } else {
         valid = false;
         this.exceptionTypes = ImmutableList.of();
-      }
+      }
     }

     List<Class<? extends Throwable>> getExceptionTypes() {
       return exceptionTypes;
     }
+
+    Key<P> getKey() {
+       return interfaceKey;
+    }

public SecondaryBinder<P> annotatedWith(Class<? extends Annotation> annotationType) {
       if (!(this.annotationType == null && this.annotation == null)) {
@@ -147,9 +153,9 @@
       return to(Key.get(targetType));
     }

- ScopedBindingBuilder toProviderMethod(ThrowingProviderMethod<?> target) {
-      Key<ThrowingProviderMethod> targetKey =
-        Key.get(ThrowingProviderMethod.class, UniqueAnnotations.create());
+ ScopedBindingBuilder toProviderMethod(CheckedProviderMethod<?> target) {
+      Key<CheckedProviderMethod> targetKey =
+        Key.get(CheckedProviderMethod.class, UniqueAnnotations.create());
       binder.bind(targetKey).toInstance(target);

       return toInternal(targetKey);
@@ -162,13 +168,13 @@

private ScopedBindingBuilder toInternal(final Key<? extends CheckedProvider> targetKey) { final Key<Result> resultKey = Key.get(Result.class, UniqueAnnotations.create());
-      final Key<P> key = createKey();
final Provider<Result> resultProvider = binder.getProvider(resultKey); final Provider<? extends CheckedProvider> targetProvider = binder.getProvider(targetKey);
+      interfaceKey = createKey();

// don't bother binding the proxy type if this is in an invalid state.
       if(valid) {
-        binder.bind(key).toProvider(new ProviderWithDependencies<P>() {
+ binder.bind(interfaceKey).toProvider(new ProviderWithDependencies<P>() { private final P instance = interfaceType.cast(Proxy.newProxyInstance( interfaceType.getClassLoader(), new Class<?>[] { interfaceType },
               new InvocationHandler() {
@@ -218,7 +224,6 @@
* Returns the exception type declared to be thrown by the get method of
      * {...@code interfaceType}.
      */
-    @SuppressWarnings({"unchecked"})
private List<Class<? extends Throwable>> getExceptionType(Class<P> interfaceType) {
       try {
         Method getMethod = interfaceType.getMethod("get");
@@ -379,7 +384,6 @@
       }
     }

-    @SuppressWarnings("unused")
-    private static long serialVersionUID = 0L;
+    private static final long serialVersionUID = 0L;
   }
 }

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

Reply via email to