All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dagger.internal.codegen.binding.DependencyRequestFactory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014 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.binding;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
import static dagger.internal.codegen.base.RequestKinds.frameworkClassName;
import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
import static dagger.internal.codegen.model.RequestKind.FUTURE;
import static dagger.internal.codegen.model.RequestKind.INSTANCE;
import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
import static dagger.internal.codegen.model.RequestKind.PRODUCER;
import static dagger.internal.codegen.model.RequestKind.PROVIDER;
import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
import static dagger.internal.codegen.xprocessing.XTypes.unwrapType;

import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XMethodType;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableSet;
import dagger.Lazy;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DaggerElement;
import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.model.RequestKind;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Provider;

/**
 * Factory for {@link DependencyRequest}s.
 *
 * 

Any factory method may throw {@link TypeNotPresentException} if a type is not available, which * may mean that the type will be generated in a later round of processing. */ public final class DependencyRequestFactory { private final KeyFactory keyFactory; private final InjectionAnnotations injectionAnnotations; @Inject DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations) { this.keyFactory = keyFactory; this.injectionAnnotations = injectionAnnotations; } ImmutableSet forRequiredResolvedVariables( List variables, List resolvedTypes) { checkState(resolvedTypes.size() == variables.size()); ImmutableSet.Builder builder = ImmutableSet.builder(); for (int i = 0; i < variables.size(); i++) { builder.add(forRequiredResolvedVariable(variables.get(i), resolvedTypes.get(i))); } return builder.build(); } /** * Creates synthetic dependency requests for each individual multibinding contribution in {@code * multibindingContributions}. */ ImmutableSet forMultibindingContributions( Key multibindingKey, Iterable multibindingContributions) { ImmutableSet.Builder requests = ImmutableSet.builder(); for (ContributionBinding multibindingContribution : multibindingContributions) { requests.add(forMultibindingContribution(multibindingKey, multibindingContribution)); } return requests.build(); } /** Creates a synthetic dependency request for one individual {@code multibindingContribution}. */ private DependencyRequest forMultibindingContribution( Key multibindingKey, ContributionBinding multibindingContribution) { checkArgument( multibindingContribution.key().multibindingContributionIdentifier().isPresent(), "multibindingContribution's key must have a multibinding contribution identifier: %s", multibindingContribution); return DependencyRequest.builder() .kind(multibindingContributionRequestKind(multibindingKey, multibindingContribution)) .key(multibindingContribution.key()) .build(); } // TODO(b/28555349): support PROVIDER_OF_LAZY here too private static final ImmutableSet WRAPPING_MAP_VALUE_FRAMEWORK_TYPES = ImmutableSet.of(PROVIDER, PRODUCER); private RequestKind multibindingContributionRequestKind( Key multibindingKey, ContributionBinding multibindingContribution) { switch (multibindingContribution.contributionType()) { case MAP: MapType mapType = MapType.from(multibindingKey); for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) { if (mapType.valuesAreTypeOf(frameworkClassName(kind))) { return kind; } } // fall through case SET: case SET_VALUES: return INSTANCE; case UNIQUE: throw new IllegalArgumentException( "multibindingContribution must be a multibinding: " + multibindingContribution); } throw new AssertionError(multibindingContribution.toString()); } DependencyRequest forRequiredResolvedVariable( XVariableElement variableElement, XType resolvedType) { checkNotNull(variableElement); checkNotNull(resolvedType); // Ban @Assisted parameters, they are not considered dependency requests. checkArgument(!isAssistedParameter(variableElement)); Optional qualifier = injectionAnnotations.getQualifier(variableElement); return newDependencyRequest(variableElement, resolvedType, qualifier); } public DependencyRequest forComponentProvisionMethod( XMethodElement provisionMethod, XMethodType provisionMethodType) { checkNotNull(provisionMethod); checkNotNull(provisionMethodType); checkArgument( provisionMethod.getParameters().isEmpty(), "Component provision methods must be empty: %s", provisionMethod); Optional qualifier = injectionAnnotations.getQualifier(provisionMethod); return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier); } public DependencyRequest forComponentProductionMethod( XMethodElement productionMethod, XMethodType productionMethodType) { checkNotNull(productionMethod); checkNotNull(productionMethodType); checkArgument( productionMethod.getParameters().isEmpty(), "Component production methods must be empty: %s", productionMethod); XType type = productionMethodType.getReturnType(); Optional qualifier = injectionAnnotations.getQualifier(productionMethod); // Only a component production method can be a request for a ListenableFuture, so we // special-case it here. if (isTypeOf(type, TypeNames.LISTENABLE_FUTURE)) { return DependencyRequest.builder() .kind(FUTURE) .key(keyFactory.forQualifiedType(qualifier, unwrapType(type))) .requestElement(DaggerElement.from(productionMethod)) .build(); } else { return newDependencyRequest(productionMethod, type, qualifier); } } DependencyRequest forComponentMembersInjectionMethod( XMethodElement membersInjectionMethod, XMethodType membersInjectionMethodType) { checkNotNull(membersInjectionMethod); checkNotNull(membersInjectionMethodType); Optional qualifier = injectionAnnotations.getQualifier(membersInjectionMethod); checkArgument(!qualifier.isPresent()); XType membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes()); return DependencyRequest.builder() .kind(MEMBERS_INJECTION) .key(keyFactory.forMembersInjectedType(membersInjectedType)) .requestElement(DaggerElement.from(membersInjectionMethod)) .build(); } DependencyRequest forProductionImplementationExecutor() { return DependencyRequest.builder() .kind(PROVIDER) .key(keyFactory.forProductionImplementationExecutor()) .build(); } DependencyRequest forProductionComponentMonitor() { return DependencyRequest.builder() .kind(PROVIDER) .key(keyFactory.forProductionComponentMonitor()) .build(); } /** * Returns a synthetic request for the present value of an optional binding generated from a * {@link dagger.BindsOptionalOf} declaration. */ DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind) { Optional key = keyFactory.unwrapOptional(requestKey); checkArgument(key.isPresent(), "not a request for optional: %s", requestKey); return DependencyRequest.builder() .kind(kind) .key(key.get()) .isNullable( requestKindImplicitlyAllowsNull( getRequestKind(OptionalType.from(requestKey).valueType()))) .build(); } private DependencyRequest newDependencyRequest( XElement requestElement, XType type, Optional qualifier) { RequestKind requestKind = getRequestKind(type); return DependencyRequest.builder() .kind(requestKind) .key(keyFactory.forQualifiedType(qualifier, extractKeyType(type))) .requestElement(DaggerElement.from(requestElement)) .isNullable(allowsNull(requestKind, Nullability.of(requestElement))) .build(); } /** * Returns {@code true} if a given request element allows null values. {@link * RequestKind#INSTANCE} requests must be nullable in order to allow null values. All other * request kinds implicitly allow null values because they are are wrapped inside {@link * Provider}, {@link Lazy}, etc. */ private boolean allowsNull(RequestKind kind, Nullability nullability) { return nullability.isNullable() || requestKindImplicitlyAllowsNull(kind); } private boolean requestKindImplicitlyAllowsNull(RequestKind kind) { return !kind.equals(INSTANCE); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy