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

dagger.internal.codegen.ProvisionBinding Maven / Gradle / Ivy

There is a newer version: 2.55
Show newest version
/*
 * Copyright (C) 2014 Google, Inc.
 *
 * 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;

import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import javax.inject.Inject;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.auto.common.MoreTypes.asDeclared;
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 dagger.internal.codegen.InjectionAnnotations.getQualifier;
import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
import static javax.lang.model.element.ElementKind.FIELD;
import static javax.lang.model.element.ElementKind.METHOD;

/**
 * A value object representing the mechanism by which a {@link Key} can be provided. New instances
 * should be created using an instance of the {@link Factory}.
 *
 * @author Gregory Kick
 * @since 2.0
 */
@AutoValue
abstract class ProvisionBinding extends ContributionBinding {

  @Override
  public BindingType bindingType() {
    return BindingType.PROVISION;
  }

  @Override
  abstract Optional unresolved();

  @Override
  abstract Optional scope();

  static final class Factory {
    private final Elements elements;
    private final Types types;
    private final Key.Factory keyFactory;
    private final DependencyRequest.Factory dependencyRequestFactory;

    Factory(Elements elements, Types types, Key.Factory keyFactory,
        DependencyRequest.Factory dependencyRequestFactory) {
      this.elements = elements;
      this.types = types;
      this.keyFactory = keyFactory;
      this.dependencyRequestFactory = dependencyRequestFactory;
    }

