Automated g4 rollback of changelist 70738452.
*** Reason for rollback ***
Fix projects that were doing dependency analysis by returning a dependency on the Injector when run on raw Elements (instead of a dependency on @Actual+@Default, even though we didn't know which would really exist).
*** Original change description ***
Automated g4 rollback of changelist 70734332.
*** Reason for rollback ***
Broke a project.
*** Original change description ***
Simplify OptionalBinder implementation to not delegate to a MapBinder.
Instead, bind directly to annotated @Actual/@Default keys. This is in
preparation for future improvements.
This contains two logical changes:
1) The error message for duplicate actual/default bindings is now the default Guice message, instead of a custom thing in MapBinder.
2) getDependencies now...
***
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=70742247
diff --git a/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java b/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java
index 5d4447d..4d4dfac 100644
--- a/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java
+++ b/extensions/multibindings/src/com/google/inject/multibindings/OptionalBinder.java
@@ -17,14 +17,12 @@
package com.google.inject.multibindings;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.inject.internal.RehashableKeys.Keys.needsRehashing;
-import static com.google.inject.internal.RehashableKeys.Keys.rehash;
import static com.google.inject.multibindings.Multibinder.checkConfiguration;
import static com.google.inject.util.Types.newParameterizedType;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Inject;
@@ -34,12 +32,9 @@
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
-import com.google.inject.internal.Errors;
-import com.google.inject.multibindings.Element.Type;
-import com.google.inject.multibindings.MapBinder.RealMapBinder;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
-import com.google.inject.spi.HasDependencies;
+import com.google.inject.spi.Element;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderLookup;
import com.google.inject.spi.ProviderWithDependencies;
@@ -47,9 +42,14 @@
import com.google.inject.spi.Toolable;
import com.google.inject.util.Types;
-import java.util.Map;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.reflect.Type;
import java.util.Set;
+import javax.inject.Qualifier;
+
/**
* An API to bind optional values, optionally with a default value.
@@ -168,6 +168,12 @@
return (TypeLiteral<Optional<Provider<T>>>) TypeLiteral.get(Types.newParameterizedType(
Optional.class, newParameterizedType(Provider.class, type.getType())));
}
+
+ @SuppressWarnings("unchecked")
+ static <T> Key<Provider<T>> providerOf(Key<T> key) {
+ Type providerT = Types.providerOf(key.getTypeLiteral().getType());
+ return (Key<Provider<T>>) key.ofType(providerT);
+ }
/**
* Returns a binding builder used to set the default value that will be injected.
@@ -189,6 +195,18 @@
public abstract LinkedBindingBuilder<T> setBinding();
enum Source { DEFAULT, ACTUAL }
+
+ @Retention(RUNTIME)
+ @Qualifier
+ @interface Default {
+ String value();
+ }
+
+ @Retention(RUNTIME)
+ @Qualifier
+ @interface Actual {
+ String value();
+ }
/**
* The actual OptionalBinder plays several roles. It implements Module to hide that
@@ -199,18 +217,21 @@
private final Key<Optional<T>> optionalKey;
private final Key<Optional<javax.inject.Provider<T>>> optionalJavaxProviderKey;
private final Key<Optional<Provider<T>>> optionalProviderKey;
- private final Key<Map<Source, Provider<T>>> mapKey;
- private final RealMapBinder<Source, T> mapBinder;
- private final Set<Dependency<?>> dependencies;
private final Provider<Optional<Provider<T>>> optionalProviderT;
-
+ private final Key<T> defaultKey;
+ private final Key<T> actualKey;
/** the target injector's binder. non-null until initialization, null afterwards */
private Binder binder;
/** the default binding, for the SPI. */
- private Binding<?> defaultBinding;
+ private Binding<T> defaultBinding;
/** the actual binding, for the SPI */
- private Binding<?> actualBinding;
+ private Binding<T> actualBinding;
+
+ /** the dependencies -- initialized with defaults & overridden when tooled. */
+ private Set<Dependency<?>> dependencies;
+ /** the dependencies -- initialized with defaults & overridden when tooled. */
+ private Set<Dependency<?>> providerDependencies;
private RealOptionalBinder(Binder binder, Key<T> typeKey) {
this.binder = binder;
@@ -219,26 +240,15 @@
this.optionalKey = typeKey.ofType(optionalOf(literal));
this.optionalJavaxProviderKey = typeKey.ofType(optionalOfJavaxProvider(literal));
this.optionalProviderKey = typeKey.ofType(optionalOfProvider(literal));
- this.mapKey =
- typeKey.ofType(MapBinder.mapOfProviderOf(TypeLiteral.get(Source.class), literal));
- this.dependencies = ImmutableSet.<Dependency<?>>of(Dependency.get(mapKey));
this.optionalProviderT = binder.getProvider(optionalProviderKey);
- if (typeKey.getAnnotation() != null) {
- this.mapBinder = (RealMapBinder<Source, T>) MapBinder.newMapBinder(binder,
- TypeLiteral.get(Source.class), typeKey.getTypeLiteral(), typeKey.getAnnotation());
- } else if (typeKey.getAnnotationType() != null) {
- this.mapBinder = (RealMapBinder<Source, T>) MapBinder.newMapBinder(binder,
- TypeLiteral.get(Source.class), typeKey.getTypeLiteral(), typeKey.getAnnotationType());
- } else {
- this.mapBinder = (RealMapBinder<Source, T>) MapBinder.newMapBinder(binder,
- TypeLiteral.get(Source.class), typeKey.getTypeLiteral());
- }
- mapBinder.updateDuplicateKeyMessage(Source.DEFAULT, "OptionalBinder for "
- + Errors.convert(typeKey)
- + " called with different setDefault values, from bindings:\n");
- mapBinder.updateDuplicateKeyMessage(Source.ACTUAL, "OptionalBinder for "
- + Errors.convert(typeKey)
- + " called with different setBinding values, from bindings:\n");
+ String name = RealElement.nameOf(typeKey);
+ this.defaultKey = Key.get(typeKey.getTypeLiteral(), new DefaultImpl(name));
+ this.actualKey = Key.get(typeKey.getTypeLiteral(), new ActualImpl(name));
+ // Until the injector initializes us, we don't know what our dependencies are,
+ // so initialize to the whole Injector (like Multibinder, and MapBinder indirectly).
+ this.dependencies = ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
+ this.providerDependencies =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
}
/**
@@ -265,82 +275,49 @@
}
@Override public LinkedBindingBuilder<T> setDefault() {
- checkConfiguration(!isInitialized(), "already initialized");
-
+ checkConfiguration(!isInitialized(), "already initialized");
addDirectTypeBinding(binder);
-
- RealElement.BindingBuilder<T> valueBinding = RealElement.addBinding(binder,
- Element.Type.OPTIONALBINDER, typeKey.getTypeLiteral(), RealElement.nameOf(typeKey));
- Key<T> valueKey = Key.get(typeKey.getTypeLiteral(), valueBinding.getAnnotation());
- mapBinder.addBinding(Source.DEFAULT).toProvider(
- new ValueProvider<T>(valueKey, binder.getProvider(valueKey)));
- return valueBinding;
+ return binder.bind(defaultKey);
}
@Override public LinkedBindingBuilder<T> setBinding() {
- checkConfiguration(!isInitialized(), "already initialized");
-
+ checkConfiguration(!isInitialized(), "already initialized");
addDirectTypeBinding(binder);
-
- RealElement.BindingBuilder<T> valueBinding = RealElement.addBinding(binder,
- Element.Type.OPTIONALBINDER, typeKey.getTypeLiteral(), RealElement.nameOf(typeKey));
- Key<T> valueKey = Key.get(typeKey.getTypeLiteral(), valueBinding.getAnnotation());
- mapBinder.addBinding(Source.ACTUAL).toProvider(
- new ValueProvider<T>(valueKey, binder.getProvider(valueKey)));
- return valueBinding;
- }
-
- /**
- * Traverses through the dependencies of the providers in order to get to the user's binding.
- */
- private Binding<?> getBindingFromMapProvider(Injector injector, Provider<T> mapProvider) {
- HasDependencies deps = (HasDependencies) mapProvider;
- Key<?> depKey = Iterables.getOnlyElement(deps.getDependencies()).getKey();
- // The dep flow is (and will stay this way, until we change the internals) --
- // Key[type=Provider<java.lang.String>, annotation=@Element(type=MAPBINDER)]
- // -> Key[type=String, annotation=@Element(type=MAPBINDER)]
- // -> Key[type=Provider<String>, annotation=@Element(type=OPTIONALBINDER)]
- // -> Key[type=String, annotation=@Element(type=OPTIONALBINDER)]
- // The last one points to the user's binding.
- for (int i = 0; i < 3; i++) {
- deps = (HasDependencies) injector.getBinding(depKey);
- depKey = Iterables.getOnlyElement(deps.getDependencies()).getKey();
- }
- return injector.getBinding(depKey);
+ return binder.bind(actualKey);
}
public void configure(Binder binder) {
checkConfiguration(!isInitialized(), "OptionalBinder was already initialized");
- final Provider<Map<Source, Provider<T>>> mapProvider = binder.getProvider(mapKey);
binder.bind(optionalProviderKey).toProvider(
new RealOptionalBinderProviderWithDependencies<Optional<Provider<T>>>(typeKey) {
private Optional<Provider<T>> optional;
@Toolable @Inject void initialize(Injector injector) {
RealOptionalBinder.this.binder = null;
- Map<Source, Provider<T>> map = mapProvider.get();
- // Map might be null if duplicates prevented MapBinder from initializing
- if (map != null) {
- if (map.containsKey(Source.ACTUAL)) {
- // TODO(sameb): Consider exposing an option that will allow
- // ACTUAL to fallback to DEFAULT if ACTUAL's provider returns null.
- // Right now, an ACTUAL binding can convert from present -> absent
- // if it's bound to a provider that returns null.
- optional = Optional.fromNullable(map.get(Source.ACTUAL));
- } else if (map.containsKey(Source.DEFAULT)) {
- optional = Optional.fromNullable(map.get(Source.DEFAULT));
- } else {
- optional = Optional.absent();
- }
-
- // Also set up the bindings for the SPI.
- if (map.containsKey(Source.ACTUAL)) {
- actualBinding = getBindingFromMapProvider(injector, map.get(Source.ACTUAL));
- }
- if (map.containsKey(Source.DEFAULT)) {
- defaultBinding = getBindingFromMapProvider(injector, map.get(Source.DEFAULT));
- }
+ actualBinding = injector.getExistingBinding(actualKey);
+ defaultBinding = injector.getExistingBinding(defaultKey);
+ Binding<T> binding = null;
+ if (actualBinding != null) {
+ // TODO(sameb): Consider exposing an option that will allow
+ // ACTUAL to fallback to DEFAULT if ACTUAL's provider returns null.
+ // Right now, an ACTUAL binding can convert from present -> absent
+ // if it's bound to a provider that returns null.
+ binding = actualBinding;
+ } else if (defaultBinding != null) {
+ binding = defaultBinding;
+ }
+
+ if (binding != null) {
+ optional = Optional.of(binding.getProvider());
+ RealOptionalBinder.this.dependencies =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(binding.getKey()));
+ RealOptionalBinder.this.providerDependencies =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(providerOf(binding.getKey())));
+ } else {
+ optional = Optional.absent();
+ RealOptionalBinder.this.dependencies = ImmutableSet.of();
+ RealOptionalBinder.this.providerDependencies = ImmutableSet.of();
}
}
@@ -349,7 +326,7 @@
}
public Set<Dependency<?>> getDependencies() {
- return dependencies;
+ return providerDependencies;
}
});
@@ -368,7 +345,7 @@
OptionalBinderBinding<Optional<T>>,
Provider<Optional<T>> {
RealOptionalKeyProvider() {
- super(mapKey);
+ super(typeKey);
}
public Optional<T> get() {
@@ -416,30 +393,27 @@
}
}
- public boolean containsElement(com.google.inject.spi.Element element) {
- if (mapBinder.containsElement(element)) {
- return true;
+ public boolean containsElement(Element element) {
+ Key<?> elementKey;
+ if (element instanceof Binding) {
+ elementKey = ((Binding<?>) element).getKey();
+ } else if (element instanceof ProviderLookup) {
+ elementKey = ((ProviderLookup<?>) element).getKey();
} else {
- Key<?> elementKey;
- if (element instanceof Binding) {
- elementKey = ((Binding<?>) element).getKey();
- } else if (element instanceof ProviderLookup) {
- elementKey = ((ProviderLookup<?>) element).getKey();
- } else {
- return false; // cannot match;
- }
-
- return elementKey.equals(optionalKey)
- || elementKey.equals(optionalProviderKey)
- || elementKey.equals(optionalJavaxProviderKey)
- || matchesTypeKey(element, elementKey)
- || matchesUserBinding(elementKey);
+ return false; // cannot match;
}
+
+ return elementKey.equals(optionalKey)
+ || elementKey.equals(optionalProviderKey)
+ || elementKey.equals(optionalJavaxProviderKey)
+ || elementKey.equals(defaultKey)
+ || elementKey.equals(actualKey)
+ || matchesTypeKey(element, elementKey);
}
}
/** Returns true if the key & element indicate they were bound by this OptionalBinder. */
- private boolean matchesTypeKey(com.google.inject.spi.Element element, Key<?> elementKey) {
+ private boolean matchesTypeKey(Element element, Key<?> elementKey) {
// Just doing .equals(typeKey) isn't enough, because the user can bind that themselves.
return elementKey.equals(typeKey)
&& element instanceof ProviderInstanceBinding
@@ -447,73 +421,17 @@
.getUserSuppliedProvider() instanceof RealOptionalBinderProviderWithDependencies);
}
- /** Returns true if the key indicates this is a user bound value for the optional binder. */
- private boolean matchesUserBinding(Key<?> elementKey) {
- return elementKey.getAnnotation() instanceof Element
- && ((Element) elementKey.getAnnotation()).setName().equals(RealElement.nameOf(typeKey))
- && ((Element) elementKey.getAnnotation()).type() == Type.OPTIONALBINDER
- && elementKey.getTypeLiteral().equals(typeKey.getTypeLiteral());
- }
-
private boolean isInitialized() {
return binder == null;
}
@Override public boolean equals(Object o) {
return o instanceof RealOptionalBinder
- && ((RealOptionalBinder<?>) o).mapKey.equals(mapKey);
+ && ((RealOptionalBinder<?>) o).typeKey.equals(typeKey);
}
@Override public int hashCode() {
- return mapKey.hashCode();
- }
-
- /** A Provider that bases equality & hashcodes off another key. */
- private static final class ValueProvider<T> implements ProviderWithDependencies<T> {
- private final Provider<T> provider;
- private volatile Key<T> key;
-
- private ValueProvider(Key<T> key, Provider<T> provider) {
- this.key = key;
- this.provider = provider;
- }
-
- public T get() {
- return provider.get();
- }
-
- public Set<Dependency<?>> getDependencies() {
- return ((HasDependencies) provider).getDependencies();
- }
-
- private Key<T> getCurrentKey() {
- // Every time, check if the key needs rehashing.
- // If so, update the field as an optimization for next time.
- Key<T> currentKey = key;
- if (needsRehashing(currentKey)) {
- currentKey = rehash(currentKey);
- key = currentKey;
- }
- return currentKey;
- }
-
- /**
- * Equality is based on the key (which includes the target information, because of how
- * RealElement works). This lets duplicate bindings collapse.
- */
- @Override public boolean equals(Object obj) {
- return obj instanceof ValueProvider
- && getCurrentKey().equals(((ValueProvider) obj).getCurrentKey());
- }
-
- /** We only use the hashcode of the typeliteral, which can't change. */
- @Override public int hashCode() {
- return key.getTypeLiteral().hashCode();
- }
-
- @Override public String toString() {
- return provider.toString();
- }
+ return typeKey.hashCode();
}
/**
@@ -539,4 +457,55 @@
}
}
}
+
+ static class DefaultImpl extends BaseAnnotation implements Default {
+ public DefaultImpl(String value) {
+ super(Default.class, value);
+ }
+ }
+
+ static class ActualImpl extends BaseAnnotation implements Actual {
+ public ActualImpl(String value) {
+ super(Actual.class, value);
+ }
+ }
+
+ abstract static class BaseAnnotation implements Serializable, Annotation {
+
+ private final String value;
+ private final Class<? extends Annotation> clazz;
+
+ BaseAnnotation(Class<? extends Annotation> clazz, String value) {
+ this.clazz = checkNotNull(clazz, "clazz");
+ this.value = checkNotNull(value, "value");
+ }
+
+ public String value() {
+ return this.value;
+ }
+
+ @Override public int hashCode() {
+ // This is specified in java.lang.Annotation.
+ return (127 * "value".hashCode()) ^ value.hashCode();
+ }
+
+ @Override public boolean equals(Object o) {
+ if (!(clazz.isInstance(o))) {
+ return false;
+ }
+
+ BaseAnnotation other = (BaseAnnotation) o;
+ return value.equals(other.value());
+ }
+
+ @Override public String toString() {
+ return "@" + clazz.getName() + (value.isEmpty() ? "" : "(value=" + value + ")");
+ }
+
+ @Override public Class<? extends Annotation> annotationType() {
+ return clazz;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
}
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java b/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
index 246c7a3..2529c18 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/OptionalBinderTest.java
@@ -43,6 +43,8 @@
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.RehashableKeys;
+import com.google.inject.multibindings.OptionalBinder.Actual;
+import com.google.inject.multibindings.OptionalBinder.Default;
import com.google.inject.multibindings.SpiUtils.VisitType;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
@@ -345,11 +347,10 @@
} catch (CreationException ce) {
assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
assertContains(ce.getMessage(),
- "1) OptionalBinder for java.lang.String called with different setDefault values, "
- + "from bindings:",
- "at " + module.getClass().getName() + ".configure(",
- "at " + module.getClass().getName() + ".configure(",
- "at " + MapBinder.RealMapBinder.class.getName());
+ "1) A binding to java.lang.String annotated with @"
+ + Default.class.getName() + " was already configured at "
+ + module.getClass().getName() + ".configure(",
+ "at " + module.getClass().getName() + ".configure(");
}
}
@@ -366,11 +367,10 @@
} catch (CreationException ce) {
assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
assertContains(ce.getMessage(),
- "1) OptionalBinder for java.lang.String called with different setBinding values, "
- + "from bindings:",
- "at " + module.getClass().getName() + ".configure(",
- "at " + module.getClass().getName() + ".configure(",
- "at " + MapBinder.RealMapBinder.class.getName());
+ "1) A binding to java.lang.String annotated with @"
+ + Actual.class.getName() + " was already configured at "
+ + module.getClass().getName() + ".configure(",
+ "at " + module.getClass().getName() + ".configure(");
}
}
@@ -387,17 +387,16 @@
Guice.createInjector(module);
fail();
} catch (CreationException ce) {
- assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
+ assertEquals(ce.getMessage(), 2, ce.getErrorMessages().size());
assertContains(ce.getMessage(),
- "1) OptionalBinder for java.lang.String called with different setDefault values, "
- + "from bindings:",
+ "1) A binding to java.lang.String annotated with @"
+ + Default.class.getName() + " was already configured at "
+ + module.getClass().getName() + ".configure(",
"at " + module.getClass().getName() + ".configure(",
- "at " + module.getClass().getName() + ".configure(",
- "and OptionalBinder for java.lang.String called with different setBinding values, "
- + "from bindings:",
- "at " + module.getClass().getName() + ".configure(",
- "at " + module.getClass().getName() + ".configure(",
- "at " + MapBinder.RealMapBinder.class.getName());
+ "2) A binding to java.lang.String annotated with @"
+ + Actual.class.getName() + " was already configured at "
+ + module.getClass().getName() + ".configure(",
+ "at " + module.getClass().getName() + ".configure(");
}
}
@@ -449,17 +448,27 @@
}
public void testMultipleDifferentOptionals() {
+ final Key<String> bKey = Key.get(String.class, named("b"));
+ final Key<String> cKey = Key.get(String.class, named("c"));
Module module = new AbstractModule() {
@Override protected void configure() {
OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault().toInstance(1);
+
+ OptionalBinder.newOptionalBinder(binder(), bKey).setDefault().toInstance("b");
+ OptionalBinder.newOptionalBinder(binder(), cKey).setDefault().toInstance("c");
}
};
Injector injector = Guice.createInjector(module);
assertEquals("a", injector.getInstance(String.class));
assertEquals(1, injector.getInstance(Integer.class).intValue());
+ assertEquals("b", injector.getInstance(bKey));
+ assertEquals("c", injector.getInstance(cKey));
- assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 1, instance("a"), null);
+ assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 3, instance("a"), null);
+ assertOptionalVisitor(intKey, setOf(module), VisitType.BOTH, 3, instance(1), null);
+ assertOptionalVisitor(bKey, setOf(module), VisitType.BOTH, 3, instance("b"), null);
+ assertOptionalVisitor(cKey, setOf(module), VisitType.BOTH, 3, instance("c"), null);
}
public void testOptionalIsAppropriatelyLazy() {
@@ -604,7 +613,7 @@
}
}
- public void testDependencies() {
+ public void testDependencies_both() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override protected void configure() {
OptionalBinder<String> optionalbinder =
@@ -619,7 +628,40 @@
HasDependencies withDependencies = (HasDependencies) binding;
Set<String> elements = Sets.newHashSet();
elements.addAll(recurseForDependencies(injector, withDependencies));
- assertEquals(ImmutableSet.of("A", "B"), elements);
+ assertEquals(ImmutableSet.of("B"), elements);
+ }
+
+ public void testDependencies_actual() {
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override protected void configure() {
+ OptionalBinder<String> optionalbinder =
+ OptionalBinder.newOptionalBinder(binder(), String.class);
+ optionalbinder.setBinding().to(Key.get(String.class, Names.named("b")));
+ bindConstant().annotatedWith(Names.named("b")).to("B");
+ }
+ });
+
+ Binding<String> binding = injector.getBinding(Key.get(String.class));
+ HasDependencies withDependencies = (HasDependencies) binding;
+ Set<String> elements = Sets.newHashSet();
+ elements.addAll(recurseForDependencies(injector, withDependencies));
+ assertEquals(ImmutableSet.of("B"), elements);
+ }
+
+ public void testDependencies_default() {
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override protected void configure() {
+ OptionalBinder<String> optionalbinder =
+ OptionalBinder.newOptionalBinder(binder(), String.class);
+ optionalbinder.setDefault().toInstance("A");
+ }
+ });
+
+ Binding<String> binding = injector.getBinding(Key.get(String.class));
+ HasDependencies withDependencies = (HasDependencies) binding;
+ Set<String> elements = Sets.newHashSet();
+ elements.addAll(recurseForDependencies(injector, withDependencies));
+ assertEquals(ImmutableSet.of("A"), elements);
}
private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) {
@@ -878,7 +920,6 @@
list.add("C");
Key<?> keyAfter = binding.getKey();
assertSame(keyBefore, keyAfter);
- assertTrue(RehashableKeys.Keys.needsRehashing(keyAfter));
}
@BindingAnnotation
diff --git a/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java b/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
index d121944..9517425 100644
--- a/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
+++ b/extensions/multibindings/test/com/google/inject/multibindings/SpiUtils.java
@@ -16,7 +16,6 @@
package com.google.inject.multibindings;
-import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.inject.multibindings.MapBinder.entryOfProviderOf;
import static com.google.inject.multibindings.MapBinder.mapOf;
import static com.google.inject.multibindings.MapBinder.mapOfJavaxProviderOf;
@@ -54,14 +53,12 @@
import com.google.inject.spi.DefaultBindingTargetVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
-import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.LinkedKeyBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.spi.ProviderLookup;
-import java.lang.reflect.ParameterizedType;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -526,16 +523,11 @@
keyType.ofType(optionalOfJavaxProvider(keyType.getTypeLiteral()));
Key<Optional<Provider<T>>> optionalProviderKey =
keyType.ofType(optionalOfProvider(keyType.getTypeLiteral()));
- Binding<Map<Source, T>> mapBinding = injector.getBinding(
- keyType.ofType(mapOf(TypeLiteral.get(Source.class), keyType.getTypeLiteral())));
- MapBinderBinding<Map<Source, T>> mapbinderBinding = (MapBinderBinding<
- Map<Source, T>>) mapBinding.acceptTargetVisitor(new Visitor<Map<Source, T>>());
boolean keyMatch = false;
boolean optionalKeyMatch = false;
boolean optionalJavaxProviderKeyMatch = false;
boolean optionalProviderKeyMatch = false;
- boolean mapBindingMatch = false;
boolean defaultMatch = false;
boolean actualMatch = false;
List<Object> otherOptionalBindings = Lists.newArrayList();
@@ -566,19 +558,12 @@
} else if (b.getKey().equals(optionalProviderKey)) {
assertTrue(contains);
optionalProviderKeyMatch = true;
- } else if (b.getKey().equals(mapBinding.getKey())) {
- assertTrue(contains);
- mapBindingMatch = true;
- // Validate that this binding is also a MapBinding.
- assertEquals(mapbinderBinding, b.acceptTargetVisitor(visitor));
} else if (expectedDefault != null && matches(b, expectedDefault)) {
assertTrue(contains);
defaultMatch = true;
} else if (expectedActual != null && matches(b, expectedActual)) {
assertTrue(contains);
actualMatch = true;
- } else if (mapbinderBinding.containsElement(b)) {
- assertTrue(contains);
} else if (contains) {
otherMatches.add(b);
}
@@ -590,7 +575,6 @@
assertTrue(optionalKeyMatch);
assertTrue(optionalJavaxProviderKeyMatch);
assertTrue(optionalProviderKeyMatch);
- assertTrue(mapBindingMatch);
assertEquals(expectedDefault != null, defaultMatch);
assertEquals(expectedActual != null, actualMatch);
assertEquals("other OptionalBindings found: " + otherOptionalBindings,
@@ -605,27 +589,22 @@
Map<Key<?>, Binding<?>> indexed = index(elements);
Key<Optional<T>> optionalKey =
keyType.ofType(OptionalBinder.optionalOf(keyType.getTypeLiteral()));
- Key<Map<Source, T>> sourceMapKey =
- keyType.ofType(mapOf(TypeLiteral.get(Source.class), keyType.getTypeLiteral()));
Visitor<Optional<T>> visitor = new Visitor<Optional<T>>();
OptionalBinderBinding<T> optionalBinder = null;
- MapBinderBinding<Map<Source, T>> mapbinderBinding = null;
Key<?> defaultKey = null;
Key<?> actualKey = null;
Binding optionalBinding = indexed.get(optionalKey);
optionalBinder = (OptionalBinderBinding<T>) optionalBinding.acceptTargetVisitor(visitor);
- Binding mapBinding = indexed.get(sourceMapKey);
- mapbinderBinding = (MapBinderBinding<Map<Source, T>>) mapBinding.acceptTargetVisitor(visitor);
// Locate the defaultKey & actualKey
for (Element element : elements) {
if (optionalBinder.containsElement(element) && element instanceof Binding) {
Binding binding = (Binding) element;
if (isSourceEntry(binding, Source.DEFAULT)) {
- defaultKey = keyFromOptionalSourceBinding(binding, indexed);
+ defaultKey = binding.getKey();
} else if (isSourceEntry(binding, Source.ACTUAL)) {
- actualKey = keyFromOptionalSourceBinding(binding, indexed);
+ actualKey = binding.getKey();
}
}
}
@@ -641,7 +620,6 @@
boolean optionalKeyMatch = false;
boolean optionalJavaxProviderKeyMatch = false;
boolean optionalProviderKeyMatch = false;
- boolean mapBindingMatch = false;
boolean defaultMatch = false;
boolean actualMatch = false;
List<Object> otherOptionalElements = Lists.newArrayList();
@@ -685,11 +663,6 @@
} else if (key != null && key.equals(optionalProviderKey)) {
assertTrue(contains);
optionalProviderKeyMatch = true;
- } else if (key != null && key.equals(sourceMapKey)) {
- assertTrue(contains);
- mapBindingMatch = true;
- // Validate that this binding is also a MapBinding.
- assertEquals(mapbinderBinding, b.acceptTargetVisitor(visitor));
} else if (key != null && key.equals(defaultKey)) {
assertTrue(contains);
if (b != null) { // otherwise it might just be a ProviderLookup into it
@@ -703,8 +676,6 @@
assertTrue("expected: " + expectedActual + ", but was: " + b, matches(b, expectedActual));
actualMatch = true;
}
- } else if (mapbinderBinding.containsElement(element)) {
- assertTrue(contains);
} else if (contains) {
otherContains.add(element);
}
@@ -715,7 +686,6 @@
assertTrue(optionalKeyMatch);
assertTrue(optionalJavaxProviderKeyMatch);
assertTrue(optionalProviderKeyMatch);
- assertTrue(mapBindingMatch);
assertEquals(expectedDefault != null, defaultMatch);
assertEquals(expectedActual != null, actualMatch);
assertEquals(otherContains.toString(), 0, otherContains.size());
@@ -725,40 +695,16 @@
// Validate that we can construct an injector out of the remaining bindings.
Guice.createInjector(Elements.getModule(nonContainedElements));
}
-
- private static Key<?> keyFromOptionalSourceBinding(Binding<?> binding,
- Map<Key<?>, Binding<?>> elements) {
- // Flow is:
- // binding == ProviderInstanceBinding<Map.Entry<Source, Provider<String>>
- // dependency on: Provider<String> that maps to ProviderInstanceBinding<String> in MapBinder
- // dependency on: Provider<String> of user set value.
- Key<?> mapKey =
- genericOf(getOnlyElement(((HasDependencies) binding).getDependencies()).getKey());
- Binding<?> mapBinding = elements.get(mapKey);
- Key<?> userKey =
- genericOf(getOnlyElement(((HasDependencies) mapBinding).getDependencies()).getKey());
- return userKey;
- }
-
- /** Returns {@code Key<T>} for something like {@code Key<Provider<T>>} */
- private static Key<?> genericOf(Key<?> key) {
- ParameterizedType type = (ParameterizedType) key.getTypeLiteral().getType();
- assertEquals(1, type.getActualTypeArguments().length);
- Key<?> result = key.ofType(type.getActualTypeArguments()[0]);
- return result;
- }
private static boolean isSourceEntry(Binding b, Source type) {
- if (b instanceof ProviderInstanceBinding && b.getKey().getAnnotation() instanceof RealElement) {
- javax.inject.Provider provider = ((ProviderInstanceBinding) b).getUserSuppliedProvider();
- if (provider instanceof Map.Entry) {
- Map.Entry entry = (Map.Entry) provider;
- if (entry.getKey() == type) {
- return true;
- }
- }
+ switch(type) {
+ case ACTUAL:
+ return b.getKey().getAnnotation() instanceof OptionalBinder.Actual;
+ case DEFAULT:
+ return b.getKey().getAnnotation() instanceof OptionalBinder.Default;
+ default:
+ throw new IllegalStateException("invalid type: " + type);
}
- return false;
}
/** Returns the subset of elements that have keys, indexed by them. */