• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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