Revision: 1271
Author: sberlin
Date: Wed Sep 22 20:16:22 2010
Log: new AssistedInject factories now implement HasDependencies (like the
old assistedinject factories)
http://code.google.com/p/google-guice/source/detail?r=1271
Modified:
/trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
/trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryModuleBuilderTest.java
=======================================
---
/trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
Sat Jul 31 09:08:27 2010
+++
/trunk/extensions/assistedinject/src/com/google/inject/assistedinject/FactoryProvider2.java
Wed Sep 22 20:16:22 2010
@@ -34,6 +34,7 @@
import com.google.inject.internal.util.Classes;
import com.google.inject.internal.util.ImmutableList;
import com.google.inject.internal.util.ImmutableMap;
+import com.google.inject.internal.util.ImmutableSet;
import com.google.inject.internal.util.Iterables;
import com.google.inject.internal.util.ToStringBuilder;
@@ -42,6 +43,7 @@
import static com.google.inject.internal.util.Preconditions.checkState;
import com.google.inject.spi.Dependency;
+import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import com.google.inject.spi.Toolable;
@@ -55,8 +57,10 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* The newer implementation of factory provider. This implementation uses
a child injector to
@@ -67,7 +71,7 @@
* @author [email protected] (Peter Schmitt)
* @author [email protected] (Sam Berlin)
*/
-final class FactoryProvider2<F> implements InvocationHandler, Provider<F> {
+final class FactoryProvider2<F> implements InvocationHandler, Provider<F>,
HasDependencies {
/** if a factory method parameter isn't annotated, it gets this
annotation. */
static final Assisted DEFAULT_ANNOTATION = new Assisted() {
@@ -102,6 +106,9 @@
/** the parameters in the factory method associated with this data. */
final ImmutableList<Key<?>> paramTypes;
+ /** All non-assisted dependencies required by this method. */
+ final Set<Dependency<?>> dependencies;
+
/** true if {...@link #validForOptimizedAssistedInject} returned true. */
final boolean optimized;
/** the list of optimized providers, empty if not optimized. */
@@ -111,12 +118,14 @@
AssistData(Constructor<?> constructor, Key<?> returnType,
ImmutableList<Key<?>> paramTypes, boolean optimized,
- List<ThreadLocalProvider> providers) {
+ List<ThreadLocalProvider> providers,
+ Set<Dependency<?>> dependencies) {
this.constructor = constructor;
this.returnType = returnType;
this.paramTypes = paramTypes;
this.optimized = optimized;
this.providers = providers;
+ this.dependencies = dependencies;
}
@Override
@@ -128,6 +137,7 @@
.add("optimized", optimized)
.add("providers", providers)
.add("cached binding", cachedBinding)
+ .add("dependencies", dependencies)
.toString();
}
@@ -206,13 +216,14 @@
Constructor<?> constructor =
(Constructor)ctorInjectionPoint.getMember();
List<ThreadLocalProvider> providers = Collections.emptyList();
+ Set<Dependency<?>> deps = getDependencies(ctorInjectionPoint,
implementation);
boolean optimized = false;
// Now go through all dependencies of the implementation and see
if it is OK to
// use an optimized form of assistedinject2. The optimized form
requires that
// all injections directly inject the object itself (and not a
Provider of the object,
// or an Injector), because it caches a single child injector and
mutates the Provider
// of the arguments in a ThreadLocal.
- if(validForOptimizedAssistedInject(ctorInjectionPoint,
implementation)) {
+ if(isValidForOptimizedAssistedInject(deps)) {
ImmutableList.Builder<ThreadLocalProvider> providerListBuilder =
ImmutableList.builder();
for(int i = 0; i < params.size(); i++) {
providerListBuilder.add(new ThreadLocalProvider());
@@ -220,7 +231,9 @@
providers = providerListBuilder.build();
optimized = true;
}
- assistDataBuilder.put(method, new AssistData(constructor,
returnType, immutableParamList, optimized, providers));
+ assistDataBuilder.put(method,
+ new AssistData(constructor, returnType, immutableParamList,
+ optimized, providers, removeAssistedDeps(deps)));
}
// If we generated any errors (from finding matching constructors,
for instance), throw an exception.
@@ -240,6 +253,14 @@
public F get() {
return factory;
}
+
+ public Set<Dependency<?>> getDependencies() {
+ Set<Dependency<?>> combinedDeps = new HashSet<Dependency<?>>();
+ for(AssistData data : assistDataByMethod.values()) {
+ combinedDeps.addAll(data.dependencies);
+ }
+ return ImmutableSet.copyOf(combinedDeps);
+ }
/**
* Returns true if the ConfigurationException is due to an error of
TypeLiteral not being fully
@@ -370,30 +391,41 @@
// All @Assisted params match up to the method's parameters.
return true;
}
-
- /**
- * Returns true if the implementation & constructor are suitable for an
- * optimized version of AssistedInject. The optimized version caches the
- * binding & uses a ThreadLocal Provider, so can only be applied if the
- * assisted bindings are immediately provided. This looks for hints that
the
- * values may be lazily retrieved, by looking for injections of Injector
or a
- * Provider for the assisted values.
- */
- private boolean validForOptimizedAssistedInject(InjectionPoint
ctorPoint, TypeLiteral<?> implementation) {
- if(ctorPoint != null) {
- for(Dependency<?> dep : ctorPoint.getDependencies()) {
- if(isInjectorOrAssistedProvider(dep)) {
- return false;
- }
+
+ /** Calculates all dependencies required by the implementation and
constructor. */
+ private Set<Dependency<?>> getDependencies(InjectionPoint ctorPoint,
TypeLiteral<?> implementation) {
+ ImmutableSet.Builder<Dependency<?>> builder = ImmutableSet.builder();
+ builder.addAll(ctorPoint.getDependencies());
+ if (!implementation.getRawType().isInterface()) {
+ for (InjectionPoint ip :
InjectionPoint.forInstanceMethodsAndFields(implementation)) {
+ builder.addAll(ip.getDependencies());
+ }
+ }
+ return builder.build();
+ }
+
+ /** Return all non-assisted dependencies. */
+ private Set<Dependency<?>> removeAssistedDeps(Set<Dependency<?>> deps) {
+ ImmutableSet.Builder<Dependency<?>> builder = ImmutableSet.builder();
+ for(Dependency<?> dep : deps) {
+ Class annotationType = dep.getKey().getAnnotationType();
+ if (annotationType == null |
| !annotationType.equals(Assisted.class)) {
+ builder.add(dep);
}
}
- if(!implementation.getRawType().isInterface()) {
- for(InjectionPoint ip :
InjectionPoint.forInstanceMethodsAndFields(implementation)) {
- for(Dependency<?> dep : ip.getDependencies()) {
- if(isInjectorOrAssistedProvider(dep)) {
- return false;
- }
- }
+ return builder.build();
+ }
+
+ /**
+ * Returns true if all dependencies are suitable for the optimized
version of AssistedInject. The
+ * optimized version caches the binding & uses a ThreadLocal Provider,
so can only be applied if
+ * the assisted bindings are immediately provided. This looks for hints
that the values may be
+ * lazily retrieved, by looking for injections of Injector or a Provider
for the assisted values.
+ */
+ private boolean isValidForOptimizedAssistedInject(Set<Dependency<?>>
dependencies) {
+ for (Dependency<?> dep : dependencies) {
+ if (isInjectorOrAssistedProvider(dep)) {
+ return false;
}
}
return true;
=======================================
---
/trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryModuleBuilderTest.java
Sat Jul 17 09:39:00 2010
+++
/trunk/extensions/assistedinject/test/com/google/inject/assistedinject/FactoryModuleBuilderTest.java
Wed Sep 22 20:16:22 2010
@@ -17,25 +17,37 @@
package com.google.inject.assistedinject;
import static com.google.inject.Asserts.assertContains;
+import static com.google.inject.name.Names.named;
+
+import java.awt.Color;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
import com.google.inject.AbstractModule;
+import com.google.inject.Binding;
import com.google.inject.CreationException;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
+import com.google.inject.Module;
import com.google.inject.Provides;
+import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
+import com.google.inject.internal.util.ImmutableSet;
import com.google.inject.internal.util.Iterables;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.Elements;
+import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.Message;
-import junit.framework.TestCase;
-
-import java.awt.*;
-import java.util.Collection;
-
public class FactoryModuleBuilderTest extends TestCase {
public void testImplicitForwardingAssistedBindingFailsWithInterface() {
@@ -341,6 +353,85 @@
AbstractCar create(Color color);
}
public static class ArtCar extends AbstractCar {}
-
-
-}
+
+ public void testFactoryBindingDependencies() {
+ // validate dependencies work in all stages & as a raw element,
+ // and that dependencies work for methods, fields, constructors,
+ // and for @AssistedInject constructors too.
+ Module module = new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(Integer.class).toInstance(42);
+ bind(Double.class).toInstance(4.2d);
+ bind(Float.class).toInstance(4.2f);
+ bind(String.class).annotatedWith(named("dog")).toInstance("dog");
+ bind(String.class).annotatedWith(named("cat1")).toInstance("cat1");
+ bind(String.class).annotatedWith(named("cat2")).toInstance("cat2");
+ bind(String.class).annotatedWith(named("cat3")).toInstance("cat3");
+
bind(String.class).annotatedWith(named("arbitrary")).toInstance("fail!");
+ install(new FactoryModuleBuilder()
+ .implement(Animal.class, Dog.class)
+ .build(AnimalHouse.class));
+ }
+ };
+
+ Set<Key<?>> expectedKeys = ImmutableSet.<Key<?>>of(
+ Key.get(Integer.class),
+ Key.get(Double.class),
+ Key.get(Float.class),
+ Key.get(String.class, named("dog")),
+ Key.get(String.class, named("cat1")),
+ Key.get(String.class, named("cat2")),
+ Key.get(String.class, named("cat3"))
+ );
+
+ Injector injector = Guice.createInjector(module);
+ validateDependencies(expectedKeys,
injector.getBinding(AnimalHouse.class));
+
+ injector = Guice.createInjector(Stage.TOOL, module);
+ validateDependencies(expectedKeys,
injector.getBinding(AnimalHouse.class));
+
+ List<Element> elements = Elements.getElements(module);
+ boolean found = false;
+ for(Element element : elements) {
+ if(element instanceof Binding) {
+ Binding binding = (Binding)element;
+ if(binding.getKey().equals(Key.get(AnimalHouse.class))) {
+ found = true;
+ validateDependencies(expectedKeys, binding);
+ break;
+ }
+ }
+ }
+ assertTrue(found);
+ }
+
+ private void validateDependencies(Set<Key<?>> expectedKeys, Binding<?>
binding) {
+ Set<Dependency<?>> dependencies =
((HasDependencies)binding).getDependencies();
+ Set<Key<?>> actualKeys = new HashSet<Key<?>>();
+ for(Dependency dependency : dependencies) {
+ actualKeys.add(dependency.getKey());
+ }
+ assertEquals(expectedKeys, actualKeys);
+ }
+
+ interface AnimalHouse {
+ Animal createAnimal(String name);
+ Cat createCat(String name);
+ Cat createCat(int age);
+ }
+
+ interface Animal {}
+ private static class Dog implements Animal {
+ @Inject int a;
+ @Inject Dog(@Assisted String a, double b) {}
+ @Inject void register(@Named("dog") String a) {}
+ }
+ private static class Cat implements Animal {
+ @Inject float a;
+ @AssistedInject Cat(@Assisted String a, @Named("cat1") String b) {}
+ @AssistedInject Cat(@Assisted int a, @Named("cat2") String b) {}
+ @AssistedInject Cat(@Assisted byte a, @Named("catfail") String b) {}
// not a dependency!
+ @Inject void register(@Named("cat3") String a) {}
+ }
+}
--
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.