    /**
     * Returns a ProvisionBinding for the given element. If {@code resolvedType} is present, this
     * will return a resolved binding, with the key & type resolved to the given type (using
     * {@link Types#asMemberOf(DeclaredType, Element)}).
     */
    ProvisionBinding forInjectConstructor(ExecutableElement constructorElement,
        Optional resolvedType) {
      checkNotNull(constructorElement);
      checkArgument(constructorElement.getKind().equals(CONSTRUCTOR));
      checkArgument(isAnnotationPresent(constructorElement, Inject.class));
      checkArgument(!getQualifier(constructorElement).isPresent());

      ExecutableType cxtorType = MoreTypes.asExecutable(constructorElement.asType());
      DeclaredType enclosingCxtorType =
          MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
      // If the class this is constructing has some type arguments, resolve everything.
      if (!enclosingCxtorType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
        DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get());
        // Validate that we're resolving from the correct type.
        checkState(types.isSameType(types.erasure(resolved), types.erasure(enclosingCxtorType)),
            "erased expected type: %s, erased actual type: %s",
            types.erasure(resolved), types.erasure(enclosingCxtorType));
        cxtorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement));
        enclosingCxtorType = resolved;
      }

      Key key = keyFactory.forInjectConstructorWithResolvedType(enclosingCxtorType);
      checkArgument(!key.qualifier().isPresent());
      ImmutableSet dependencies =
          dependencyRequestFactory.forRequiredResolvedVariables(enclosingCxtorType,
              constructorElement.getParameters(),
              cxtorType.getParameterTypes());
      Optional membersInjectionRequest =
          membersInjectionRequest(enclosingCxtorType);
      Optional scope = Scope.uniqueScopeOf(constructorElement.getEnclosingElement());

      TypeElement bindingTypeElement =
          MoreElements.asType(constructorElement.getEnclosingElement());

      return new AutoValue_ProvisionBinding(
          ContributionType.UNIQUE,
          SourceElement.forElement(constructorElement),
          key,
          dependencies,
          findBindingPackage(key),
          Optional.absent(),
          membersInjectionRequest,
          Kind.INJECTION,
          hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types)
              ? Optional.of(forInjectConstructor(constructorElement, Optional.absent()))
              : Optional.absent(),
          scope);
    }

    private static final ImmutableSet MEMBER_KINDS =
        Sets.immutableEnumSet(METHOD, FIELD);

    private Optional membersInjectionRequest(DeclaredType type) {
      TypeElement typeElement = MoreElements.asType(type.asElement());
      if (!types.isSameType(elements.getTypeElement(Object.class.getCanonicalName()).asType(),
          typeElement.getSuperclass())) {
        return Optional.of(dependencyRequestFactory.forMembersInjectedType(type));
      }
      for (Element enclosedElement : typeElement.getEnclosedElements()) {
        if (MEMBER_KINDS.contains(enclosedElement.getKind())
            && (isAnnotationPresent(enclosedElement, Inject.class))) {
          return Optional.of(dependencyRequestFactory.forMembersInjectedType(type));
        }
      }
      return Optional.absent();
    }

    ProvisionBinding forProvidesMethod(
        ExecutableElement providesMethod, TypeElement contributedBy) {
      checkArgument(providesMethod.getKind().equals(METHOD));
      SourceElement sourceElement = SourceElement.forElement(providesMethod, contributedBy);
      ExecutableType resolvedMethod =
          MoreTypes.asExecutable(sourceElement.asMemberOfContributingType(types));
      Key key = keyFactory.forProvidesMethod(sourceElement);
      ImmutableSet dependencies =
          dependencyRequestFactory.forRequiredResolvedVariables(
              MoreTypes.asDeclared(contributedBy.asType()),
              providesMethod.getParameters(),
              resolvedMethod.getParameterTypes());
      Optional scope = Scope.uniqueScopeOf(providesMethod);
      return new AutoValue_ProvisionBinding(
          ContributionType.fromBindingMethod(providesMethod),
          sourceElement,
          key,
          dependencies,
          findBindingPackage(key),
          ConfigurationAnnotations.getNullableType(providesMethod),
          Optional.absent(),
          Kind.PROVISION,
          Optional.absent(),
          scope);
    }

    /**
     * A synthetic binding of {@code Map} that depends on {@code Map>}.
     */
    ProvisionBinding syntheticMapOfValuesBinding(DependencyRequest requestForMapOfValues) {
      checkNotNull(requestForMapOfValues);
      Optional mapOfProvidersKey =
          keyFactory.implicitMapProviderKeyFrom(requestForMapOfValues.key());
      checkArgument(
          mapOfProvidersKey.isPresent(),
          "%s is not a request for Map",
          requestForMapOfValues);
      DependencyRequest requestForMapOfProviders =
          dependencyRequestFactory.forImplicitMapBinding(
              requestForMapOfValues, mapOfProvidersKey.get());
      return new AutoValue_ProvisionBinding(
          ContributionType.UNIQUE,
          SourceElement.forElement(requestForMapOfProviders.requestElement()),
          requestForMapOfValues.key(),
          ImmutableSet.of(requestForMapOfProviders),
          findBindingPackage(requestForMapOfValues.key()),
          Optional.absent(),
          Optional.absent(),
          Kind.SYNTHETIC_MAP,
          Optional.absent(),
          Scope.uniqueScopeOf(requestForMapOfProviders.requestElement()));
    }

    /**
     * A synthetic binding that depends explicitly on a set of individual provision multibinding
     * contribution methods.
     * 
     * 

Note that these could be set multibindings or map multibindings. */ ProvisionBinding syntheticMultibinding( final DependencyRequest request, Iterable multibindingContributions) { return new AutoValue_ProvisionBinding( ContributionType.UNIQUE, SourceElement.forElement(request.requestElement()), request.key(), dependencyRequestFactory.forMultibindingContributions(request, multibindingContributions), findBindingPackage(request.key()), Optional.absent(), Optional.absent(), Kind.forMultibindingRequest(request), Optional.absent(), Scope.uniqueScopeOf(request.requestElement())); } ProvisionBinding forComponent(TypeElement componentDefinitionType) { checkNotNull(componentDefinitionType); return new AutoValue_ProvisionBinding( ContributionType.UNIQUE, SourceElement.forElement(componentDefinitionType), keyFactory.forComponent(componentDefinitionType.asType()), ImmutableSet.of(), Optional.absent(), Optional.absent(), Optional.absent(), Kind.COMPONENT, Optional.absent(), Optional.absent()); } ProvisionBinding forComponentMethod(ExecutableElement componentMethod) { checkNotNull(componentMethod); checkArgument(componentMethod.getKind().equals(METHOD)); checkArgument(componentMethod.getParameters().isEmpty()); Optional scope = Scope.uniqueScopeOf(componentMethod); return new AutoValue_ProvisionBinding( ContributionType.UNIQUE, SourceElement.forElement(componentMethod), keyFactory.forComponentMethod(componentMethod), ImmutableSet.of(), Optional.absent(), ConfigurationAnnotations.getNullableType(componentMethod), Optional.absent(), Kind.COMPONENT_PROVISION, Optional.absent(), scope); } ProvisionBinding forSubcomponentBuilderMethod( ExecutableElement subcomponentBuilderMethod, TypeElement contributedBy) { checkNotNull(subcomponentBuilderMethod); checkArgument(subcomponentBuilderMethod.getKind().equals(METHOD)); checkArgument(subcomponentBuilderMethod.getParameters().isEmpty()); DeclaredType declaredContainer = asDeclared(contributedBy.asType()); return new AutoValue_ProvisionBinding( ContributionType.UNIQUE, SourceElement.forElement(subcomponentBuilderMethod, contributedBy), keyFactory.forSubcomponentBuilderMethod(subcomponentBuilderMethod, declaredContainer), ImmutableSet.of(), Optional.absent(), Optional.absent(), Optional.absent(), Kind.SUBCOMPONENT_BUILDER, Optional.absent(), Optional.absent()); } ProvisionBinding delegate( DelegateDeclaration delegateDeclaration, ProvisionBinding delegate) { return new AutoValue_ProvisionBinding( delegate.contributionType(), delegateDeclaration.sourceElement(), delegateDeclaration.key(), ImmutableSet.of(delegateDeclaration.delegateRequest()), findBindingPackage(delegateDeclaration.key()), delegate.nullableType(), Optional.absent(), Kind.SYNTHETIC_DELEGATE_BINDING, Optional.absent(), Scope.uniqueScopeOf(delegateDeclaration.sourceElement().element())); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy