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.