dagger.internal.codegen.binding.ComponentDescriptor Maven / Gradle / Ivy
Show all versions of dagger-compiler Show documentation
/*
* 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 androidx.room.compiler.processing.XElementKt.isMethod;
import static androidx.room.compiler.processing.XTypeKt.isVoid;
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.ComponentAnnotation.rootComponentAnnotation;
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations;
import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
import static dagger.internal.codegen.base.Scopes.productionScope;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.javapoet.TypeNames.isFutureType;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XMethodType;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.squareup.javapoet.TypeName;
import dagger.Component;
import dagger.Module;
import dagger.Subcomponent;
import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.base.ComponentAnnotation;
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XTypeElements;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* A component declaration.
*
* Represents one type annotated with {@code @Component}, {@code Subcomponent},
* {@code @ProductionComponent}, or {@code @ProductionSubcomponent}.
*
*
When validating bindings installed in modules, a {@link ComponentDescriptor} can also
* represent a synthetic component for the module, where there is an entry point for each binding in
* the module.
*/
@CheckReturnValue
@AutoValue
public abstract class ComponentDescriptor {
private BindingFactory bindingFactory;
/** The annotation that specifies that {@link #typeElement()} is a component. */
public abstract ComponentAnnotation annotation();
/**
* The element that defines the component. This is the element to which the {@link #annotation()}
* was applied.
*/
public abstract XTypeElement typeElement();
/**
* The set of component dependencies listed in {@link Component#dependencies} or {@link
* dagger.producers.ProductionComponent#dependencies()}.
*/
public abstract ImmutableSet dependencies();
/**
* The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by
* traversing {@link Module#includes()}.
*/
public abstract ImmutableSet modules();
/** The scopes of the component. */
public abstract ImmutableSet scopes();
/**
* All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain
* Module#subcomponents() module's subcomponents}.
*/
abstract ImmutableSet childComponentsDeclaredByModules();
/**
* All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
* factory method.
*/
public abstract ImmutableBiMap
childComponentsDeclaredByFactoryMethods();
/**
* All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
* builder method.
*/
abstract ImmutableMap
childComponentsDeclaredByBuilderEntryPoints();
public abstract ImmutableSet componentMethods();
/** Returns a descriptor for the creator type for this component type, if the user defined one. */
public abstract Optional creatorDescriptor();
/** Returns {@code true} if this is a subcomponent. */
public final boolean isSubcomponent() {
return annotation().isSubcomponent();
}
/**
* Returns {@code true} if this is a production component or subcomponent, or a
* {@code @ProducerModule} when doing module binding validation.
*/
public final boolean isProduction() {
return annotation().isProduction();
}
/**
* Returns {@code true} if this is a real component, and not a fictional one used to validate
* module bindings.
*/
public final boolean isRealComponent() {
return annotation().isRealComponent();
}
/** The non-abstract {@link #modules()} and the {@link #dependencies()}. */
public final ImmutableSet dependenciesAndConcreteModules() {
return Stream.concat(
moduleTypes().stream()
.filter(dep -> !dep.isAbstract())
.map(module -> ComponentRequirement.forModule(module.getType())),
dependencies().stream())
.collect(toImmutableSet());
}
/** The types of the {@link #modules()}. */
public final ImmutableSet moduleTypes() {
return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
}
/**
* The types for which the component will need instances if all of its bindings are used. For the
* types the component will need in a given binding graph, use {@link
* BindingGraph#componentRequirements()}.
*
*
* - {@linkplain #modules()} modules} with concrete instance bindings
*
- Bound instances
*
- {@linkplain #dependencies() dependencies}
*
*/
@Memoized
ImmutableSet requirements() {
ImmutableSet.Builder requirements = ImmutableSet.builder();
modules().stream()
.filter(
module ->
module.bindings().stream().anyMatch(ContributionBinding::requiresModuleInstance))
.map(module -> ComponentRequirement.forModule(module.moduleElement().getType()))
.forEach(requirements::add);
requirements.addAll(dependencies());
requirements.addAll(
creatorDescriptor()
.map(ComponentCreatorDescriptor::boundInstanceRequirements)
.orElse(ImmutableSet.of()));
return requirements.build();
}
/**
* Returns this component's dependencies keyed by its provision/production method.
*
* Note that the dependencies' types are not simply the enclosing type of the method; a method
* may be declared by a supertype of the actual dependency.
*/
@Memoized
public ImmutableMap dependenciesByDependencyMethod() {
ImmutableMap.Builder builder = ImmutableMap.builder();
for (ComponentRequirement componentDependency : dependencies()) {
XTypeElements.getAllMethods(componentDependency.typeElement()).stream()
.filter(ComponentDescriptor::isComponentContributionMethod)
.forEach(method -> builder.put(method, componentDependency));
}
return builder.buildOrThrow();
}
/** The {@linkplain #dependencies() component dependency} that defines a method. */
public final ComponentRequirement getDependencyThatDefinesMethod(XElement method) {
checkArgument(isMethod(method), "method must be an executable element: %s", method);
checkState(
dependenciesByDependencyMethod().containsKey(method),
"no dependency implements %s",
method);
return dependenciesByDependencyMethod().get(method);
}
/**
* All {@link Subcomponent}s which are direct children of this component. This includes
* subcomponents installed from {@link Module#subcomponents()} as well as subcomponent {@linkplain
* #childComponentsDeclaredByFactoryMethods() factory methods} and {@linkplain
* #childComponentsDeclaredByBuilderEntryPoints() builder methods}.
*/
public final ImmutableSet childComponents() {
return ImmutableSet.builder()
.addAll(childComponentsDeclaredByFactoryMethods().values())
.addAll(childComponentsDeclaredByBuilderEntryPoints().values())
.addAll(childComponentsDeclaredByModules())
.build();
}
/** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */
@Memoized
public ImmutableMap childComponentsByElement() {
return Maps.uniqueIndex(childComponents(), ComponentDescriptor::typeElement);
}
/** Returns the factory method that declares a child component. */
final Optional getFactoryMethodForChildComponent(
ComponentDescriptor childComponent) {
return Optional.ofNullable(
childComponentsDeclaredByFactoryMethods().inverse().get(childComponent));
}
private final Supplier>
childComponentsByBuilderType =
Suppliers.memoize(
() ->
childComponents().stream()
.filter(child -> child.creatorDescriptor().isPresent())
.collect(
toImmutableMap(
child -> child.creatorDescriptor().get().typeElement(),
child -> child)));
/** Returns the child component with the given builder type. */
final ComponentDescriptor getChildComponentWithBuilderType(XTypeElement builderType) {
return checkNotNull(
childComponentsByBuilderType.get().get(builderType),
"no child component found for builder type %s",
builderType.getQualifiedName());
}
/** Returns the first component method associated with this binding request, if one exists. */
public Optional firstMatchingComponentMethod(BindingRequest request) {
return Optional.ofNullable(firstMatchingComponentMethods().get(request));
}
@Memoized
ImmutableMap firstMatchingComponentMethods() {
Map methods = new HashMap<>();
for (ComponentMethodDescriptor method : entryPointMethods()) {
methods.putIfAbsent(BindingRequest.bindingRequest(method.dependencyRequest().get()), method);
}
return ImmutableMap.copyOf(methods);
}
/** The entry point methods on the component type. Each has a {@link DependencyRequest}. */
public final ImmutableSet entryPointMethods() {
return componentMethods().stream()
.filter(method -> method.dependencyRequest().isPresent())
.collect(toImmutableSet());
}
/**
* Returns {@code true} for components that have a creator, either because the user {@linkplain
* #creatorDescriptor() specified one} or because it's a top-level component with an implicit
* builder.
*/
public final boolean hasCreator() {
return !isSubcomponent() || creatorDescriptor().isPresent();
}
/**
* Returns the {@link CancellationPolicy} for this component, or an empty optional if either the
* component is not a production component or no {@code CancellationPolicy} annotation is present.
*/
public final Optional cancellationPolicy() {
return isProduction()
// TODO(bcorso): Get values from XAnnotation instead of using CancellationPolicy directly.
? Optional.ofNullable(typeElement().getAnnotation(TypeNames.CANCELLATION_POLICY))
.map(CancellationPolicy::from)
: Optional.empty();
}
/** Returns the bindings for the component. */
@Memoized
public ImmutableSet bindings() {
ImmutableSet.Builder builder = ImmutableSet.builder();
componentBinding().ifPresent(builder::add);
return builder
.addAll(componentDependencyBindings())
.addAll(boundInstanceBindings())
.addAll(subcomponentCreatorBindings())
.addAll(moduleBindings())
.build();
}
/** Returns the binding for the component, itself, if this is a real component. */
@Memoized
Optional componentBinding() {
return isRealComponent()
? Optional.of(bindingFactory.componentBinding(typeElement()))
: Optional.empty();
}
/** Returns the bindings for the component dependency and those contributed by its methods. */
@Memoized
ImmutableSet componentDependencyBindings() {
ImmutableSet.Builder builder = ImmutableSet.builder();
for (ComponentRequirement dependency : dependencies()) {
builder.add(bindingFactory.componentDependencyBinding(dependency));
// Within a component dependency, we want to allow the same method to appear multiple
// times assuming it is the exact same method. We do this by tracking a set of bindings
// we've already added with the binding element removed since that is the only thing
// allowed to differ.
HashMultimap dedupeBindings = HashMultimap.create();
XTypeElements.getAllMethods(dependency.typeElement()).stream()
// MembersInjection methods aren't "provided" explicitly, so ignore them.
.filter(ComponentDescriptor::isComponentContributionMethod)
.forEach(
method -> {
ContributionBinding binding =
isProduction() && isComponentProductionMethod(method)
? bindingFactory.componentDependencyProductionMethodBinding(method)
: bindingFactory.componentDependencyProvisionMethodBinding(method);
if (dedupeBindings.put(
getSimpleName(method),
// Remove the binding element since we know that will be different, but
// everything else we want to be the same to consider it a duplicate.
binding.toBuilder().clearBindingElement().build())) {
builder.add(binding);
}
});
}
return builder.build();
}
/** Returns the {@code @BindsInstance} bindings required to create this component. */
@Memoized
ImmutableSet boundInstanceBindings() {
return creatorDescriptor().isPresent()
? creatorDescriptor().get().boundInstanceRequirements().stream()
.map(
requirement ->
bindingFactory.boundInstanceBinding(
requirement,
creatorDescriptor().get().elementForRequirement(requirement)))
.collect(toImmutableSet())
: ImmutableSet.of();
}
/** Returns the subcomponent creator bindings for this component. */
@Memoized
ImmutableSet subcomponentCreatorBindings() {
ImmutableSet.Builder builder = ImmutableSet.builder();
childComponentsDeclaredByBuilderEntryPoints()
.forEach(
(builderEntryPoint, childComponent) -> {
if (!childComponentsDeclaredByModules().contains(childComponent)) {
builder.add(
bindingFactory.subcomponentCreatorBinding(
builderEntryPoint.methodElement(), typeElement()));
}
});
return builder.build();
}
@Memoized
ImmutableSet moduleBindings() {
return modules().stream()
.map(ModuleDescriptor::bindings)
.flatMap(ImmutableSet::stream)
.collect(toImmutableSet());
}
@Memoized
public ImmutableSet delegateDeclarations() {
return modules().stream()
.map(ModuleDescriptor::delegateDeclarations)
.flatMap(ImmutableSet::stream)
.collect(toImmutableSet());
}
@Memoized
public ImmutableSet multibindingDeclarations() {
return modules().stream()
.map(ModuleDescriptor::multibindingDeclarations)
.flatMap(ImmutableSet::stream)
.collect(toImmutableSet());
}
@Memoized
public ImmutableSet optionalBindingDeclarations() {
return modules().stream()
.map(ModuleDescriptor::optionalDeclarations)
.flatMap(ImmutableSet::stream)
.collect(toImmutableSet());
}
@Memoized
public ImmutableSet subcomponentDeclarations() {
return modules().stream()
.map(ModuleDescriptor::subcomponentDeclarations)
.flatMap(ImmutableSet::stream)
.collect(toImmutableSet());
}
@Memoized
@Override
public int hashCode() {
// TODO(b/122962745): Only use typeElement().hashCode()
return Objects.hash(typeElement(), annotation());
}
// TODO(ronshapiro): simplify the equality semantics
@Override
public abstract boolean equals(Object obj);
/** A component method. */
@AutoValue
public abstract static class ComponentMethodDescriptor {
/** The method itself. Note that this may be declared on a supertype of the component. */
public abstract XMethodElement methodElement();
/**
* The dependency request for production, provision, and subcomponent creator methods. Absent
* for subcomponent factory methods.
*/
public abstract Optional dependencyRequest();
/** The subcomponent for subcomponent factory methods and subcomponent creator methods. */
public abstract Optional subcomponent();
/** A {@link ComponentMethodDescriptor}builder for a method. */
public static Builder builder(XMethodElement method) {
return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder()
.methodElement(method);
}
/** A builder of {@link ComponentMethodDescriptor}s. */
@AutoValue.Builder
public interface Builder {
/** @see ComponentMethodDescriptor#methodElement() */
Builder methodElement(XMethodElement methodElement);
/**
* @see ComponentMethodDescriptor#dependencyRequest()
*/
@CanIgnoreReturnValue // TODO(kak): remove this once open-source checkers understand AutoValue
Builder dependencyRequest(DependencyRequest dependencyRequest);
/**
* @see ComponentMethodDescriptor#subcomponent()
*/
@CanIgnoreReturnValue // TODO(kak): remove this once open-source checkers understand AutoValue
Builder subcomponent(ComponentDescriptor subcomponent);
/** Builds the descriptor. */
ComponentMethodDescriptor build();
}
}
/** No-argument methods defined on {@link Object} that are ignored for contribution. */
private static final ImmutableSet NON_CONTRIBUTING_OBJECT_METHOD_NAMES =
ImmutableSet.of("toString", "hashCode", "clone", "getClass");
/**
* Returns {@code true} if a method could be a component entry point but not a members-injection
* method.
*/
private static boolean isComponentContributionMethod(XMethodElement method) {
return method.getParameters().isEmpty()
&& !isVoid(method.getReturnType())
&& !method.getEnclosingElement().getClassName().equals(TypeName.OBJECT)
&& !NON_CONTRIBUTING_OBJECT_METHOD_NAMES.contains(getSimpleName(method));
}
/** Returns {@code true} if a method could be a component production entry point. */
private static boolean isComponentProductionMethod(XMethodElement method) {
return isComponentContributionMethod(method) && isFutureType(method.getReturnType());
}
/** A factory for creating a {@link ComponentDescriptor}. */
@Singleton
public static final class Factory implements ClearableCache {
private final XProcessingEnv processingEnv;
private final BindingFactory bindingFactory;
private final DependencyRequestFactory dependencyRequestFactory;
private final ModuleDescriptor.Factory moduleDescriptorFactory;
private final InjectionAnnotations injectionAnnotations;
private final DaggerSuperficialValidation superficialValidation;
private final Map cache = new HashMap<>();
@Inject
Factory(
XProcessingEnv processingEnv,
BindingFactory bindingFactory,
DependencyRequestFactory dependencyRequestFactory,
ModuleDescriptor.Factory moduleDescriptorFactory,
InjectionAnnotations injectionAnnotations,
DaggerSuperficialValidation superficialValidation) {
this.processingEnv = processingEnv;
this.bindingFactory = bindingFactory;
this.dependencyRequestFactory = dependencyRequestFactory;
this.moduleDescriptorFactory = moduleDescriptorFactory;
this.injectionAnnotations = injectionAnnotations;
this.superficialValidation = superficialValidation;
}
/** Returns a descriptor for a root component type. */
public ComponentDescriptor rootComponentDescriptor(XTypeElement typeElement) {
Optional annotation =
rootComponentAnnotation(typeElement, superficialValidation);
checkArgument(annotation.isPresent(), "%s must have a component annotation", typeElement);
return create(typeElement, annotation.get());
}
/** Returns a descriptor for a subcomponent type. */
public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) {
Optional annotation =
subcomponentAnnotation(typeElement, superficialValidation);
checkArgument(annotation.isPresent(), "%s must have a subcomponent annotation", typeElement);
return create(typeElement, annotation.get());
}
/**
* Returns a descriptor for a fictional component based on a module type in order to validate
* its bindings.
*/
public ComponentDescriptor moduleComponentDescriptor(XTypeElement typeElement) {
Optional annotation = moduleAnnotation(typeElement, superficialValidation);
checkArgument(annotation.isPresent(), "%s must have a module annotation", typeElement);
return create(typeElement, ComponentAnnotation.fromModuleAnnotation(annotation.get()));
}
private ComponentDescriptor create(
XTypeElement typeElement, ComponentAnnotation componentAnnotation) {
return reentrantComputeIfAbsent(
cache, typeElement, unused -> createUncached(typeElement, componentAnnotation));
}
private ComponentDescriptor createUncached(
XTypeElement typeElement, ComponentAnnotation componentAnnotation) {
ImmutableSet componentDependencies =
componentAnnotation.dependencyTypes().stream()
.map(ComponentRequirement::forDependency)
.collect(toImmutableSet());
// Start with the component's modules. For fictional components built from a module, start
// with that module.
ImmutableSet modules =
componentAnnotation.isRealComponent()
? componentAnnotation.modules()
: ImmutableSet.of(typeElement);
ImmutableSet transitiveModules =
moduleDescriptorFactory.transitiveModules(modules);
ImmutableSet.Builder componentMethodsBuilder =
ImmutableSet.builder();
ImmutableBiMap.Builder
subcomponentsByFactoryMethod = ImmutableBiMap.builder();
ImmutableMap.Builder
subcomponentsByBuilderMethod = ImmutableBiMap.builder();
if (componentAnnotation.isRealComponent()) {
for (XMethodElement componentMethod : getAllUnimplementedMethods(typeElement)) {
ComponentMethodDescriptor componentMethodDescriptor =
getDescriptorForComponentMethod(componentAnnotation, typeElement, componentMethod);
componentMethodsBuilder.add(componentMethodDescriptor);
componentMethodDescriptor
.subcomponent()
.ifPresent(
subcomponent -> {
// If the dependency request is present, that means the method returns the
// subcomponent factory.
if (componentMethodDescriptor.dependencyRequest().isPresent()) {
subcomponentsByBuilderMethod.put(componentMethodDescriptor, subcomponent);
} else {
subcomponentsByFactoryMethod.put(componentMethodDescriptor, subcomponent);
}
});
}
}
// Validation should have ensured that this set will have at most one element.
ImmutableSet enclosedCreators =
enclosedAnnotatedTypes(typeElement, creatorAnnotationsFor(componentAnnotation));
Optional creatorDescriptor =
enclosedCreators.isEmpty()
? Optional.empty()
: Optional.of(
ComponentCreatorDescriptor.create(
getOnlyElement(enclosedCreators), dependencyRequestFactory));
ImmutableSet scopes = injectionAnnotations.getScopes(typeElement);
if (componentAnnotation.isProduction()) {
scopes =
ImmutableSet.builder()
.addAll(scopes).add(productionScope(processingEnv))
.build();
}
ImmutableSet subcomponentsFromModules =
transitiveModules.stream()
.flatMap(transitiveModule -> transitiveModule.subcomponentDeclarations().stream())
.map(SubcomponentDeclaration::subcomponentType)
.map(this::subcomponentDescriptor)
.collect(toImmutableSet());
ComponentDescriptor componentDescriptor =
new AutoValue_ComponentDescriptor(
componentAnnotation,
typeElement,
componentDependencies,
transitiveModules,
scopes,
subcomponentsFromModules,
subcomponentsByFactoryMethod.buildOrThrow(),
subcomponentsByBuilderMethod.buildOrThrow(),
componentMethodsBuilder.build(),
creatorDescriptor);
componentDescriptor.bindingFactory = bindingFactory;
return componentDescriptor;
}
private ComponentMethodDescriptor getDescriptorForComponentMethod(
ComponentAnnotation componentAnnotation,
XTypeElement componentElement,
XMethodElement componentMethod) {
ComponentMethodDescriptor.Builder descriptor =
ComponentMethodDescriptor.builder(componentMethod);
XMethodType resolvedComponentMethod = componentMethod.asMemberOf(componentElement.getType());
XType returnType = resolvedComponentMethod.getReturnType();
if (isDeclared(returnType)
&& !injectionAnnotations.getQualifier(componentMethod).isPresent()) {
XTypeElement returnTypeElement = returnType.getTypeElement();
if (returnTypeElement.hasAnyAnnotation(subcomponentAnnotations())) {
// It's a subcomponent factory method. There is no dependency request, and there could be
// any number of parameters. Just return the descriptor.
return descriptor.subcomponent(subcomponentDescriptor(returnTypeElement)).build();
}
if (isSubcomponentCreator(returnTypeElement)) {
descriptor.subcomponent(
subcomponentDescriptor(returnTypeElement.getEnclosingTypeElement()));
}
}
switch (componentMethod.getParameters().size()) {
case 0:
checkArgument(
!isVoid(returnType), "component method cannot be void: %s", componentMethod);
descriptor.dependencyRequest(
componentAnnotation.isProduction()
? dependencyRequestFactory.forComponentProductionMethod(
componentMethod, resolvedComponentMethod)
: dependencyRequestFactory.forComponentProvisionMethod(
componentMethod, resolvedComponentMethod));
break;
case 1:
checkArgument(
isVoid(returnType)
// TODO(bcorso): Replace this with isSameType()?
|| returnType
.getTypeName()
.equals(resolvedComponentMethod.getParameterTypes().get(0).getTypeName()),
"members injection method must return void or parameter type: %s",
componentMethod);
descriptor.dependencyRequest(
dependencyRequestFactory.forComponentMembersInjectionMethod(
componentMethod, resolvedComponentMethod));
break;
default:
throw new IllegalArgumentException(
"component method has too many parameters: " + componentMethod);
}
return descriptor.build();
}
@Override
public void clearCache() {
cache.clear();
}
}
}