Automated rollback of commit 1a5123d0
*** Original change description ***
Inline requests for map bindings
Under the hood, remove ContributionBinding.Kind.SYNTHETIC_MAP. Map<K,V> and Map<K, Produced<V>> bindings now act just like Map<K, FrameworkType<V>>, and have dependencies on their contributions directly instead of wrapping a another FrameworkType<Map<K, FrameworkType<V>>>
***
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=166785831
diff --git a/java/dagger/internal/MapBuilder.java b/java/dagger/internal/MapBuilder.java
deleted file mode 100644
index 1560491..0000000
--- a/java/dagger/internal/MapBuilder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * 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 dagger.internal;
-
-import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * A fluent builder class that returns a {@link Map}. Used in component implementations where a map
- * must be created in one fluent statement for inlined request fulfillments.
- */
-public final class MapBuilder<K, V> {
- private final Map<K, V> contributions;
-
- private MapBuilder(int size) {
- contributions = newLinkedHashMapWithExpectedSize(size);
- }
-
- /**
- * Creates a new {@link MapBuilder} with {@code size} elements.
- */
- public static <K, V> MapBuilder<K, V> newMapBuilder(int size) {
- return new MapBuilder<>(size);
- }
-
- public MapBuilder<K, V> put(K key, V value) {
- contributions.put(key, value);
- return this;
- }
-
- public Map<K, V> build() {
- switch (contributions.size()) {
- case 0:
- return Collections.emptyMap();
- default:
- return Collections.unmodifiableMap(contributions);
- }
- }
-}
diff --git a/java/dagger/internal/MapFactory.java b/java/dagger/internal/MapFactory.java
index b6f925a..d4b9189 100644
--- a/java/dagger/internal/MapFactory.java
+++ b/java/dagger/internal/MapFactory.java
@@ -17,11 +17,8 @@
package dagger.internal;
import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-import static dagger.internal.Preconditions.checkNotNull;
import static java.util.Collections.unmodifiableMap;
-import java.util.Collections;
-import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.inject.Provider;
@@ -35,31 +32,21 @@
*
*/
public final class MapFactory<K, V> implements Factory<Map<K, V>> {
- private static final Provider<Map<Object, Object>> EMPTY =
- InstanceFactory.create(Collections.emptyMap());
-
private final Map<K, Provider<V>> contributingMap;
- /**
- * Returns a new {@link Builder}
- */
- public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
- }
-
- /**
- * Returns a factory of an empty map.
- */
- @SuppressWarnings("unchecked") // safe contravariant cast
- public static <K, V> Provider<Map<K, V>> emptyMapProvider() {
- return (Provider<Map<K, V>>) (Provider) EMPTY;
- }
-
private MapFactory(Map<K, Provider<V>> map) {
this.contributingMap = unmodifiableMap(map);
}
/**
+ * Returns a new MapFactory.
+ */
+ public static <K, V> MapFactory<K, V> create(Provider<Map<K, Provider<V>>> mapProviderFactory) {
+ Map<K, Provider<V>> map = mapProviderFactory.get();
+ return new MapFactory<K, V>(map);
+ }
+
+ /**
* Returns a {@code Map<K, V>} whose iteration order is that of the elements
* given by each of the providers, which are invoked in the order given at creation.
*/
@@ -71,25 +58,4 @@
}
return unmodifiableMap(result);
}
-
- // TODO(ronshapiro): can we merge the builders? Or maybe just use a (Immutable)MapBuilder?
- /** A builder for {@link MapFactory}. */
- public static final class Builder<K, V> {
- private final LinkedHashMap<K, Provider<V>> map;
-
- private Builder(int size) {
- this.map = newLinkedHashMapWithExpectedSize(size);
- }
-
- /** Associates {@code key} with {@code providerOfValue}. */
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- map.put(checkNotNull(key, "key"), checkNotNull(providerOfValue, "provider"));
- return this;
- }
-
- /** Returns a new {@link MapProviderFactory}. */
- public MapFactory<K, V> build() {
- return new MapFactory<>(map);
- }
- }
}
diff --git a/java/dagger/internal/MapProviderFactory.java b/java/dagger/internal/MapProviderFactory.java
index 2458a3c..c27beb2 100644
--- a/java/dagger/internal/MapProviderFactory.java
+++ b/java/dagger/internal/MapProviderFactory.java
@@ -17,10 +17,10 @@
package dagger.internal;
import static dagger.internal.DaggerCollections.newLinkedHashMapWithExpectedSize;
-import static dagger.internal.Preconditions.checkNotNull;
import static java.util.Collections.unmodifiableMap;
import dagger.Lazy;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.inject.Provider;
@@ -34,13 +34,24 @@
*/
public final class MapProviderFactory<K, V>
implements Factory<Map<K, Provider<V>>>, Lazy<Map<K, Provider<V>>> {
+ private static final MapProviderFactory<Object, Object> EMPTY =
+ new MapProviderFactory<Object, Object>(Collections.<Object, Provider<Object>>emptyMap());
+
private final Map<K, Provider<V>> contributingMap;
/**
* Returns a new {@link Builder}
*/
public static <K, V> Builder<K, V> builder(int size) {
- return new Builder<>(size);
+ return new Builder<K, V>(size);
+ }
+
+ /**
+ * Returns a factory of an empty map.
+ */
+ @SuppressWarnings("unchecked") // safe contravariant cast
+ public static <K, V> MapProviderFactory<K, V> empty() {
+ return (MapProviderFactory<K, V>) EMPTY;
}
private MapProviderFactory(Map<K, Provider<V>> contributingMap) {
@@ -57,23 +68,37 @@
return this.contributingMap;
}
- /** A builder for {@link MapProviderFactory}. */
+ /**
+ * A builder to help build the {@link MapProviderFactory}
+ */
public static final class Builder<K, V> {
- private final LinkedHashMap<K, Provider<V>> map;
+ private final LinkedHashMap<K, Provider<V>> mapBuilder;
private Builder(int size) {
- this.map = newLinkedHashMapWithExpectedSize(size);
+ // TODO(user): consider which way to initialize mapBuilder is better
+ this.mapBuilder = newLinkedHashMapWithExpectedSize(size);
}
- /** Associates {@code key} with {@code providerOfValue}. */
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- map.put(checkNotNull(key, "key"), checkNotNull(providerOfValue, "provider"));
- return this;
- }
-
- /** Returns a new {@link MapProviderFactory}. */
+ /**
+ * Returns a new {@link MapProviderFactory}
+ */
public MapProviderFactory<K, V> build() {
- return new MapProviderFactory<>(map);
+ return new MapProviderFactory<K, V>(this.mapBuilder);
+ }
+
+ /**
+ * Associate k with providerOfValue in {@code Builder}
+ */
+ public Builder<K, V> put(K key, Provider<V> providerOfValue) {
+ if (key == null) {
+ throw new NullPointerException("The key is null");
+ }
+ if (providerOfValue == null) {
+ throw new NullPointerException("The provider of the value is null");
+ }
+
+ this.mapBuilder.put(key, providerOfValue);
+ return this;
}
}
}
diff --git a/java/dagger/internal/codegen/BindingExpression.java b/java/dagger/internal/codegen/BindingExpression.java
index 06c8e64..093e5c5 100644
--- a/java/dagger/internal/codegen/BindingExpression.java
+++ b/java/dagger/internal/codegen/BindingExpression.java
@@ -198,9 +198,6 @@
case SYNTHETIC_MULTIBOUND_SET:
return new SetBindingExpression(
provisionBinding, graph, componentBindingExpressions, bindingExpression, elements);
- case SYNTHETIC_MULTIBOUND_MAP:
- return new MapBindingExpression(
- provisionBinding, graph, componentBindingExpressions, bindingExpression, elements);
case SYNTHETIC_OPTIONAL_BINDING:
return new OptionalBindingExpression(
provisionBinding, bindingExpression, componentBindingExpressions);
diff --git a/java/dagger/internal/codegen/BindingGraph.java b/java/dagger/internal/codegen/BindingGraph.java
index 14b9c7d..110d08e 100644
--- a/java/dagger/internal/codegen/BindingGraph.java
+++ b/java/dagger/internal/codegen/BindingGraph.java
@@ -35,6 +35,7 @@
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.base.VerifyException;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -518,6 +519,7 @@
ImmutableSet.Builder<Optional<ContributionBinding>> maybeContributionBindings =
ImmutableSet.builder();
+ maybeContributionBindings.add(syntheticMapOfValuesBinding(requestKey));
maybeContributionBindings.add(
syntheticMultibinding(
requestKey, multibindingContributions, multibindingDeclarations));
@@ -583,17 +585,71 @@
owningResolver.componentDescriptor.subcomponentsByBuilderType().get(builderType));
}
- private ImmutableSet<Key> keysMatchingRequest(Key requestKey) {
+ private Iterable<Key> keysMatchingRequest(Key requestKey) {
ImmutableSet.Builder<Key> keys = ImmutableSet.builder();
keys.add(requestKey);
keyFactory.unwrapSetKey(requestKey, Produced.class).ifPresent(keys::add);
keyFactory.rewrapMapKey(requestKey, Producer.class, Provider.class).ifPresent(keys::add);
keyFactory.rewrapMapKey(requestKey, Provider.class, Producer.class).ifPresent(keys::add);
- keys.addAll(keyFactory.implicitFrameworkMapKeys(requestKey));
return keys.build();
}
/**
+ * If {@code key} is a {@code Map<K, V>} or {@code Map<K, Produced<V>>}, and there are any
+ * multibinding contributions or declarations that apply to that map, returns a synthetic
+ * binding for the {@code key} that depends on an {@linkplain #syntheticMultibinding(Key,
+ * Iterable, Iterable) underlying synthetic multibinding}.
+ *
+ * <p>The returned binding has the same {@link BindingType} as the underlying synthetic
+ * multibinding.
+ */
+ private Optional<ContributionBinding> syntheticMapOfValuesBinding(final Key key) {
+ return syntheticMultibinding(
+ key,
+ multibindingContributionsForValueMap(key),
+ multibindingDeclarationsForValueMap(key))
+ .map(
+ syntheticMultibinding -> {
+ switch (syntheticMultibinding.bindingType()) {
+ case PROVISION:
+ return provisionBindingFactory.syntheticMapOfValuesBinding(key);
+
+ case PRODUCTION:
+ return productionBindingFactory.syntheticMapOfValuesOrProducedBinding(key);
+
+ default:
+ throw new VerifyException(syntheticMultibinding.toString());
+ }
+ });
+ }
+
+ /**
+ * If {@code key} is for {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns all
+ * multibinding contributions whose key is for {@code Map<K, Provider<V>>} or {@code Map<K,
+ * Producer<V>>} with the same qualifier and {@code K} and {@code V}.
+ */
+ private ImmutableSet<ContributionBinding> multibindingContributionsForValueMap(Key key) {
+ return keyFactory
+ .implicitFrameworkMapKeys(key)
+ .stream()
+ .flatMap(mapKey -> getExplicitMultibindings(mapKey).stream())
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * If {@code key} is for {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns all
+ * multibinding declarations whose key is for {@code Map<K, Provider<V>>} or {@code Map<K,
+ * Producer<V>>} with the same qualifier and {@code K} and {@code V}.
+ */
+ private ImmutableSet<MultibindingDeclaration> multibindingDeclarationsForValueMap(Key key) {
+ return keyFactory
+ .implicitFrameworkMapKeys(key)
+ .stream()
+ .flatMap(mapKey -> getMultibindingDeclarations(mapKey).stream())
+ .collect(toImmutableSet());
+ }
+
+ /**
* Returns a synthetic binding that depends on individual multibinding contributions.
*
* <p>If there are no {@code multibindingContributions} or {@code multibindingDeclarations},
@@ -1109,9 +1165,7 @@
.stream()
.map(ContributionBinding::bindingKind)
.anyMatch(SYNTHETIC_MULTIBOUND_KINDS::contains)
- && keysMatchingRequest(resolvedBindings.key())
- .stream()
- .anyMatch(key -> !getLocalExplicitMultibindings(key).isEmpty());
+ && !getLocalExplicitMultibindings(resolvedBindings.key()).isEmpty();
}
/**
diff --git a/java/dagger/internal/codegen/BindingGraphValidator.java b/java/dagger/internal/codegen/BindingGraphValidator.java
index 32143d0..1bbcbdc 100644
--- a/java/dagger/internal/codegen/BindingGraphValidator.java
+++ b/java/dagger/internal/codegen/BindingGraphValidator.java
@@ -30,6 +30,7 @@
import static dagger.internal.codegen.ConfigurationAnnotations.getComponentAnnotation;
import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
+import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MAP;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_KINDS;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
import static dagger.internal.codegen.ContributionBinding.indexMapBindingsByAnnotationType;
@@ -993,7 +994,8 @@
.stream()
.map(ContributionBinding::bindingKind)
// TODO(dpb): Kill with fire.
- .anyMatch(SYNTHETIC_MULTIBOUND_KINDS::contains)) {
+ .anyMatch(
+ kind -> SYNTHETIC_MULTIBOUND_KINDS.contains(kind) || SYNTHETIC_MAP.equals(kind))) {
reportMultipleContributionTypes();
return;
}
diff --git a/java/dagger/internal/codegen/ContributionBinding.java b/java/dagger/internal/codegen/ContributionBinding.java
index 6706757..8891e67 100644
--- a/java/dagger/internal/codegen/ContributionBinding.java
+++ b/java/dagger/internal/codegen/ContributionBinding.java
@@ -73,6 +73,12 @@
*/
enum Kind {
/**
+ * The synthetic binding for {@code Map<K, V>} that depends on either
+ * {@code Map<K, Provider<V>>} or {@code Map<K, Producer<V>>}.
+ */
+ SYNTHETIC_MAP,
+
+ /**
* A synthetic binding for a multibound set that depends on the individual multibinding
* {@link Provides @Provides} or {@link Produces @Produces} methods.
*/
diff --git a/java/dagger/internal/codegen/DependencyRequest.java b/java/dagger/internal/codegen/DependencyRequest.java
index 5a4b4b6..bbd899a 100644
--- a/java/dagger/internal/codegen/DependencyRequest.java
+++ b/java/dagger/internal/codegen/DependencyRequest.java
@@ -344,26 +344,43 @@
* Creates a synthetic dependency request for one individual {@code multibindingContribution}.
*/
private DependencyRequest forMultibindingContribution(
- ContributionBinding multibindingContribution, Kind requestKind) {
+ ContributionBinding multibindingContribution) {
checkArgument(
multibindingContribution.key().multibindingContributionIdentifier().isPresent(),
"multibindingContribution's key must have a multibinding contribution identifier: %s",
multibindingContribution);
return DependencyRequest.builder()
- .kind(requestKind)
+ .kind(multibindingContributionRequestKind(multibindingContribution))
.key(multibindingContribution.key())
.build();
}
+ private Kind multibindingContributionRequestKind(ContributionBinding multibindingContribution) {
+ switch (multibindingContribution.contributionType()) {
+ case MAP:
+ return multibindingContribution.bindingType().equals(BindingType.PRODUCTION)
+ ? Kind.PRODUCER
+ : Kind.PROVIDER;
+ case SET:
+ case SET_VALUES:
+ return Kind.INSTANCE;
+ case UNIQUE:
+ throw new IllegalArgumentException(
+ "multibindingContribution must be a multibinding: " + multibindingContribution);
+ default:
+ throw new AssertionError(multibindingContribution.toString());
+ }
+ }
+
/**
* Creates synthetic dependency requests for each individual multibinding contribution in {@code
* multibindingContributions}.
*/
ImmutableSet<DependencyRequest> forMultibindingContributions(
- Iterable<ContributionBinding> multibindingContributions, Kind requestKind) {
+ Iterable<ContributionBinding> multibindingContributions) {
ImmutableSet.Builder<DependencyRequest> requests = ImmutableSet.builder();
for (ContributionBinding multibindingContribution : multibindingContributions) {
- requests.add(forMultibindingContribution(multibindingContribution, requestKind));
+ requests.add(forMultibindingContribution(multibindingContribution));
}
return requests.build();
}
diff --git a/java/dagger/internal/codegen/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
index 0b22230..a8b5b16 100644
--- a/java/dagger/internal/codegen/FrameworkFieldInitializer.java
+++ b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
@@ -29,6 +29,7 @@
import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
import static dagger.internal.codegen.MoreAnnotationMirrors.getTypeValue;
+import static dagger.internal.codegen.SourceFiles.frameworkMapFactoryClassName;
import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.SourceFiles.mapFactoryClassName;
import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
@@ -47,7 +48,6 @@
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -328,6 +328,14 @@
makeParametersCodeBlock(arguments));
}
+ case SYNTHETIC_MAP:
+ FrameworkDependency frameworkDependency = getOnlyElement(binding.frameworkDependencies());
+ return CodeBlock.of(
+ "$T.create($L)",
+ mapFactoryClassName(binding),
+ componentBindingExpressions.getDependencyExpression(
+ frameworkDependency, componentName));
+
case SYNTHETIC_MULTIBOUND_SET:
return factoryForSetMultibindingInitialization(binding);
@@ -402,27 +410,16 @@
ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
MapType mapType = MapType.from(binding.key().type());
- CodeBlock.Builder builderCall = CodeBlock.builder().add("$T.", mapFactoryClassName(binding));
+ CodeBlock.Builder builderCall =
+ CodeBlock.builder().add("$T.", frameworkMapFactoryClassName(binding.bindingType()));
boolean useRawTypes = useRawType();
if (!useRawTypes) {
- // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
- // mapType.unwrappedValueType() method that doesn't require a framework type
- TypeMirror valueType = mapType.valueType();
- for (Class<?> frameworkClass :
- ImmutableSet.of(Provider.class, Producer.class, Produced.class)) {
- if (mapType.valuesAreTypeOf(frameworkClass)) {
- valueType = mapType.unwrappedValueType(frameworkClass);
- break;
- }
- }
- builderCall.add("<$T, $T>", mapType.keyType(), valueType);
+ builderCall.add(
+ "<$T, $T>",
+ mapType.keyType(),
+ mapType.unwrappedValueType(binding.bindingType().frameworkClass()));
}
-
- if (binding.bindingType().equals(BindingType.PROVISION)) {
- builderCall.add("builder($L)", frameworkDependencies.size());
- } else {
- builderCall.add("builder()");
- }
+ builderCall.add("builder($L)", frameworkDependencies.size());
codeBlocks.add(builderCall.build());
for (FrameworkDependency frameworkDependency : frameworkDependencies) {
diff --git a/java/dagger/internal/codegen/Key.java b/java/dagger/internal/codegen/Key.java
index 4871e4b..3c4cecc 100644
--- a/java/dagger/internal/codegen/Key.java
+++ b/java/dagger/internal/codegen/Key.java
@@ -546,15 +546,12 @@
}
/**
- * Optionally extract a {@link Key} for the underlying provision binding(s) if such a valid key
- * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code
- * <K, V>} or {@code Map<K, Producer<V>>}, a key of {@code Map<K, Provider<V>>} will be
- * returned.
+ * Optionally extract a {@link Key} for the underlying provision binding(s) if such a
+ * valid key can be inferred from the given key. Specifically, if the key represents a
+ * {@link Map}{@code <K, V>}, a key of {@code Map<K, Provider<V>>} will be returned.
*/
Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
- return firstPresent(
- rewrapMapKey(possibleMapKey, Produced.class, Provider.class),
- wrapMapKey(possibleMapKey, Provider.class));
+ return wrapMapKey(possibleMapKey, Provider.class);
}
/**
diff --git a/java/dagger/internal/codegen/MapBindingExpression.java b/java/dagger/internal/codegen/MapBindingExpression.java
deleted file mode 100644
index 8e5746c..0000000
--- a/java/dagger/internal/codegen/MapBindingExpression.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * 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 dagger.internal.codegen;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
-import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.MapBuilder;
-import java.util.Collections;
-import java.util.Map;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
-
-/** A {@link BindingExpression} for multibound maps. */
-final class MapBindingExpression extends SimpleInvocationBindingExpression {
- /** Maximum number of key-value pairs that can be passed to ImmutableMap.of(K, V, K, V, ...). */
- private static final int MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS = 5;
-
- private final ProvisionBinding binding;
- private final ImmutableMap<DependencyRequest, ContributionBinding> dependencies;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final Elements elements;
-
- MapBindingExpression(
- ProvisionBinding binding,
- BindingGraph graph,
- ComponentBindingExpressions componentBindingExpressions,
- BindingExpression delegate,
- Elements elements) {
- super(delegate);
- ContributionBinding.Kind bindingKind = binding.bindingKind();
- checkArgument(bindingKind.equals(SYNTHETIC_MULTIBOUND_MAP), bindingKind);
- this.binding = binding;
- this.componentBindingExpressions = componentBindingExpressions;
- this.elements = elements;
- this.dependencies =
- Maps.toMap(
- binding.dependencies(),
- dep -> graph.resolvedBindings().get(dep.bindingKey()).contributionBinding());
- }
-
- @Override
- CodeBlock getInstanceDependencyExpression(
- DependencyRequest.Kind requestKind, ClassName requestingClass) {
- // TODO(ronshapiro): We should also make an ImmutableMap version of MapFactory
- boolean isImmutableMapAvailable = isImmutableMapAvailable();
- // TODO(ronshapiro, gak): Use Maps.immutableEnumMap() if it's available?
- if (isImmutableMapAvailable && dependencies.size() <= MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS) {
- return CodeBlock.builder()
- .add("$T.", ImmutableMap.class)
- .add(maybeTypeParameters(requestingClass))
- .add(
- "of($L)",
- dependencies
- .keySet()
- .stream()
- .map(dependency -> keyAndValueExpression(dependency, requestingClass))
- .collect(toParametersCodeBlock()))
- .build();
- }
- switch (dependencies.size()) {
- case 0:
- return collectionsStaticFactoryInvocation(requestingClass, CodeBlock.of("emptyMap()"));
- case 1:
- return collectionsStaticFactoryInvocation(
- requestingClass,
- CodeBlock.of(
- "singletonMap($L)",
- keyAndValueExpression(getOnlyElement(dependencies.keySet()), requestingClass)));
- default:
- CodeBlock.Builder instantiation = CodeBlock.builder();
- instantiation
- .add("$T.", isImmutableMapAvailable ? ImmutableMap.class : MapBuilder.class)
- .add(maybeTypeParameters(requestingClass));
- if (isImmutableMapAvailable) {
- // TODO(ronshapiro): builderWithExpectedSize
- instantiation.add("builder()");
- } else {
- instantiation.add("newMapBuilder($L)", dependencies.size());
- }
- for (DependencyRequest dependency : dependencies.keySet()) {
- instantiation.add(".put($L)", keyAndValueExpression(dependency, requestingClass));
- }
- return instantiation.add(".build()").build();
- }
- }
-
- private CodeBlock keyAndValueExpression(DependencyRequest dependency, ClassName requestingClass) {
- return CodeBlock.of(
- "$L, $L",
- getMapKeyExpression(dependencies.get(dependency).mapKey().get()),
- componentBindingExpressions.getDependencyExpression(dependency, requestingClass));
- }
-
- private CodeBlock collectionsStaticFactoryInvocation(
- ClassName requestingClass, CodeBlock methodInvocation) {
- return CodeBlock.builder()
- .add("$T.", Collections.class)
- .add(maybeTypeParameters(requestingClass))
- .add(methodInvocation)
- .build();
- }
-
- private CodeBlock maybeTypeParameters(ClassName requestingClass) {
- TypeMirror bindingKeyType = binding.key().type();
- MapType mapType = MapType.from(binding.key());
- return isTypeAccessibleFrom(bindingKeyType, requestingClass.packageName())
- ? CodeBlock.of("<$T, $T>", mapType.keyType(), mapType.valueType())
- : CodeBlock.of("");
- }
-
- private boolean isImmutableMapAvailable() {
- return elements.getTypeElement(ImmutableMap.class.getCanonicalName()) != null;
- }
-
- @Override
- protected CodeBlock explicitTypeParameter(ClassName requestingClass) {
- if (isImmutableMapAvailable()) {
- TypeMirror keyType = binding.key().type();
- return CodeBlock.of(
- "<$T>",
- isTypeAccessibleFrom(keyType, requestingClass.packageName()) ? keyType : Map.class);
- }
- return CodeBlock.of("");
- }
-}
diff --git a/java/dagger/internal/codegen/MemberSelect.java b/java/dagger/internal/codegen/MemberSelect.java
index fc0217a..5466292 100644
--- a/java/dagger/internal/codegen/MemberSelect.java
+++ b/java/dagger/internal/codegen/MemberSelect.java
@@ -20,19 +20,17 @@
import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
import static dagger.internal.codegen.CodeBlocks.toTypeNamesCodeBlock;
import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
+import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
+import static dagger.internal.codegen.ContributionBinding.Kind.PROVISION;
import static dagger.internal.codegen.SourceFiles.bindingTypeElementTypeVariableNames;
+import static dagger.internal.codegen.SourceFiles.frameworkMapFactoryClassName;
import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.SourceFiles.setFactoryClassName;
import static dagger.internal.codegen.TypeNames.FACTORY;
-import static dagger.internal.codegen.TypeNames.MAP_FACTORY;
import static dagger.internal.codegen.TypeNames.MEMBERS_INJECTOR;
import static dagger.internal.codegen.TypeNames.MEMBERS_INJECTORS;
-import static dagger.internal.codegen.TypeNames.PRODUCER;
-import static dagger.internal.codegen.TypeNames.PRODUCERS;
-import static dagger.internal.codegen.TypeNames.PROVIDER;
import static javax.lang.model.type.TypeKind.DECLARED;
-import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -90,7 +88,7 @@
&& !contributionBinding.scope().isPresent()) {
switch (contributionBinding.bindingKind()) {
case SYNTHETIC_MULTIBOUND_MAP:
- return Optional.of(emptyMapFactory(contributionBinding));
+ return Optional.of(emptyFrameworkMapFactory(contributionBinding));
case SYNTHETIC_MULTIBOUND_SET:
return Optional.of(emptySetFactory(contributionBinding));
@@ -168,19 +166,20 @@
MEMBERS_INJECTOR);
}
- /** A {@link MemberSelect} for a factory of an empty map. */
- private static MemberSelect emptyMapFactory(ContributionBinding contributionBinding) {
+ /**
+ * A {@link MemberSelect} for a factory of an empty map of factory types, where a factory can be
+ * either a {@link javax.inject.Provider} or {@link dagger.producers.Producer}.
+ */
+ private static MemberSelect emptyFrameworkMapFactory(ContributionBinding contributionBinding) {
BindingType bindingType = contributionBinding.bindingType();
- ImmutableList<TypeMirror> typeParameters =
- ImmutableList.copyOf(
- MoreTypes.asDeclared(contributionBinding.key().type()).getTypeArguments());
- if (bindingType.equals(BindingType.PRODUCTION)) {
- return new ParameterizedStaticMethod(
- PRODUCERS, typeParameters, CodeBlock.of("emptyMapProducer()"), PRODUCER);
- } else {
- return new ParameterizedStaticMethod(
- MAP_FACTORY, typeParameters, CodeBlock.of("emptyMapProvider()"), PROVIDER);
- }
+ MapType mapType = MapType.from(contributionBinding.key());
+
+ return new ParameterizedStaticMethod(
+ frameworkMapFactoryClassName(bindingType),
+ ImmutableList.of(
+ mapType.keyType(), mapType.unwrappedValueType(bindingType.frameworkClass())),
+ CodeBlock.of("empty()"),
+ ClassName.get(bindingType.frameworkClass()));
}
/**
diff --git a/java/dagger/internal/codegen/ProductionBinding.java b/java/dagger/internal/codegen/ProductionBinding.java
index 91eb94d..4a71dea 100644
--- a/java/dagger/internal/codegen/ProductionBinding.java
+++ b/java/dagger/internal/codegen/ProductionBinding.java
@@ -18,7 +18,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.DependencyRequest.Kind.PRODUCER;
import static dagger.internal.codegen.MapKeys.getMapKey;
import static dagger.internal.codegen.MoreAnnotationMirrors.wrapOptionalInEquivalence;
import static dagger.internal.codegen.Util.toImmutableSet;
@@ -180,6 +179,28 @@
}
/**
+ * A synthetic binding of {@code Map<K, V>} or {@code Map<K, Produced<V>>} that depends on
+ * {@code Map<K, Producer<V>>}.
+ */
+ ProductionBinding syntheticMapOfValuesOrProducedBinding(Key mapOfValuesOrProducedKey) {
+ checkNotNull(mapOfValuesOrProducedKey);
+ Optional<Key> mapOfProducersKey =
+ keyFactory.implicitMapProducerKeyFrom(mapOfValuesOrProducedKey);
+ checkArgument(
+ mapOfProducersKey.isPresent(),
+ "%s is not a key for of Map<K, V> or Map<K, Produced<V>>",
+ mapOfValuesOrProducedKey);
+ DependencyRequest requestForMapOfProducers =
+ dependencyRequestFactory.producerForImplicitMapBinding(mapOfProducersKey.get());
+ return ProductionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .key(mapOfValuesOrProducedKey)
+ .explicitDependencies(requestForMapOfProducers)
+ .bindingKind(Kind.SYNTHETIC_MAP)
+ .build();
+ }
+
+ /**
* A synthetic binding that depends explicitly on a set of individual provision or production
* multibinding contribution methods.
*
@@ -191,8 +212,7 @@
.contributionType(ContributionType.UNIQUE)
.key(key)
.explicitDependencies(
- dependencyRequestFactory.forMultibindingContributions(
- multibindingContributions, PRODUCER))
+ dependencyRequestFactory.forMultibindingContributions(multibindingContributions))
.bindingKind(Kind.forMultibindingKey(key))
.build();
}
diff --git a/java/dagger/internal/codegen/ProvisionBinding.java b/java/dagger/internal/codegen/ProvisionBinding.java
index 6774255..6d40e97 100644
--- a/java/dagger/internal/codegen/ProvisionBinding.java
+++ b/java/dagger/internal/codegen/ProvisionBinding.java
@@ -235,6 +235,21 @@
.build();
}
+ /** A synthetic binding of {@code Map<K, V>} that depends on {@code Map<K, Provider<V>>}. */
+ ProvisionBinding syntheticMapOfValuesBinding(Key mapOfValuesKey) {
+ checkNotNull(mapOfValuesKey);
+ Optional<Key> mapOfProvidersKey = keyFactory.implicitMapProviderKeyFrom(mapOfValuesKey);
+ checkArgument(mapOfProvidersKey.isPresent(), "%s is not a key for Map<K, V>", mapOfValuesKey);
+ DependencyRequest requestForMapOfProviders =
+ dependencyRequestFactory.providerForImplicitMapBinding(mapOfProvidersKey.get());
+ return ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .key(mapOfValuesKey)
+ .provisionDependencies(requestForMapOfProviders)
+ .bindingKind(Kind.SYNTHETIC_MAP)
+ .build();
+ }
+
/**
* A synthetic binding that depends explicitly on a set of individual provision multibinding
* contribution methods.
@@ -243,16 +258,11 @@
*/
ProvisionBinding syntheticMultibinding(
Key key, Iterable<ContributionBinding> multibindingContributions) {
- DependencyRequest.Kind dependencyKind =
- MapType.isMap(key) && MapType.from(key).valuesAreTypeOf(Provider.class)
- ? DependencyRequest.Kind.PROVIDER
- : DependencyRequest.Kind.INSTANCE;
return ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
.key(key)
.provisionDependencies(
- dependencyRequestFactory.forMultibindingContributions(
- multibindingContributions, dependencyKind))
+ dependencyRequestFactory.forMultibindingContributions(multibindingContributions))
.bindingKind(Kind.forMultibindingKey(key))
.build();
}
diff --git a/java/dagger/internal/codegen/SourceFiles.java b/java/dagger/internal/codegen/SourceFiles.java
index 858f184..ded5f6f 100644
--- a/java/dagger/internal/codegen/SourceFiles.java
+++ b/java/dagger/internal/codegen/SourceFiles.java
@@ -19,10 +19,8 @@
import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
import static dagger.internal.codegen.ContributionBinding.Kind.INJECTION;
-import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_MAP;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_MULTIBOUND_SET;
import static dagger.internal.codegen.Optionals.optionalComparator;
import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
@@ -53,15 +51,17 @@
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.MapFactory;
+import dagger.internal.MapProviderFactory;
import dagger.internal.SetFactory;
import dagger.producers.Produced;
-import dagger.producers.Producer;
+import dagger.producers.internal.MapOfProducerProducer;
+import dagger.producers.internal.MapProducer;
import dagger.producers.internal.SetOfProducedProducer;
import dagger.producers.internal.SetProducer;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
-import javax.inject.Provider;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
@@ -264,24 +264,41 @@
}
}
- /** The {@link java.util.Map} factory class name appropriate for map bindings. */
+ /**
+ * The {@link java.util.Map}-of-value factory class name appropriate for map bindings.
+ *
+ * <ul>
+ * <li>{@link MapFactory} for provision bindings.
+ * <li>{@link MapProducer} for production bindings.
+ * </ul>
+ */
static ClassName mapFactoryClassName(ContributionBinding binding) {
- checkState(binding.bindingKind().equals(SYNTHETIC_MULTIBOUND_MAP), binding.bindingKind());
- MapType mapType = MapType.from(binding.key());
switch (binding.bindingType()) {
- case PROVISION:
- return mapType.valuesAreTypeOf(Provider.class) ? MAP_PROVIDER_FACTORY : MAP_FACTORY;
case PRODUCTION:
- return mapType.valuesAreFrameworkType()
- ? mapType.valuesAreTypeOf(Producer.class)
- ? MAP_OF_PRODUCER_PRODUCER
- : MAP_OF_PRODUCED_PRODUCER
- : MAP_PRODUCER;
+ return MapType.from(binding.key()).valuesAreTypeOf(Produced.class)
+ ? MAP_OF_PRODUCED_PRODUCER : MAP_PRODUCER;
+
+ case PROVISION:
+ return MAP_FACTORY;
+
default:
- throw new IllegalArgumentException(binding.bindingType().toString());
+ throw new AssertionError(binding.toString());
}
}
+ /**
+ * The {@link java.util.Map}-of-framework factory class name appropriate for map bindings.
+ *
+ * <ul>
+ * <li>{@link MapProviderFactory} for provision bindings.
+ * <li>{@link MapOfProducerProducer} for production bindings.
+ * </ul>
+ */
+ static ClassName frameworkMapFactoryClassName(BindingType bindingType) {
+ return bindingType.equals(BindingType.PRODUCTION)
+ ? MAP_OF_PRODUCER_PRODUCER : MAP_PROVIDER_FACTORY;
+ }
+
private static String factoryPrefix(ContributionBinding binding) {
switch (binding.bindingKind()) {
case INJECTION:
diff --git a/java/dagger/producers/internal/MapOfProducedProducer.java b/java/dagger/producers/internal/MapOfProducedProducer.java
index 6a50b22..7fe2ce4 100644
--- a/java/dagger/producers/internal/MapOfProducedProducer.java
+++ b/java/dagger/producers/internal/MapOfProducedProducer.java
@@ -16,22 +16,20 @@
package dagger.producers.internal;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static dagger.producers.internal.Producers.producerFromProvider;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import dagger.producers.Produced;
import dagger.producers.Producer;
import java.util.List;
import java.util.Map;
-import javax.inject.Provider;
/**
* A {@link Producer} implementation used to implement {@link Map} bindings. This producer returns a
@@ -41,22 +39,48 @@
* @author Jesse Beder
*/
public final class MapOfProducedProducer<K, V> extends AbstractProducer<Map<K, Produced<V>>> {
- private final Map<K, Producer<V>> mapOfProducers;
+ private final Producer<Map<K, Producer<V>>> mapProducerProducer;
- private MapOfProducedProducer(Map<K, Producer<V>> mapOfProducers) {
- this.mapOfProducers = mapOfProducers;
+ private MapOfProducedProducer(Producer<Map<K, Producer<V>>> mapProducerProducer) {
+ this.mapProducerProducer = mapProducerProducer;
+ }
+
+ /**
+ * Returns a producer of {@code Map<K, Produced<V>>}, where the map is derived from the given map
+ * of producers by waiting for those producers' resulting futures. The iteration order mirrors the
+ * order of the input map.
+ *
+ * <p>If any of the delegate producers, or their resulting values, are null, then this producer's
+ * future will succeed and the corresponding {@code Produced<V>} will fail with a
+ * {@link NullPointerException}.
+ *
+ * <p>Canceling this future will attempt to cancel all of the component futures, and if any of the
+ * component futures fails or is canceled, this one is, too.
+ */
+ public static <K, V> MapOfProducedProducer<K, V> create(
+ Producer<Map<K, Producer<V>>> mapProducerProducer) {
+ return new MapOfProducedProducer<K, V>(mapProducerProducer);
}
@Override
public ListenableFuture<Map<K, Produced<V>>> compute() {
- return Futures.transform(
- Futures.allAsList(
- Iterables.transform(
- mapOfProducers.entrySet(), MapOfProducedProducer.<K, V>entryUnwrapper())),
- new Function<List<Map.Entry<K, Produced<V>>>, Map<K, Produced<V>>>() {
+ return Futures.transformAsync(
+ mapProducerProducer.get(),
+ new AsyncFunction<Map<K, Producer<V>>, Map<K, Produced<V>>>() {
@Override
- public Map<K, Produced<V>> apply(List<Map.Entry<K, Produced<V>>> entries) {
- return ImmutableMap.copyOf(entries);
+ public ListenableFuture<Map<K, Produced<V>>> apply(final Map<K, Producer<V>> map) {
+ // TODO(beder): Use Futures.whenAllComplete when Guava 20 is released.
+ return transform(
+ Futures.allAsList(
+ Iterables.transform(
+ map.entrySet(), MapOfProducedProducer.<K, V>entryUnwrapper())),
+ new Function<List<Map.Entry<K, Produced<V>>>, Map<K, Produced<V>>>() {
+ @Override
+ public Map<K, Produced<V>> apply(List<Map.Entry<K, Produced<V>>> entries) {
+ return ImmutableMap.copyOf(entries);
+ }
+ },
+ directExecutor());
}
},
directExecutor());
@@ -90,35 +114,4 @@
entryUnwrapper() {
return (Function) ENTRY_UNWRAPPER;
}
-
- /** Returns a new {@link Builder}. */
- public static <K, V> Builder<K, V> builder() {
- return new Builder<>();
- }
-
- /** A builder for {@link MapOfProducedProducer}. */
- public static final class Builder<K, V> {
- private final ImmutableMap.Builder<K, Producer<V>> mapBuilder = ImmutableMap.builder();
-
- /** Returns a new {@link MapOfProducedProducer}. */
- public MapOfProducedProducer<K, V> build() {
- return new MapOfProducedProducer<>(mapBuilder.build());
- }
-
- /** Associates {@code key} with {@code producerOfValue}. */
- public Builder<K, V> put(K key, Producer<V> producerOfValue) {
- checkNotNull(key, "key");
- checkNotNull(producerOfValue, "producer of value");
- mapBuilder.put(key, producerOfValue);
- return this;
- }
-
- /** Associates {@code key} with {@code providerOfValue}. */
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- checkNotNull(key, "key");
- checkNotNull(providerOfValue, "provider of value");
- mapBuilder.put(key, producerFromProvider(providerOfValue));
- return this;
- }
- }
}
diff --git a/java/dagger/producers/internal/MapOfProducerProducer.java b/java/dagger/producers/internal/MapOfProducerProducer.java
index 282cf86..5eef863 100644
--- a/java/dagger/producers/internal/MapOfProducerProducer.java
+++ b/java/dagger/producers/internal/MapOfProducerProducer.java
@@ -17,6 +17,7 @@
package dagger.producers.internal;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Maps.newLinkedHashMapWithExpectedSize;
import static dagger.producers.internal.Producers.producerFromProvider;
import com.google.common.collect.ImmutableMap;
@@ -33,11 +34,20 @@
* @author Jesse Beder
*/
public final class MapOfProducerProducer<K, V> extends AbstractProducer<Map<K, Producer<V>>> {
+ private static final MapOfProducerProducer<Object, Object> EMPTY =
+ new MapOfProducerProducer<Object, Object>(ImmutableMap.<Object, Producer<Object>>of());
+
private final ImmutableMap<K, Producer<V>> contributingMap;
/** Returns a new {@link Builder}. */
- public static <K, V> Builder<K, V> builder() {
- return new Builder<>();
+ public static <K, V> Builder<K, V> builder(int size) {
+ return new Builder<K, V>(size);
+ }
+
+ /** Returns a producer of an empty map. */
+ @SuppressWarnings("unchecked") // safe contravariant cast
+ public static <K, V> MapOfProducerProducer<K, V> empty() {
+ return (MapOfProducerProducer<K, V>) EMPTY;
}
private MapOfProducerProducer(ImmutableMap<K, Producer<V>> contributingMap) {
@@ -49,11 +59,22 @@
return Futures.<Map<K, Producer<V>>>immediateFuture(contributingMap);
}
- /** A builder for {@link MapOfProducerProducer} */
+ /**
+ * A builder to help build the {@link MapOfProducerProducer}
+ */
public static final class Builder<K, V> {
- private final ImmutableMap.Builder<K, Producer<V>> mapBuilder = ImmutableMap.builder();
+ private final Map<K, Producer<V>> mapBuilder;
- /** Associates {@code key} with {@code producerOfValue}. */
+ private Builder(int size) {
+ this.mapBuilder = newLinkedHashMapWithExpectedSize(size);
+ }
+
+ /** Returns a new {@link MapOfProducerProducer}. */
+ public MapOfProducerProducer<K, V> build() {
+ return new MapOfProducerProducer<K, V>(ImmutableMap.copyOf(mapBuilder));
+ }
+
+ /** Associates key with producerOfValue in {@code Builder}. */
public Builder<K, V> put(K key, Producer<V> producerOfValue) {
checkNotNull(key, "key");
checkNotNull(producerOfValue, "producer of value");
@@ -61,17 +82,12 @@
return this;
}
- /** Associates {@code key} with {@code providerOfValue}. */
+ /** Associates key with providerOfValue in {@code Builder}. */
public Builder<K, V> put(K key, Provider<V> providerOfValue) {
checkNotNull(key, "key");
checkNotNull(providerOfValue, "provider of value");
mapBuilder.put(key, producerFromProvider(providerOfValue));
return this;
}
-
- /** Returns a new {@link MapOfProducerProducer}. */
- public MapOfProducerProducer<K, V> build() {
- return new MapOfProducerProducer<>(mapBuilder.build());
- }
}
}
diff --git a/java/dagger/producers/internal/MapProducer.java b/java/dagger/producers/internal/MapProducer.java
index ca1650e..1a13b9d 100644
--- a/java/dagger/producers/internal/MapProducer.java
+++ b/java/dagger/producers/internal/MapProducer.java
@@ -16,21 +16,19 @@
package dagger.producers.internal;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.util.concurrent.Futures.transform;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-import static dagger.producers.internal.Producers.producerFromProvider;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import dagger.producers.Producer;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
-import javax.inject.Provider;
/**
* A {@link Producer} implementation used to implement {@link Map} bindings. This producer returns a
@@ -39,64 +37,73 @@
* @author Jesse Beder
*/
public final class MapProducer<K, V> extends AbstractProducer<Map<K, V>> {
- private final ImmutableMap<K, Producer<V>> mapOfProducers;
+ private final Producer<Map<K, Producer<V>>> mapProducerProducer;
- private MapProducer(ImmutableMap<K, Producer<V>> mapOfProducers) {
- this.mapOfProducers = mapOfProducers;
+ private MapProducer(Producer<Map<K, Producer<V>>> mapProducerProducer) {
+ this.mapProducerProducer = mapProducerProducer;
}
- /** Returns a new {@link Builder}. */
- public static <K, V> Builder<K, V> builder() {
- return new Builder<>();
- }
-
- /** A builder for {@link MapProducer} */
- public static final class Builder<K, V> {
- private final ImmutableMap.Builder<K, Producer<V>> mapBuilder = ImmutableMap.builder();
-
- /** Associates {@code key} with {@code producerOfValue}. */
- public Builder<K, V> put(K key, Producer<V> producerOfValue) {
- checkNotNull(key, "key");
- checkNotNull(producerOfValue, "producer of value");
- mapBuilder.put(key, producerOfValue);
- return this;
- }
-
- /** Associates {@code key} with {@code providerOfValue}. */
- public Builder<K, V> put(K key, Provider<V> providerOfValue) {
- checkNotNull(key, "key");
- checkNotNull(providerOfValue, "provider of value");
- mapBuilder.put(key, producerFromProvider(providerOfValue));
- return this;
- }
-
- /** Returns a new {@link MapProducer}. */
- public MapProducer<K, V> build() {
- return new MapProducer<>(mapBuilder.build());
- }
+ /**
+ * Returns a producer of {@code Map<K, V>}, where the map is derived from the given map of
+ * producers by waiting for those producers' resulting futures. The iteration order mirrors the
+ * order of the input map.
+ *
+ * <p>If any of the delegate producers, or their resulting values, are null, then this producer's
+ * future will fail with a {@link NullPointerException}.
+ *
+ * <p>Canceling this future will attempt to cancel all of the component futures, and if any of the
+ * component futures fails or is canceled, this one is, too.
+ */
+ public static <K, V> MapProducer<K, V> create(Producer<Map<K, Producer<V>>> mapProducerProducer) {
+ return new MapProducer<K, V>(mapProducerProducer);
}
@Override
- protected ListenableFuture<Map<K, V>> compute() {
- final List<ListenableFuture<Map.Entry<K, V>>> listOfEntries = new ArrayList<>();
- for (final Entry<K, Producer<V>> entry : mapOfProducers.entrySet()) {
- listOfEntries.add(
- Futures.transform(entry.getValue().get(), new Function<V, Entry<K, V>>() {
- @Override
- public Entry<K, V> apply(V computedValue) {
- return Maps.immutableEntry(entry.getKey(), computedValue);
- }
- }, directExecutor()));
- }
-
- return Futures.transform(
- Futures.allAsList(listOfEntries),
- new Function<List<Map.Entry<K, V>>, Map<K, V>>() {
+ public ListenableFuture<Map<K, V>> compute() {
+ return Futures.transformAsync(
+ mapProducerProducer.get(),
+ new AsyncFunction<Map<K, Producer<V>>, Map<K, V>>() {
@Override
- public Map<K, V> apply(List<Map.Entry<K, V>> entries) {
- return ImmutableMap.copyOf(entries);
+ public ListenableFuture<Map<K, V>> apply(final Map<K, Producer<V>> map) {
+ // TODO(beder): Use Futures.whenAllComplete when Guava 20 is released.
+ return transform(
+ Futures.allAsList(
+ Iterables.transform(map.entrySet(), MapProducer.<K, V>entryUnwrapper())),
+ new Function<List<Map.Entry<K, V>>, Map<K, V>>() {
+ @Override
+ public Map<K, V> apply(List<Map.Entry<K, V>> entries) {
+ return ImmutableMap.copyOf(entries);
+ }
+ },
+ directExecutor());
}
},
directExecutor());
}
+
+ private static final Function<
+ Map.Entry<Object, Producer<Object>>, ListenableFuture<Map.Entry<Object, Object>>>
+ ENTRY_UNWRAPPER =
+ new Function<
+ Map.Entry<Object, Producer<Object>>, ListenableFuture<Map.Entry<Object, Object>>>() {
+ @Override
+ public ListenableFuture<Map.Entry<Object, Object>> apply(
+ final Map.Entry<Object, Producer<Object>> entry) {
+ return transform(
+ entry.getValue().get(),
+ new Function<Object, Map.Entry<Object, Object>>() {
+ @Override
+ public Map.Entry<Object, Object> apply(Object value) {
+ return Maps.immutableEntry(entry.getKey(), value);
+ }
+ },
+ directExecutor());
+ }
+ };
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // bivariate implementation
+ private static <K, V>
+ Function<Map.Entry<K, Producer<V>>, ListenableFuture<Map.Entry<K, V>>> entryUnwrapper() {
+ return (Function) ENTRY_UNWRAPPER;
+ }
}
diff --git a/java/dagger/producers/internal/Producers.java b/java/dagger/producers/internal/Producers.java
index ee0bb8f..029bcb5 100644
--- a/java/dagger/producers/internal/Producers.java
+++ b/java/dagger/producers/internal/Producers.java
@@ -22,7 +22,6 @@
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
@@ -30,7 +29,6 @@
import dagger.producers.Produced;
import dagger.producers.Producer;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import javax.inject.Provider;
@@ -153,13 +151,5 @@
};
}
- private static final Producer<Map<Object, Object>> EMPTY_MAP_PRODUCER =
- Producers.<Map<Object, Object>>immediateProducer(ImmutableMap.of());
-
- @SuppressWarnings("unchecked") // safe contravariant cast
- public static <K, V> Producer<Map<K, V>> emptyMapProducer() {
- return (Producer<Map<K, V>>) (Producer) EMPTY_MAP_PRODUCER;
- }
-
private Producers() {}
}
diff --git a/javatests/dagger/functional/LazyMaps.java b/javatests/dagger/functional/LazyMaps.java
deleted file mode 100644
index eeb1368..0000000
--- a/javatests/dagger/functional/LazyMaps.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * 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 dagger.functional;
-
-import dagger.Component;
-import dagger.Lazy;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-/**
- * Bindings that use {@code Lazy<T>} as the value in a multibound map. A regression was uncovered
- * when using {@code MapType.valuesAreFrameworkType()}, which treats {@link Lazy} as a framework
- * type and incorrectly suggested {@link dagger.internal.MapProviderFactory} for a {@code Map<K,
- * Lazy<V>>} instead of a plain {@link dagger.internal.MapFactory}. See b/65084589.
- */
-class LazyMaps {
- @Module
- abstract static class TestModule {
- @Provides
- @Singleton
- static AtomicInteger provideAtomicInteger() {
- return new AtomicInteger();
- }
-
- @Provides
- static String provideString(AtomicInteger atomicInteger) {
- return "value-" + atomicInteger.incrementAndGet();
- }
-
- @Provides
- @IntoMap
- @StringKey("key")
- static Lazy<String> mapContribution(Lazy<String> lazy) {
- return lazy;
- }
-
- /* TODO(b/65118638) Replace once @Binds @IntoMap Lazy<T> methods work properly.
- @Binds
- @IntoMap
- @StringKey("binds-key")
- abstract Lazy<String> mapContributionAsBinds(Lazy<String> lazy);
- */
- }
-
- @Singleton
- @Component(modules = TestModule.class)
- interface TestComponent {
- Map<String, Lazy<String>> mapOfLazy();
-
- Map<String, Provider<Lazy<String>>> mapOfProviderOfLazy();
-
- Provider<Map<String, Lazy<String>>> providerForMapOfLazy();
-
- Provider<Map<String, Provider<Lazy<String>>>> providerForMapOfProviderOfLazy();
- }
-}
diff --git a/javatests/dagger/functional/LazyMapsTest.java b/javatests/dagger/functional/LazyMapsTest.java
deleted file mode 100644
index a3e289a..0000000
--- a/javatests/dagger/functional/LazyMapsTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * 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 dagger.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Lazy;
-import dagger.functional.LazyMaps.TestComponent;
-import java.util.Map;
-import javax.inject.Provider;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for {@link LazyMaps}. */
-@RunWith(JUnit4.class)
-public class LazyMapsTest {
- @Test
- public void mapOfLazies() {
- TestComponent component = DaggerLazyMaps_TestComponent.create();
- Map<String, Lazy<String>> laziesMap = component.mapOfLazy();
-
- String firstGet = laziesMap.get("key").get();
- assertThat(firstGet).isEqualTo("value-1");
- assertThat(firstGet).isSameAs(laziesMap.get("key").get());
-
- assertThat(component.mapOfLazy().get("key").get()).isEqualTo("value-2");
- }
-
- @Test
- public void mapOfProviderOfLaziesReturnsDifferentLazy() {
- TestComponent component = DaggerLazyMaps_TestComponent.create();
- Map<String, Provider<Lazy<String>>> providersOfLaziesMap = component.mapOfProviderOfLazy();
-
- assertThat(providersOfLaziesMap.get("key").get().get())
- .isNotEqualTo(providersOfLaziesMap.get("key").get().get());
- }
-}
diff --git a/javatests/dagger/internal/codegen/Compilers.java b/javatests/dagger/internal/codegen/Compilers.java
index 3eee251..a42d1a2 100644
--- a/javatests/dagger/internal/codegen/Compilers.java
+++ b/javatests/dagger/internal/codegen/Compilers.java
@@ -16,12 +16,8 @@
package dagger.internal.codegen;
-import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
-import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;
import static com.google.testing.compile.Compiler.javac;
-import static java.util.stream.Collectors.joining;
-import com.google.common.base.Splitter;
import com.google.testing.compile.Compiler;
/** {@link Compiler} instances for testing Dagger. */
@@ -31,18 +27,4 @@
static Compiler daggerCompiler() {
return javac().withProcessors(new ComponentProcessor());
}
-
- static Compiler daggerCompilerWithoutGuava() {
- return daggerCompiler().withOptions("-classpath", classpathWithoutGuava());
- }
-
- private static final String GUAVA = "guava";
-
- private static String classpathWithoutGuava() {
- return Splitter.on(PATH_SEPARATOR.value())
- .splitToList(JAVA_CLASS_PATH.value())
- .stream()
- .filter(jar -> !jar.contains(GUAVA))
- .collect(joining(PATH_SEPARATOR.value()));
- }
}
diff --git a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
index cc22bae..6aba380 100644
--- a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
@@ -107,7 +107,7 @@
"",
"@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
"interface TestComponent {",
- " Provider<Map<PathEnum, Provider<Handler>>> dispatcher();",
+ " Map<PathEnum, Provider<Handler>> dispatcher();",
"}");
JavaFileObject generatedComponent =
JavaFileObjects.forSourceLines(
@@ -153,8 +153,8 @@
" }",
"",
" @Override",
- " public Provider<Map<PathEnum, Provider<Handler>>> dispatcher() {",
- " return mapOfPathEnumAndProviderOfHandlerProvider;",
+ " public Map<PathEnum, Provider<Handler>> dispatcher() {",
+ " return mapOfPathEnumAndProviderOfHandlerProvider.get();",
" }",
"",
" public static final class Builder {",
@@ -259,7 +259,7 @@
"",
"@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
"interface TestComponent {",
- " Provider<Map<String, Provider<Handler>>> dispatcher();",
+ " Map<String, Provider<Handler>> dispatcher();",
"}");
JavaFileObject generatedComponent =
JavaFileObjects.forSourceLines(
@@ -305,8 +305,8 @@
" }",
"",
" @Override",
- " public Provider<Map<String, Provider<Handler>>> dispatcher() {",
- " return mapOfStringAndProviderOfHandlerProvider;",
+ " public Map<String, Provider<Handler>> dispatcher() {",
+ " return mapOfStringAndProviderOfHandlerProvider.get();",
" }",
"",
" public static final class Builder {",
@@ -420,7 +420,7 @@
"",
"@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
"interface TestComponent {",
- " Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher();",
+ " Map<WrappedClassKey, Provider<Handler>> dispatcher();",
"}");
JavaFileObject generatedComponent =
JavaFileObjects.forSourceLines(
@@ -468,8 +468,8 @@
" }",
"",
" @Override",
- " public Provider<Map<WrappedClassKey, Provider<Handler>>> dispatcher() {",
- " return mapOfWrappedClassKeyAndProviderOfHandlerProvider;",
+ " public Map<WrappedClassKey, Provider<Handler>> dispatcher() {",
+ " return mapOfWrappedClassKeyAndProviderOfHandlerProvider.get();",
" }",
"",
" public static final class Builder {",
@@ -585,7 +585,7 @@
"",
"@Component(modules = {MapModuleOne.class, MapModuleTwo.class})",
"interface TestComponent {",
- " Provider<Map<PathEnum, Handler>> dispatcher();",
+ " Map<PathEnum, Handler> dispatcher();",
"}");
JavaFileObject generatedComponent =
JavaFileObjects.forSourceLines(
@@ -593,6 +593,7 @@
"package test;",
"",
"import dagger.internal.MapFactory;",
+ "import dagger.internal.MapProviderFactory;",
"import dagger.internal.Preconditions;",
"import java.util.Map;",
"import javax.annotation.Generated;",
@@ -602,6 +603,8 @@
"public final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<PathEnum, Provider<Handler>>>",
+ " mapOfPathEnumAndProviderOfHandlerProvider;",
" private Provider<Map<PathEnum, Handler>> mapOfPathEnumAndHandlerProvider;",
"",
" private DaggerTestComponent(Builder builder) {",
@@ -622,16 +625,18 @@
" MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
" this.provideLoginHandlerProvider =",
" MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
- " this.mapOfPathEnumAndHandlerProvider =",
- " MapFactory.<PathEnum, Handler>builder(2)",
+ " this.mapOfPathEnumAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathEnum, Handler>builder(2)",
" .put(PathEnum.ADMIN, provideAdminHandlerProvider)",
" .put(PathEnum.LOGIN, provideLoginHandlerProvider)",
" .build();",
+ " this.mapOfPathEnumAndHandlerProvider =",
+ " MapFactory.create(mapOfPathEnumAndProviderOfHandlerProvider);",
" }",
"",
" @Override",
- " public Provider<Map<PathEnum, Handler>> dispatcher() {",
- " return mapOfPathEnumAndHandlerProvider;",
+ " public Map<PathEnum, Handler> dispatcher() {",
+ " return mapOfPathEnumAndHandlerProvider.get();",
" }",
"",
" public static final class Builder {",
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java b/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
deleted file mode 100644
index 7759419..0000000
--- a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * 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 dagger.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompilerWithoutGuava;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.NPE_FROM_PROVIDES_METHOD;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import com.squareup.javapoet.CodeBlock;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MapBindingExpressionTest {
- public static final CodeBlock NPE_FROM_PROVIDES =
- CodeBlocks.stringLiteral(ErrorMessages.CANNOT_RETURN_NULL_FROM_NON_NULLABLE_PROVIDES_METHOD);
-
- @Test
- public void mapBindings() {
- JavaFileObject mapModuleFile = JavaFileObjects.forSourceLines("test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntKey;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.LongKey;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface MapModule {",
- " @Multibinds Map<String, String> stringMap();",
- " @Provides @IntoMap @IntKey(0) static int provideInt() { return 0; }",
- " @Provides @IntoMap @LongKey(0) static long provideLong0() { return 0; }",
- " @Provides @IntoMap @LongKey(1) static long provideLong1() { return 1; }",
- " @Provides @IntoMap @LongKey(2) static long provideLong2() { return 2; }",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = MapModule.class)",
- "interface TestComponent {",
- " Map<String, String> strings();",
- " Map<String, Provider<String>> providerStrings();",
- "",
- " Map<Integer, Integer> ints();",
- " Map<Integer, Provider<Integer>> providerInts();",
- " Map<Long, Long> longs();",
- " Map<Long, Provider<Long>> providerLongs();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import dagger.internal.MapBuilder;",
- "import java.util.Collections;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerTestComponent implements TestComponent {",
- " private DaggerTestComponent(Builder builder) {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public Map<String, String> strings() {",
- " return Collections.<String, String>emptyMap();",
- " }",
- "",
- " @Override",
- " public Map<String, Provider<String>> providerStrings() {",
- " return Collections.<String, Provider<String>>emptyMap();",
- " }",
- "",
- " @Override",
- " public Map<Integer, Integer> ints() {",
- " return Collections.<Integer, Integer>singletonMap(0, MapModule.provideInt());",
- " }",
- "",
- " @Override",
- " public Map<Integer, Provider<Integer>> providerInts() {",
- " return Collections.<Integer, Provider<Integer>>singletonMap(",
- " 0, MapModule_ProvideIntFactory.create());",
- " }",
- "",
- " @Override",
- " public Map<Long, Long> longs() {",
- " return MapBuilder.<Long, Long>newMapBuilder(3)",
- " .put(0L, MapModule.provideLong0())",
- " .put(1L, MapModule.provideLong1())",
- " .put(2L, MapModule.provideLong2())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return MapBuilder.<Long, Provider<Long>>newMapBuilder(3)",
- " .put(0L, MapModule_ProvideLong0Factory.create())",
- " .put(1L, MapModule_ProvideLong1Factory.create())",
- " .put(2L, MapModule_ProvideLong2Factory.create())",
- " .build();",
- " }",
- "",
- " public static final class Builder {",
- " private Builder() {",
- " }",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent(this);",
- " }",
- " }",
- "}");
- Compilation compilation = daggerCompilerWithoutGuava().compile(mapModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void inaccessible() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible",
- "package other;",
- "",
- "class Inaccessible {}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import java.util.Map;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Map<Integer, Inaccessible> map) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Multibinds abstract Map<Integer, Inaccessible> ints();",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "import other.TestModule;",
- "import other.UsesInaccessible;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import java.util.Collections;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerTestComponent implements TestComponent {",
- " private DaggerTestComponent(Builder builder) {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newUsesInaccessible(",
- " (Map) Collections.emptyMap());",
- " }",
- "",
- " public static final class Builder {",
- " private Builder() {}",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent(this);",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompilerWithoutGuava().compile(module, inaccessible, usesInaccessible, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void subcomponentOmitsInheritedBindings() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
- " return \"parent value\";",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "import java.util.Map;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Map<String, Object> objectMap();",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- "import dagger.internal.Preconditions;",
- "import java.util.Collections;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerParent implements Parent {",
- " private ParentModule parentModule;",
- "",
- " private DaggerParent(Builder builder) {",
- " initialize(builder);",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static Parent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(final Builder builder) {",
- " this.parentModule = builder.parentModule;",
- " }",
- "",
- " @Override",
- " public Child child() {",
- " return new ChildImpl();",
- " }",
- "",
- " public static final class Builder {",
- " private ParentModule parentModule;",
- "",
- " private Builder() {}",
- "",
- " public Parent build() {",
- " if (parentModule == null) {",
- " this.parentModule = new ParentModule();",
- " }",
- " return new DaggerParent(this);",
- " }",
- "",
- " public Builder parentModule(ParentModule parentModule) {",
- " this.parentModule = Preconditions.checkNotNull(parentModule);",
- " return this;",
- " }",
- " }",
- "",
- " private final class ChildImpl implements Child {",
- " private ChildImpl() {}",
- "",
- " @Override",
- " public Map<String, Object> objectMap() {",
- " return Collections.<String, Object>singletonMap(",
- " \"parent key\",",
- " Preconditions.checkNotNull(",
- " DaggerParent.this.parentModule.parentKeyObject(),",
- " " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- " }",
- "}");
- Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .hasSourceEquivalentTo(expected);
- }
-
-}
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java b/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
deleted file mode 100644
index 0b10fa4..0000000
--- a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * 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 dagger.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
-import static dagger.internal.codegen.GeneratedLines.NPE_FROM_PROVIDES_METHOD;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class MapBindingExpressionWithGuavaTest {
- @Test
- public void mapBindings() {
- JavaFileObject mapModuleFile =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntKey;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.LongKey;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface MapModule {",
- " @Multibinds Map<String, String> stringMap();",
- " @Provides @IntoMap @IntKey(0) static int provideInt() { return 0; }",
- " @Provides @IntoMap @LongKey(0) static long provideLong0() { return 0; }",
- " @Provides @IntoMap @LongKey(1) static long provideLong1() { return 1; }",
- " @Provides @IntoMap @LongKey(2) static long provideLong2() { return 2; }",
- "}");
- JavaFileObject subcomponentModuleFile =
- JavaFileObjects.forSourceLines(
- "test.SubcomponentMapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntKey;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.LongKey;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface SubcomponentMapModule {",
- " @Provides @IntoMap @LongKey(3) static long provideLong3() { return 3; }",
- " @Provides @IntoMap @LongKey(4) static long provideLong4() { return 4; }",
- " @Provides @IntoMap @LongKey(5) static long provideLong5() { return 5; }",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Component(modules = MapModule.class)",
- "interface TestComponent {",
- " Map<String, String> strings();",
- " Map<String, Provider<String>> providerStrings();",
- "",
- " Map<Integer, Integer> ints();",
- " Map<Integer, Provider<Integer>> providerInts();",
- " Map<Long, Long> longs();",
- " Map<Long, Provider<Long>> providerLongs();",
- "",
- " Sub sub();",
- "}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
- "test.Sub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "",
- "@Subcomponent(modules = SubcomponentMapModule.class)",
- "interface Sub {",
- " Map<Long, Long> longs();",
- " Map<Long, Provider<Long>> providerLongs();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableMap;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "import javax.inject.Provider;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerTestComponent implements TestComponent {",
- " private DaggerTestComponent(Builder builder) {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public Map<String, String> strings() {",
- " return ImmutableMap.<String, String>of();",
- " }",
- "",
- " @Override",
- " public Map<String, Provider<String>> providerStrings() {",
- " return ImmutableMap.<String, Provider<String>>of();",
- " }",
- "",
- " @Override",
- " public Map<Integer, Integer> ints() {",
- " return ImmutableMap.<Integer, Integer>of(0, MapModule.provideInt());",
- " }",
- "",
- " @Override",
- " public Map<Integer, Provider<Integer>> providerInts() {",
- " return ImmutableMap.<Integer, Provider<Integer>>of(",
- " 0, MapModule_ProvideIntFactory.create());",
- " }",
- "",
- " @Override",
- " public Map<Long, Long> longs() {",
- " return ImmutableMap.<Long, Long>of(",
- " 0L, MapModule.provideLong0(),",
- " 1L, MapModule.provideLong1(),",
- " 2L, MapModule.provideLong2());",
- " }",
- "",
- " @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return ImmutableMap.<Long, Provider<Long>>of(",
- " 0L, MapModule_ProvideLong0Factory.create(),",
- " 1L, MapModule_ProvideLong1Factory.create(),",
- " 2L, MapModule_ProvideLong2Factory.create());",
- " }",
- "",
- " @Override",
- " public Sub sub() {",
- " return new SubImpl();",
- " }",
- "",
- " public static final class Builder {",
- " private Builder() {",
- " }",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent(this);",
- " }",
- " }",
- " private final class SubImpl implements Sub {",
- " private SubImpl() {}",
- "",
- " @Override",
- " public Map<Long, Long> longs() {",
- " return ImmutableMap.<Long, Long>builder()",
- " .put(0L, MapModule.provideLong0())",
- " .put(1L, MapModule.provideLong1())",
- " .put(2L, MapModule.provideLong2())",
- " .put(3L, SubcomponentMapModule.provideLong3())",
- " .put(4L, SubcomponentMapModule.provideLong4())",
- " .put(5L, SubcomponentMapModule.provideLong5())",
- " .build();",
- " }",
- "",
- " @Override",
- " public Map<Long, Provider<Long>> providerLongs() {",
- " return ImmutableMap.<Long, Provider<Long>>builder()",
- " .put(0L, MapModule_ProvideLong0Factory.create())",
- " .put(1L, MapModule_ProvideLong1Factory.create())",
- " .put(2L, MapModule_ProvideLong2Factory.create())",
- " .put(3L, SubcomponentMapModule_ProvideLong3Factory.create())",
- " .put(4L, SubcomponentMapModule_ProvideLong4Factory.create())",
- " .put(5L, SubcomponentMapModule_ProvideLong5Factory.create())",
- " .build();",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(mapModuleFile, componentFile, subcomponentModuleFile, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void inaccessible() {
- JavaFileObject inaccessible =
- JavaFileObjects.forSourceLines(
- "other.Inaccessible", "package other;", "", "class Inaccessible {}");
- JavaFileObject usesInaccessible =
- JavaFileObjects.forSourceLines(
- "other.UsesInaccessible",
- "package other;",
- "",
- "import java.util.Map;",
- "import javax.inject.Inject;",
- "",
- "public class UsesInaccessible {",
- " @Inject UsesInaccessible(Map<Integer, Inaccessible> map) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "other.TestModule",
- "package other;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "public abstract class TestModule {",
- " @Multibinds abstract Map<Integer, Inaccessible> ints();",
- "}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import java.util.Map;",
- "import javax.inject.Provider;",
- "import other.TestModule;",
- "import other.UsesInaccessible;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " UsesInaccessible usesInaccessible();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableMap;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "import other.UsesInaccessible;",
- "import other.UsesInaccessible_Factory;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerTestComponent implements TestComponent {",
- " private DaggerTestComponent(Builder builder) {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public UsesInaccessible usesInaccessible() {",
- " return UsesInaccessible_Factory.newUsesInaccessible((Map) ImmutableMap.of());",
- " }",
- "",
- " public static final class Builder {",
- " private Builder() {}",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent(this);",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().compile(module, inaccessible, usesInaccessible, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-
- @Test
- public void subcomponentOmitsInheritedBindings() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface Parent {",
- " Child child();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "class ParentModule {",
- " @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
- " return \"parent value\";",
- " }",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "test.Child",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Map<String, Object> objectMap();",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.DaggerParent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableMap;",
- "import dagger.internal.Preconditions;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerParent implements Parent {",
- " private ParentModule parentModule;",
- "",
- " private DaggerParent(Builder builder) {",
- " initialize(builder);",
- " }",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static Parent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize(final Builder builder) {",
- " this.parentModule = builder.parentModule;",
- " }",
- "",
- " @Override",
- " public Child child() {",
- " return new ChildImpl();",
- " }",
- "",
- " public static final class Builder {",
- " private ParentModule parentModule;",
- "",
- " private Builder() {}",
- "",
- " public Parent build() {",
- " if (parentModule == null) {",
- " this.parentModule = new ParentModule();",
- " }",
- " return new DaggerParent(this);",
- " }",
- "",
- " public Builder parentModule(ParentModule parentModule) {",
- " this.parentModule = Preconditions.checkNotNull(parentModule);",
- " return this;",
- " }",
- " }",
- "",
- " private final class ChildImpl implements Child {",
- " private ChildImpl() {}",
- "",
- " @Override",
- " public Map<String, Object> objectMap() {",
- " return ImmutableMap.<String, Object>of(",
- " \"parent key\",",
- " Preconditions.checkNotNull(",
- " DaggerParent.this.parentModule.parentKeyObject(),",
- " " + NPE_FROM_PROVIDES_METHOD + ");",
- " }",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(parent, parentModule, child);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerParent")
- .hasSourceEquivalentTo(expected);
- }
-
- @Test
- public void productionComponents() {
- JavaFileObject mapModuleFile =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.multibindings.Multibinds;",
- "import java.util.Map;",
- "",
- "@Module",
- "interface MapModule {",
- " @Multibinds Map<String, String> stringMap();",
- "}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "import java.util.Map;",
- "",
- "@ProductionComponent(modules = MapModule.class)",
- "interface TestComponent {",
- " ListenableFuture<Map<String, String>> stringMap();",
- "}");
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "test.DaggerTestComponent",
- "package test;",
- "",
- "import com.google.common.collect.ImmutableMap;",
- "import com.google.common.util.concurrent.Futures;",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.internal.Preconditions;",
- "import java.util.Map;",
- "import javax.annotation.Generated;",
- "",
- GENERATED_ANNOTATION,
- "public final class DaggerTestComponent implements TestComponent {",
- " private DaggerTestComponent(Builder builder) {}",
- "",
- " public static Builder builder() {",
- " return new Builder();",
- " }",
- "",
- " public static TestComponent create() {",
- " return new Builder().build();",
- " }",
- "",
- " @Override",
- " public ListenableFuture<Map<String, String>> stringMap() {",
- " return Futures.<Map<String, String>>immediateFuture(",
- " ImmutableMap.<String, String>of());",
- " }",
- "",
- " public static final class Builder {",
- " private Builder() {}",
- "",
- " public TestComponent build() {",
- " return new DaggerTestComponent(this);",
- " }",
- "",
- " @Deprecated",
- " public Builder testComponent_ProductionExecutorModule(",
- " TestComponent_ProductionExecutorModule",
- " testComponent_ProductionExecutorModule) {",
- " Preconditions.checkNotNull(testComponent_ProductionExecutorModule);",
- " return this;",
- " }",
- " }",
- "}");
- Compilation compilation =
- daggerCompiler().compile(mapModuleFile, componentFile);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
index 11d9db4..4a72a5f 100644
--- a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
+++ b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
@@ -212,7 +212,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.MapProviderFactory;",
"import dagger.internal.Preconditions;",
"import java.util.Map;",
"import javax.annotation.Generated;",
@@ -222,6 +222,8 @@
"public final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<PathKey, Provider<Handler>>>",
+ " mapOfPathKeyAndProviderOfHandlerProvider;",
"",
" private DaggerTestComponent(Builder builder) {",
" initialize(builder);",
@@ -241,15 +243,18 @@
" MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
" this.provideLoginHandlerProvider =",
" MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathKey, Handler>builder(2)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.ADMIN, \"AdminPath\"),",
+ " provideAdminHandlerProvider)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
+ " provideLoginHandlerProvider)",
+ " .build();",
" }",
"",
" @Override",
" public Map<PathKey, Provider<Handler>> dispatcher() {",
- " return ImmutableMap.<PathKey, Provider<Handler>>of(",
- " PathKeyCreator.createPathKey(PathEnum.ADMIN, \"AdminPath\"),",
- " provideAdminHandlerProvider,",
- " PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
- " provideLoginHandlerProvider);",
+ " return mapOfPathKeyAndProviderOfHandlerProvider.get();",
" }",
"",
" public static final class Builder {",
@@ -381,7 +386,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.MapProviderFactory;",
"import dagger.internal.Preconditions;",
"import java.util.Map;",
"import javax.annotation.Generated;",
@@ -391,6 +396,8 @@
"public final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
+ " private Provider<Map<PathKey, Provider<Handler>>>",
+ " mapOfPathKeyAndProviderOfHandlerProvider;",
"",
" private DaggerTestComponent(Builder builder) {",
" initialize(builder);",
@@ -410,15 +417,18 @@
" MapModuleOne_ProvideAdminHandlerFactory.create(builder.mapModuleOne);",
" this.provideLoginHandlerProvider =",
" MapModuleTwo_ProvideLoginHandlerFactory.create(builder.mapModuleTwo);",
+ " this.mapOfPathKeyAndProviderOfHandlerProvider =",
+ " MapProviderFactory.<PathKey, Handler>builder(2)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.ADMIN, \"DefaultPath\"),",
+ " provideAdminHandlerProvider)",
+ " .put(PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
+ " provideLoginHandlerProvider)",
+ " .build();",
" }",
"",
" @Override",
" public Map<PathKey, Provider<Handler>> dispatcher() {",
- " return ImmutableMap.<PathKey, Provider<Handler>>of(",
- " PathKeyCreator.createPathKey(PathEnum.ADMIN, \"DefaultPath\"),",
- " provideAdminHandlerProvider,",
- " PathKeyCreator.createPathKey(PathEnum.LOGIN, \"LoginPath\"),",
- " provideLoginHandlerProvider);",
+ " return mapOfPathKeyAndProviderOfHandlerProvider.get();",
" }",
"",
" public static final class Builder {",
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
index 226972c..1cadddb 100644
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
@@ -16,11 +16,16 @@
package dagger.internal.codegen;
+import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
+import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompilerWithoutGuava;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
+import static java.util.stream.Collectors.joining;
+import com.google.common.base.Splitter;
import com.google.testing.compile.Compilation;
+import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
import com.squareup.javapoet.CodeBlock;
import javax.tools.JavaFileObject;
@@ -131,8 +136,7 @@
" }",
" }",
"}");
- Compilation compilation =
- daggerCompilerWithoutGuava().compile(emptySetModuleFile, setModuleFile, componentFile);
+ Compilation compilation = compiler().compile(emptySetModuleFile, setModuleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
@@ -247,8 +251,7 @@
" }",
"}");
Compilation compilation =
- daggerCompilerWithoutGuava()
- .compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile);
+ compiler().compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
@@ -276,6 +279,7 @@
"import dagger.Module;",
"import dagger.Provides;",
"import dagger.multibindings.IntoSet;",
+ "import dagger.multibindings.IntoMap;",
"import dagger.multibindings.StringKey;",
"",
"@Module",
@@ -283,6 +287,10 @@
" @Provides @IntoSet static Object parentObject() {",
" return \"parent object\";",
" }",
+ "",
+ " @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
+ " return \"parent value\";",
+ " }",
"}");
JavaFileObject child =
JavaFileObjects.forSourceLines(
@@ -290,25 +298,35 @@
"package test;",
"",
"import dagger.Subcomponent;",
+ "import java.util.Map;",
"import java.util.Set;",
"",
"@Subcomponent",
"interface Child {",
" Set<Object> objectSet();",
+ " Map<String, Object> objectMap();",
"}");
JavaFileObject expected =
JavaFileObjects.forSourceLines(
"test.DaggerParent",
"package test;",
"",
+ "import dagger.internal.MapFactory;",
+ "import dagger.internal.MapProviderFactory;",
"import dagger.internal.Preconditions;",
"import java.util.Collections;",
+ "import java.util.Map;",
"import java.util.Set;",
"import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
"",
GENERATED_ANNOTATION,
"public final class DaggerParent implements Parent {",
- " private DaggerParent(Builder builder) {}",
+ " private Provider<Object> parentKeyObjectProvider;",
+ "",
+ " private DaggerParent(Builder builder) {",
+ " initialize(builder);",
+ " }",
"",
" public static Builder builder() {",
" return new Builder();",
@@ -318,40 +336,84 @@
" return new Builder().build();",
" }",
"",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.parentKeyObjectProvider =",
+ " ParentModule_ParentKeyObjectFactory.create(builder.parentModule);",
+ " }",
+ "",
" @Override",
" public Child child() {",
" return new ChildImpl();",
" }",
"",
" public static final class Builder {",
+ " private ParentModule parentModule;",
+ "",
" private Builder() {}",
"",
" public Parent build() {",
+ " if (parentModule == null) {",
+ " this.parentModule = new ParentModule();",
+ " }",
" return new DaggerParent(this);",
" }",
"",
- " @Deprecated",
" public Builder parentModule(ParentModule parentModule) {",
- " Preconditions.checkNotNull(parentModule);",
+ " this.parentModule = Preconditions.checkNotNull(parentModule);",
" return this;",
" }",
" }",
"",
" private final class ChildImpl implements Child {",
- " private ChildImpl() {}",
+ " private Provider<Map<String, Provider<Object>>>",
+ " mapOfStringAndProviderOfObjectProvider;",
+ " private Provider<Map<String, Object>> mapOfStringAndObjectProvider;",
+ "",
+ " private ChildImpl() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.mapOfStringAndProviderOfObjectProvider =",
+ " MapProviderFactory.<String, Object>builder(1)",
+ " .put(\"parent key\", DaggerParent.this.parentKeyObjectProvider)",
+ " .build();",
+ " this.mapOfStringAndObjectProvider = MapFactory.create(",
+ " mapOfStringAndProviderOfObjectProvider);",
+ " }",
"",
" @Override",
" public Set<Object> objectSet() {",
" return Collections.<Object>singleton(Preconditions.checkNotNull(",
" ParentModule.parentObject(), " + NPE_FROM_PROVIDES + "));",
" }",
+ "",
+ " @Override",
+ " public Map<String, Object> objectMap() {",
+ " return mapOfStringAndObjectProvider.get();",
+ " }",
" }",
"}");
- Compilation compilation = daggerCompilerWithoutGuava().compile(parent, parentModule, child);
+ Compilation compilation = compiler().compile(parent, parentModule, child);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerParent")
.hasSourceEquivalentTo(expected);
}
+ private Compiler compiler() {
+ return daggerCompiler().withOptions("-classpath", classpathWithoutGuava());
+ }
+
+ private static final String GUAVA = "guava";
+
+ private String classpathWithoutGuava() {
+ return Splitter.on(PATH_SEPARATOR.value())
+ .splitToList(JAVA_CLASS_PATH.value())
+ .stream()
+ .filter(jar -> !jar.contains(GUAVA))
+ .collect(joining(":"));
+ }
}
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
index 8de07ec..1312e09 100644
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
+++ b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
@@ -286,6 +286,7 @@
"import dagger.Module;",
"import dagger.Provides;",
"import dagger.multibindings.IntoSet;",
+ "import dagger.multibindings.IntoMap;",
"import dagger.multibindings.StringKey;",
"",
"@Module",
@@ -293,6 +294,10 @@
" @Provides @IntoSet static Object parentObject() {",
" return \"parent object\";",
" }",
+ "",
+ " @Provides @IntoMap @StringKey(\"parent key\") Object parentKeyObject() {",
+ " return \"parent value\";",
+ " }",
"}");
JavaFileObject child =
JavaFileObjects.forSourceLines(
@@ -300,11 +305,13 @@
"package test;",
"",
"import dagger.Subcomponent;",
+ "import java.util.Map;",
"import java.util.Set;",
"",
"@Subcomponent",
"interface Child {",
" Set<Object> objectSet();",
+ " Map<String, Object> objectMap();",
"}");
JavaFileObject expected =
JavaFileObjects.forSourceLines(
@@ -312,13 +319,21 @@
"package test;",
"",
"import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.MapFactory;",
+ "import dagger.internal.MapProviderFactory;",
"import dagger.internal.Preconditions;",
+ "import java.util.Map;",
"import java.util.Set;",
"import javax.annotation.Generated;",
+ "import javax.inject.Provider;",
"",
GENERATED_ANNOTATION,
"public final class DaggerParent implements Parent {",
- " private DaggerParent(Builder builder) {}",
+ " private Provider<Object> parentKeyObjectProvider;",
+ "",
+ " private DaggerParent(Builder builder) {",
+ " initialize(builder);",
+ " }",
"",
" public static Builder builder() {",
" return new Builder();",
@@ -328,33 +343,64 @@
" return new Builder().build();",
" }",
"",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final Builder builder) {",
+ " this.parentKeyObjectProvider =",
+ " ParentModule_ParentKeyObjectFactory.create(builder.parentModule);",
+ " }",
+ "",
" @Override",
" public Child child() {",
" return new ChildImpl();",
" }",
"",
" public static final class Builder {",
+ " private ParentModule parentModule;",
+ "",
" private Builder() {}",
"",
" public Parent build() {",
+ " if (parentModule == null) {",
+ " this.parentModule = new ParentModule();",
+ " }",
" return new DaggerParent(this);",
" }",
"",
- " @Deprecated",
" public Builder parentModule(ParentModule parentModule) {",
- " Preconditions.checkNotNull(parentModule);",
+ " this.parentModule = Preconditions.checkNotNull(parentModule);",
" return this;",
" }",
" }",
"",
" private final class ChildImpl implements Child {",
- " private ChildImpl() {}",
+ " private Provider<Map<String, Provider<Object>>>",
+ " mapOfStringAndProviderOfObjectProvider;",
+ " private Provider<Map<String, Object>> mapOfStringAndObjectProvider;",
+ "",
+ " private ChildImpl() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.mapOfStringAndProviderOfObjectProvider =",
+ " MapProviderFactory.<String, Object>builder(1)",
+ " .put(\"parent key\", DaggerParent.this.parentKeyObjectProvider)",
+ " .build();",
+ " this.mapOfStringAndObjectProvider = MapFactory.create(",
+ " mapOfStringAndProviderOfObjectProvider);",
+ " }",
"",
" @Override",
" public Set<Object> objectSet() {",
" return ImmutableSet.<Object>of(Preconditions.checkNotNull(",
" ParentModule.parentObject(), " + NPE_FROM_PROVIDES + "));",
" }",
+ "",
+ " @Override",
+ " public Map<String, Object> objectMap() {",
+ " return mapOfStringAndObjectProvider.get();",
+ " }",
" }",
"}");
Compilation compilation = daggerCompiler().compile(parent, parentModule, child);
diff --git a/javatests/dagger/producers/internal/MapOfProducerProducerTest.java b/javatests/dagger/producers/internal/MapOfProducerProducerTest.java
index 645a016..fe285ed 100644
--- a/javatests/dagger/producers/internal/MapOfProducerProducerTest.java
+++ b/javatests/dagger/producers/internal/MapOfProducerProducerTest.java
@@ -31,7 +31,7 @@
@Test
public void success() throws Exception {
MapOfProducerProducer<Integer, String> mapOfProducerProducer =
- MapOfProducerProducer.<Integer, String>builder()
+ MapOfProducerProducer.<Integer, String>builder(2)
.put(15, Producers.<String>immediateProducer("fifteen"))
.put(42, Producers.<String>immediateProducer("forty two"))
.build();
@@ -47,7 +47,7 @@
public void failingContributionDoesNotFailMap() throws Exception {
RuntimeException cause = new RuntimeException("monkey");
MapOfProducerProducer<Integer, String> mapOfProducerProducer =
- MapOfProducerProducer.<Integer, String>builder()
+ MapOfProducerProducer.<Integer, String>builder(2)
.put(15, Producers.<String>immediateProducer("fifteen"))
.put(42, Producers.<String>immediateFailedProducer(cause))
.build();
diff --git a/javatests/dagger/producers/internal/MapProducerTest.java b/javatests/dagger/producers/internal/MapProducerTest.java
index ee7978b..3a8f19d 100644
--- a/javatests/dagger/producers/internal/MapProducerTest.java
+++ b/javatests/dagger/producers/internal/MapProducerTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import com.google.common.collect.ImmutableMap;
import dagger.producers.Producer;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@@ -31,10 +32,13 @@
@Test
public void success() throws Exception {
Producer<Map<Integer, String>> mapProducer =
- MapProducer.<Integer, String>builder()
- .put(15, Producers.immediateProducer("fifteen"))
- .put(42, Producers.immediateProducer("forty two"))
- .build();
+ MapProducer.create(
+ Producers.<Map<Integer, Producer<String>>>immediateProducer(
+ ImmutableMap.<Integer, Producer<String>>of(
+ 15,
+ Producers.<String>immediateProducer("fifteen"),
+ 42,
+ Producers.<String>immediateProducer("forty two"))));
Map<Integer, String> map = mapProducer.get().get();
assertThat(map).hasSize(2);
assertThat(map).containsEntry(15, "fifteen");
@@ -45,11 +49,27 @@
public void failingContribution() throws Exception {
RuntimeException cause = new RuntimeException("monkey");
Producer<Map<Integer, String>> mapProducer =
- MapProducer.<Integer, String>builder()
- .put(15, Producers.immediateProducer("fifteen"))
- // TODO(ronshapiro): remove the type parameter when we drop java7 support
- .put(42, Producers.<String>immediateFailedProducer(cause))
- .build();
+ MapProducer.create(
+ Producers.<Map<Integer, Producer<String>>>immediateProducer(
+ ImmutableMap.<Integer, Producer<String>>of(
+ 15,
+ Producers.<String>immediateProducer("fifteen"),
+ 42,
+ Producers.<String>immediateFailedProducer(cause))));
+ try {
+ mapProducer.get().get();
+ fail();
+ } catch (ExecutionException e) {
+ assertThat(e.getCause()).isSameAs(cause);
+ }
+ }
+
+ @Test
+ public void failingInput() throws Exception {
+ RuntimeException cause = new RuntimeException("monkey");
+ Producer<Map<Integer, String>> mapProducer =
+ MapProducer.create(
+ Producers.<Map<Integer, Producer<String>>>immediateFailedProducer(cause));
try {
mapProducer.get().get();
fail();