1 /* 2 * Copyright (C) 2014 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.auto.common.MoreTypes.isTypeOf; 20 import static com.google.common.base.Preconditions.checkArgument; 21 import static com.google.common.base.Preconditions.checkNotNull; 22 import static com.google.common.base.Preconditions.checkState; 23 import static com.google.common.collect.Iterables.getOnlyElement; 24 import static dagger.internal.codegen.base.RequestKinds.extractKeyType; 25 import static dagger.internal.codegen.base.RequestKinds.frameworkClass; 26 import static dagger.internal.codegen.base.RequestKinds.getRequestKind; 27 import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType; 28 import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType; 29 import static dagger.model.RequestKind.FUTURE; 30 import static dagger.model.RequestKind.INSTANCE; 31 import static dagger.model.RequestKind.MEMBERS_INJECTION; 32 import static dagger.model.RequestKind.PRODUCER; 33 import static dagger.model.RequestKind.PROVIDER; 34 35 import com.google.common.collect.ImmutableSet; 36 import com.google.common.util.concurrent.ListenableFuture; 37 import dagger.Lazy; 38 import dagger.internal.codegen.base.MapType; 39 import dagger.internal.codegen.base.OptionalType; 40 import dagger.model.DependencyRequest; 41 import dagger.model.Key; 42 import dagger.model.RequestKind; 43 import java.util.List; 44 import java.util.Optional; 45 import javax.inject.Inject; 46 import javax.inject.Provider; 47 import javax.lang.model.element.AnnotationMirror; 48 import javax.lang.model.element.Element; 49 import javax.lang.model.element.ExecutableElement; 50 import javax.lang.model.element.VariableElement; 51 import javax.lang.model.type.DeclaredType; 52 import javax.lang.model.type.ExecutableType; 53 import javax.lang.model.type.TypeMirror; 54 55 /** 56 * Factory for {@link DependencyRequest}s. 57 * 58 * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available, which 59 * may mean that the type will be generated in a later round of processing. 60 */ 61 public final class DependencyRequestFactory { 62 private final KeyFactory keyFactory; 63 private final InjectionAnnotations injectionAnnotations; 64 65 @Inject DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations)66 DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations) { 67 this.keyFactory = keyFactory; 68 this.injectionAnnotations = injectionAnnotations; 69 } 70 forRequiredResolvedVariables( List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes)71 ImmutableSet<DependencyRequest> forRequiredResolvedVariables( 72 List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) { 73 checkState(resolvedTypes.size() == variables.size()); 74 ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder(); 75 for (int i = 0; i < variables.size(); i++) { 76 builder.add(forRequiredResolvedVariable(variables.get(i), resolvedTypes.get(i))); 77 } 78 return builder.build(); 79 } 80 81 /** 82 * Creates synthetic dependency requests for each individual multibinding contribution in {@code 83 * multibindingContributions}. 84 */ forMultibindingContributions( Key multibindingKey, Iterable<ContributionBinding> multibindingContributions)85 ImmutableSet<DependencyRequest> forMultibindingContributions( 86 Key multibindingKey, Iterable<ContributionBinding> multibindingContributions) { 87 ImmutableSet.Builder<DependencyRequest> requests = ImmutableSet.builder(); 88 for (ContributionBinding multibindingContribution : multibindingContributions) { 89 requests.add(forMultibindingContribution(multibindingKey, multibindingContribution)); 90 } 91 return requests.build(); 92 } 93 94 /** Creates a synthetic dependency request for one individual {@code multibindingContribution}. */ forMultibindingContribution( Key multibindingKey, ContributionBinding multibindingContribution)95 private DependencyRequest forMultibindingContribution( 96 Key multibindingKey, ContributionBinding multibindingContribution) { 97 checkArgument( 98 multibindingContribution.key().multibindingContributionIdentifier().isPresent(), 99 "multibindingContribution's key must have a multibinding contribution identifier: %s", 100 multibindingContribution); 101 return DependencyRequest.builder() 102 .kind(multibindingContributionRequestKind(multibindingKey, multibindingContribution)) 103 .key(multibindingContribution.key()) 104 .build(); 105 } 106 107 // TODO(b/28555349): support PROVIDER_OF_LAZY here too 108 private static final ImmutableSet<RequestKind> WRAPPING_MAP_VALUE_FRAMEWORK_TYPES = 109 ImmutableSet.of(PROVIDER, PRODUCER); 110 multibindingContributionRequestKind( Key multibindingKey, ContributionBinding multibindingContribution)111 private RequestKind multibindingContributionRequestKind( 112 Key multibindingKey, ContributionBinding multibindingContribution) { 113 switch (multibindingContribution.contributionType()) { 114 case MAP: 115 MapType mapType = MapType.from(multibindingKey); 116 for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) { 117 if (mapType.valuesAreTypeOf(frameworkClass(kind))) { 118 return kind; 119 } 120 } 121 // fall through 122 case SET: 123 case SET_VALUES: 124 return INSTANCE; 125 case UNIQUE: 126 throw new IllegalArgumentException( 127 "multibindingContribution must be a multibinding: " + multibindingContribution); 128 } 129 throw new AssertionError(multibindingContribution.toString()); 130 } 131 forRequiredResolvedVariable( VariableElement variableElement, TypeMirror resolvedType)132 DependencyRequest forRequiredResolvedVariable( 133 VariableElement variableElement, TypeMirror resolvedType) { 134 checkNotNull(variableElement); 135 checkNotNull(resolvedType); 136 // Ban @Assisted parameters, they are not considered dependency requests. 137 checkArgument(!AssistedInjectionAnnotations.isAssistedParameter(variableElement)); 138 Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(variableElement); 139 return newDependencyRequest(variableElement, resolvedType, qualifier); 140 } 141 forComponentProvisionMethod( ExecutableElement provisionMethod, ExecutableType provisionMethodType)142 public DependencyRequest forComponentProvisionMethod( 143 ExecutableElement provisionMethod, ExecutableType provisionMethodType) { 144 checkNotNull(provisionMethod); 145 checkNotNull(provisionMethodType); 146 checkArgument( 147 provisionMethod.getParameters().isEmpty(), 148 "Component provision methods must be empty: %s", 149 provisionMethod); 150 Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(provisionMethod); 151 return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier); 152 } 153 forComponentProductionMethod( ExecutableElement productionMethod, ExecutableType productionMethodType)154 public DependencyRequest forComponentProductionMethod( 155 ExecutableElement productionMethod, ExecutableType productionMethodType) { 156 checkNotNull(productionMethod); 157 checkNotNull(productionMethodType); 158 checkArgument( 159 productionMethod.getParameters().isEmpty(), 160 "Component production methods must be empty: %s", 161 productionMethod); 162 TypeMirror type = productionMethodType.getReturnType(); 163 Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(productionMethod); 164 // Only a component production method can be a request for a ListenableFuture, so we 165 // special-case it here. 166 if (isTypeOf(ListenableFuture.class, type)) { 167 return DependencyRequest.builder() 168 .kind(FUTURE) 169 .key(keyFactory.forQualifiedType(qualifier, unwrapType(type))) 170 .requestElement(productionMethod) 171 .build(); 172 } else { 173 return newDependencyRequest(productionMethod, type, qualifier); 174 } 175 } 176 forComponentMembersInjectionMethod( ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType)177 DependencyRequest forComponentMembersInjectionMethod( 178 ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType) { 179 checkNotNull(membersInjectionMethod); 180 checkNotNull(membersInjectionMethodType); 181 Optional<AnnotationMirror> qualifier = 182 injectionAnnotations.getQualifier(membersInjectionMethod); 183 checkArgument(!qualifier.isPresent()); 184 TypeMirror membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes()); 185 return DependencyRequest.builder() 186 .kind(MEMBERS_INJECTION) 187 .key(keyFactory.forMembersInjectedType(membersInjectedType)) 188 .requestElement(membersInjectionMethod) 189 .build(); 190 } 191 forProductionImplementationExecutor()192 DependencyRequest forProductionImplementationExecutor() { 193 return DependencyRequest.builder() 194 .kind(PROVIDER) 195 .key(keyFactory.forProductionImplementationExecutor()) 196 .build(); 197 } 198 forProductionComponentMonitor()199 DependencyRequest forProductionComponentMonitor() { 200 return DependencyRequest.builder() 201 .kind(PROVIDER) 202 .key(keyFactory.forProductionComponentMonitor()) 203 .build(); 204 } 205 206 /** 207 * Returns a synthetic request for the present value of an optional binding generated from a 208 * {@link dagger.BindsOptionalOf} declaration. 209 */ forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind)210 DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind) { 211 Optional<Key> key = keyFactory.unwrapOptional(requestKey); 212 checkArgument(key.isPresent(), "not a request for optional: %s", requestKey); 213 return DependencyRequest.builder() 214 .kind(kind) 215 .key(key.get()) 216 .isNullable( 217 allowsNull(getRequestKind(OptionalType.from(requestKey).valueType()), Optional.empty())) 218 .build(); 219 } 220 newDependencyRequest( Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier)221 private DependencyRequest newDependencyRequest( 222 Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier) { 223 RequestKind requestKind = getRequestKind(type); 224 return DependencyRequest.builder() 225 .kind(requestKind) 226 .key(keyFactory.forQualifiedType(qualifier, extractKeyType(type))) 227 .requestElement(requestElement) 228 .isNullable(allowsNull(requestKind, getNullableType(requestElement))) 229 .build(); 230 } 231 232 /** 233 * Returns {@code true} if a given request element allows null values. {@link 234 * RequestKind#INSTANCE} requests must be annotated with {@code @Nullable} in order to allow null 235 * values. All other request kinds implicitly allow null values because they are are wrapped 236 * inside {@link Provider}, {@link Lazy}, etc. 237 */ allowsNull(RequestKind kind, Optional<DeclaredType> nullableType)238 private boolean allowsNull(RequestKind kind, Optional<DeclaredType> nullableType) { 239 return nullableType.isPresent() || !kind.equals(INSTANCE); 240 } 241 } 242