1 /* 2 * Copyright (C) 2016 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.producers.internal; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static dagger.producers.internal.Producers.producerFromProvider; 21 22 import com.google.common.collect.ImmutableMap; 23 import dagger.producers.Producer; 24 import java.util.Map; 25 import javax.inject.Provider; 26 27 /** 28 * An {@code abstract} {@link Producer} implementation used to implement {@link Map} bindings. 29 * 30 * @param <K>The key type of the map that this produces 31 * @param <V>The type that each contributing producer 32 * @param <V2>The value type of the map that this produces. For {@link MapProducer}, {@code V} and 33 * {@code V2} will be equivalent. 34 */ 35 abstract class AbstractMapProducer<K, V, V2> extends AbstractProducer<Map<K, V2>> { 36 private final ImmutableMap<K, Producer<V>> contributingMap; 37 AbstractMapProducer(ImmutableMap<K, Producer<V>> contributingMap)38 AbstractMapProducer(ImmutableMap<K, Producer<V>> contributingMap) { 39 this.contributingMap = contributingMap; 40 } 41 42 /** The map of {@link Producer}s that contribute to this map binding. */ contributingMap()43 final ImmutableMap<K, Producer<V>> contributingMap() { 44 return contributingMap; 45 } 46 47 /** A builder for {@link AbstractMapProducer} */ 48 public abstract static class Builder<K, V, V2> { 49 final ImmutableMap.Builder<K, Producer<V>> mapBuilder; 50 Builder(int size)51 Builder(int size) { 52 mapBuilder = ImmutableMap.builderWithExpectedSize(size); 53 } 54 55 // Unfortunately, we cannot return a self-type here because a raw Producer type passed to one of 56 // these methods affects the returned type of the method. The first put*() call erases the self 57 // type to the "raw" self type, and the second erases the type to the upper bound 58 // (AbstractMapProducer.Builder), which doesn't have a build() method. 59 // 60 // The methods are therefore not declared public so that each subtype will redeclare them and 61 // expand their accessibility 62 63 /** Associates {@code key} with {@code producerOfValue}. */ put(K key, Producer<V> producerOfValue)64 Builder<K, V, V2> put(K key, Producer<V> producerOfValue) { 65 checkNotNull(key, "key"); 66 checkNotNull(producerOfValue, "producer of value"); 67 mapBuilder.put(key, producerOfValue); 68 return this; 69 } 70 71 /** Associates {@code key} with {@code providerOfValue}. */ put(K key, Provider<V> providerOfValue)72 Builder<K, V, V2> put(K key, Provider<V> providerOfValue) { 73 checkNotNull(key, "key"); 74 checkNotNull(providerOfValue, "provider of value"); 75 mapBuilder.put(key, producerFromProvider(providerOfValue)); 76 return this; 77 } 78 79 /** Adds contributions from a super-implementation of a component into this builder. */ putAll(Producer<Map<K, V2>> mapOfProducers)80 Builder<K, V, V2> putAll(Producer<Map<K, V2>> mapOfProducers) { 81 if (mapOfProducers instanceof DelegateProducer) { 82 @SuppressWarnings("unchecked") 83 DelegateProducer<Map<K, V2>> asDelegateProducer = (DelegateProducer) mapOfProducers; 84 return putAll(asDelegateProducer.getDelegate()); 85 } 86 @SuppressWarnings("unchecked") 87 AbstractMapProducer<K, V, ?> asAbstractMapProducer = 88 ((AbstractMapProducer<K, V, ?>) (Producer) mapOfProducers); 89 mapBuilder.putAll(asAbstractMapProducer.contributingMap); 90 return this; 91 } 92 } 93 } 94