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

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

/*
 * 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.Verify.verify;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.ComponentCreatorAnnotation.getCreatorAnnotations;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotations;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
import static dagger.internal.codegen.xprocessing.XTypes.isSubtype;

import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XExecutableParameterElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XMethodType;
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.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import dagger.internal.codegen.base.ComponentCreatorKind;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.xprocessing.XElements;
import java.util.List;

/**
 * A descriptor for a component creator type: that is, a type annotated with
 * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions).
 */
@AutoValue
public abstract class ComponentCreatorDescriptor {

  /** Returns the annotation marking this creator. */
  public abstract ComponentCreatorAnnotation annotation();

  /** The kind of this creator. */
  public final ComponentCreatorKind kind() {
    return annotation().creatorKind();
  }

  /** The annotated creator type. */
  public abstract XTypeElement typeElement();

  /** The method that creates and returns a component instance. */
  public abstract XMethodElement factoryMethod();

  /**
   * Multimap of component requirements to setter methods that set that requirement.
   *
   * 

In a valid creator, there will be exactly one element per component requirement, so this * method should only be called when validating the descriptor. */ abstract ImmutableSetMultimap unvalidatedSetterMethods(); /** * Multimap of component requirements to factory method parameters that set that requirement. * *

In a valid creator, there will be exactly one element per component requirement, so this * method should only be called when validating the descriptor. */ abstract ImmutableSetMultimap unvalidatedFactoryParameters(); /** * Multimap of component requirements to elements (methods or parameters) that set that * requirement. * *

In a valid creator, there will be exactly one element per component requirement, so this * method should only be called when validating the descriptor. */ public final ImmutableSetMultimap unvalidatedRequirementElements() { // ComponentCreatorValidator ensures that there are either setter methods or factory method // parameters, but not both, so we can cheat a little here since we know that only one of // the two multimaps will be non-empty. return ImmutableSetMultimap.copyOf( // no actual copy unvalidatedSetterMethods().isEmpty() ? unvalidatedFactoryParameters() : unvalidatedSetterMethods()); } /** * Map of component requirements to elements (setter methods or factory method parameters) that * set them. */ @Memoized ImmutableMap requirementElements() { return flatten(unvalidatedRequirementElements()); } /** Map of component requirements to setter methods for those requirements. */ @Memoized public ImmutableMap setterMethods() { return flatten(unvalidatedSetterMethods()); } /** Map of component requirements to factory method parameters for those requirements. */ @Memoized public ImmutableMap factoryParameters() { return flatten(unvalidatedFactoryParameters()); } private static ImmutableMap flatten(Multimap multimap) { return ImmutableMap.copyOf( Maps.transformValues(multimap.asMap(), values -> getOnlyElement(values))); } /** Returns the set of component requirements this creator allows the user to set. */ public final ImmutableSet userSettableRequirements() { // Note: they should have been validated at the point this is used, so this set is valid. return unvalidatedRequirementElements().keySet(); } /** Returns the set of requirements for modules and component dependencies for this creator. */ public final ImmutableSet moduleAndDependencyRequirements() { return userSettableRequirements().stream() .filter(requirement -> !requirement.isBoundInstance()) .collect(toImmutableSet()); } /** Returns the set of bound instance requirements for this creator. */ final ImmutableSet boundInstanceRequirements() { return userSettableRequirements().stream() .filter(ComponentRequirement::isBoundInstance) .collect(toImmutableSet()); } /** Returns the element in this creator that sets the given {@code requirement}. */ final XElement elementForRequirement(ComponentRequirement requirement) { return requirementElements().get(requirement); } /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */ public static ComponentCreatorDescriptor create( XTypeElement creator, DependencyRequestFactory dependencyRequestFactory) { XType componentType = creator.getEnclosingTypeElement().getType(); ImmutableSetMultimap.Builder setterMethods = ImmutableSetMultimap.builder(); XMethodElement factoryMethod = null; for (XMethodElement method : getAllUnimplementedMethods(creator)) { XMethodType resolvedMethodType = method.asMemberOf(creator.getType()); if (isSubtype(componentType, resolvedMethodType.getReturnType())) { verify( factoryMethod == null, "Expected a single factory method for %s but found multiple: [%s, %s]", XElements.toStableString(creator), XElements.toStableString(factoryMethod), XElements.toStableString(method)); factoryMethod = method; } else { XExecutableParameterElement parameter = getOnlyElement(method.getParameters()); XType parameterType = getOnlyElement(resolvedMethodType.getParameterTypes()); setterMethods.put( requirement(method, parameter, parameterType, dependencyRequestFactory, method), method); } } verify( factoryMethod != null, "Expected a single factory method for %s but found none.", XElements.toStableString(creator)); ImmutableSetMultimap.Builder factoryParameters = ImmutableSetMultimap.builder(); XMethodType resolvedFactoryMethodType = factoryMethod.asMemberOf(creator.getType()); List parameters = factoryMethod.getParameters(); List parameterTypes = resolvedFactoryMethodType.getParameterTypes(); for (int i = 0; i < parameters.size(); i++) { XExecutableParameterElement parameter = parameters.get(i); XType parameterType = parameterTypes.get(i); factoryParameters.put( requirement( factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter), parameter); } // Validation should have ensured exactly one creator annotation is present on the type. ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(creator)); return new AutoValue_ComponentCreatorDescriptor( annotation, creator, factoryMethod, setterMethods.build(), factoryParameters.build()); } private static ComponentRequirement requirement( XMethodElement method, XExecutableParameterElement parameter, XType parameterType, DependencyRequestFactory dependencyRequestFactory, XElement elementForVariableName) { if (method.hasAnnotation(TypeNames.BINDS_INSTANCE) || parameter.hasAnnotation(TypeNames.BINDS_INSTANCE)) { DependencyRequest request = dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType); return ComponentRequirement.forBoundInstance( request.key(), request.isNullable(), elementForVariableName); } return parameterType.getTypeElement().hasAnyAnnotation(moduleAnnotations()) ? ComponentRequirement.forModule(parameterType) : ComponentRequirement.forDependency(parameterType); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy