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: