1 /* 2 * Copyright (C) 2015 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.internal.codegen.binding; 18 19 import static com.google.common.base.Preconditions.checkArgument; 20 21 import androidx.room.compiler.processing.XMethodElement; 22 import androidx.room.compiler.processing.XMethodType; 23 import androidx.room.compiler.processing.XType; 24 import androidx.room.compiler.processing.XTypeElement; 25 import com.google.auto.value.AutoValue; 26 import com.google.auto.value.extension.memoized.Memoized; 27 import dagger.internal.codegen.base.ContributionType; 28 import dagger.internal.codegen.base.ContributionType.HasContributionType; 29 import dagger.internal.codegen.base.MapType; 30 import dagger.internal.codegen.base.SetType; 31 import dagger.internal.codegen.javapoet.TypeNames; 32 import dagger.internal.codegen.model.Key; 33 import dagger.multibindings.Multibinds; 34 import java.util.Map; 35 import java.util.Optional; 36 import java.util.Set; 37 import javax.inject.Inject; 38 39 /** 40 * A declaration that a multibinding with a certain key is available to be injected in a component 41 * even if the component has no multibindings for that key. Identified by a map- or set-returning 42 * method annotated with {@link Multibinds @Multibinds}. 43 */ 44 @AutoValue 45 public abstract class MultibindingDeclaration extends BindingDeclaration 46 implements HasContributionType { 47 48 /** 49 * The map or set key whose availability is declared. For maps, this will be {@code Map<K, 50 * Provider<V>>}. For sets, this will be {@code Set<T>}. 51 */ 52 @Override key()53 public abstract Key key(); 54 55 /** 56 * {@link ContributionType#SET} if the declared type is a {@link Set}, or 57 * {@link ContributionType#MAP} if it is a {@link Map}. 58 */ 59 @Override contributionType()60 public abstract ContributionType contributionType(); 61 62 @Memoized 63 @Override hashCode()64 public abstract int hashCode(); 65 66 @Override equals(Object obj)67 public abstract boolean equals(Object obj); 68 69 /** A factory for {@link MultibindingDeclaration}s. */ 70 public static final class Factory { 71 private final KeyFactory keyFactory; 72 73 @Inject Factory(KeyFactory keyFactory)74 Factory(KeyFactory keyFactory) { 75 this.keyFactory = keyFactory; 76 } 77 78 /** A multibinding declaration for a {@link Multibinds @Multibinds} method. */ forMultibindsMethod( XMethodElement moduleMethod, XTypeElement moduleElement)79 MultibindingDeclaration forMultibindsMethod( 80 XMethodElement moduleMethod, XTypeElement moduleElement) { 81 checkArgument(moduleMethod.hasAnnotation(TypeNames.MULTIBINDS)); 82 return forDeclaredMethod( 83 moduleMethod, moduleMethod.asMemberOf(moduleElement.getType()), moduleElement); 84 } 85 forDeclaredMethod( XMethodElement method, XMethodType methodType, XTypeElement contributingType)86 private MultibindingDeclaration forDeclaredMethod( 87 XMethodElement method, XMethodType methodType, XTypeElement contributingType) { 88 XType returnType = methodType.getReturnType(); 89 checkArgument( 90 SetType.isSet(returnType) || MapType.isMap(returnType), 91 "%s must return a set or map", 92 method); 93 return new AutoValue_MultibindingDeclaration( 94 Optional.of(method), 95 Optional.of(contributingType), 96 keyFactory.forMultibindsMethod(method, methodType), 97 contributionType(returnType)); 98 } 99 contributionType(XType returnType)100 private ContributionType contributionType(XType returnType) { 101 if (MapType.isMap(returnType)) { 102 return ContributionType.MAP; 103 } else if (SetType.isSet(returnType)) { 104 return ContributionType.SET; 105 } else { 106 throw new IllegalArgumentException("Must be Map or Set: " + returnType); 107 } 108 } 109 } 110 } 111