Skip to content

Instantly share code, notes, and snippets.

@gissuebot
Created July 7, 2014 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gissuebot/2fe77187560ecc421691 to your computer and use it in GitHub Desktop.
Save gissuebot/2fe77187560ecc421691 to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 435, comment 10
### Eclipse Workspace Patch 1.0
#P guice
Index: extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
===================================================================
--- extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java (revision 1143)
+++ extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java (working copy)
@@ -35,10 +35,13 @@
import static com.google.inject.internal.Iterables.getOnlyElement;
import com.google.inject.internal.Lists;
import static com.google.inject.internal.Preconditions.checkState;
+
+import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import com.google.inject.spi.Toolable;
import com.google.inject.util.Providers;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@@ -81,6 +84,7 @@
/** the produced type, or null if all methods return concrete types */
private final BindingCollector collector;
+ private final ImmutableMap<Method, Constructor<?>> constructorsByMethod;
private final ImmutableMap<Method, Key<?>> returnTypesByMethod;
private final ImmutableMap<Method, ImmutableList<Key<?>>> paramTypes;
@@ -104,6 +108,7 @@
Class<F> factoryRawType = (Class) factoryType.getRawType();
try {
+ ImmutableMap.Builder<Method, Constructor<?>> constructorsBuilder = ImmutableMap.builder();
ImmutableMap.Builder<Method, Key<?>> returnTypesBuilder = ImmutableMap.builder();
ImmutableMap.Builder<Method, ImmutableList<Key<?>>> paramTypesBuilder
= ImmutableMap.builder();
@@ -120,10 +125,41 @@
Key<?> paramKey = getKey(param, method, paramAnnotations[p++], errors);
keys.add(assistKey(method, paramKey, errors));
}
- paramTypesBuilder.put(method, ImmutableList.copyOf(keys));
+ ImmutableList<Key<?>> immutableParamList = ImmutableList.copyOf(keys);
+ paramTypesBuilder.put(method, immutableParamList);
+
+ // try to match up the method to the constructor
+ TypeLiteral<?> implementation = collector.getBindings().get(returnType);
+ if(implementation == null) {
+ implementation = returnType.getTypeLiteral();
+ }
+ // TODO: Support finding the proper constructor per method...
+ // Right now, this will fail later on if it's the wrong constructor, because it will
+ // be missing necessary bindings.
+ Constructor<?> constructor = null;
+ try {
+ constructor = (Constructor)InjectionPoint.forConstructorOf(implementation).getMember();
+ } catch(ConfigurationException ce) {
+ // There are two reasons this could throw.
+ // 1) The implementation is an interface and is forwarded (explicitly or implicitly)
+ // to another binding (see FactoryModuleBuildTest.test[Implicit|Explicit]ForwardingAssistedBinding.
+ // In this case, things are OK and the exception is right to be ignored.
+ // 2) The implementation has something wrong with its constructors (two @injects, invalid ctor, etc..)
+ // In this case, by having a null constructor we let the proper exception be recreated later on.
+ }
+ if(constructor != null) {
+ constructorsBuilder.put(method, constructor);
+ }
}
+
+ // If we generated any errors (from finding matching constructors, for instance), throw an exception.
+ if(errors.hasErrors()) {
+ throw errors.toException();
+ }
+
returnTypesByMethod = returnTypesBuilder.build();
paramTypes = paramTypesBuilder.build();
+ constructorsByMethod = constructorsBuilder.build();
} catch (ErrorsException e) {
throw new ConfigurationException(e.getErrors().getMessages());
}
@@ -135,7 +171,7 @@
public F get() {
return factory;
}
-
+
/**
* Returns a key similar to {@code key}, but with an {@literal @}Assisted binding annotation.
* This fails if another binding annotation is clobbered in the process. If the key already has
@@ -197,10 +233,31 @@
binder.bind((Key) paramKey).toProvider(Providers.of(args[p++]));
}
- if (collector.getBindings().containsKey(returnType)) {
- binder.bind(assistedReturnType).to((TypeLiteral) collector.getBindings().get(returnType));
+
+ Constructor<?> constructor = constructorsByMethod.get(method);
+ // If the injector already has a binding for the return type, don't
+ // bother binding to a specific constructor. Otherwise, there could be
+ // bugs where an implicit binding isn't used (or an explicitly forwarded
+ // binding isn't used)
+ if (injector.getExistingBinding(returnType) != null) {
+ constructor = null;
+ }
+
+
+ TypeLiteral<?> implementation = collector.getBindings().get(returnType);
+ if (implementation != null) {
+ if(constructor == null) {
+ binder.bind(assistedReturnType).to((TypeLiteral)implementation);
+ } else {
+ binder.bind(assistedReturnType).toConstructor((Constructor)constructor, (TypeLiteral)implementation);
+ }
} else {
- binder.bind(assistedReturnType).to((Key) returnType);
+ // no implementation, but need to bind from assisted key to actual key.
+ if(constructor == null) {
+ binder.bind(assistedReturnType).to((Key)returnType);
+ } else {
+ binder.bind(assistedReturnType).toConstructor((Constructor)constructor);
+ }
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment