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

dagger.internal.codegen.writing.DependencyMethodProducerCreationExpression Maven / Gradle / Ivy

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

import static com.google.common.base.Preconditions.checkNotNull;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
import static dagger.internal.codegen.javapoet.TypeNames.dependencyMethodProducerOf;
import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;

import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeName;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ComponentDependencyProductionBinding;
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;

/**
 * A {@link dagger.producers.Producer} creation expression for a production method on a production
 * component's {@linkplain dagger.producers.ProductionComponent#dependencies()} dependency} that
 * returns a {@link com.google.common.util.concurrent.ListenableFuture}.
 */
// TODO(dpb): Resolve with DependencyMethodProviderCreationExpression.
final class DependencyMethodProducerCreationExpression
    implements FrameworkInstanceCreationExpression {
  private final ComponentDependencyProductionBinding binding;
  private final ComponentImplementation componentImplementation;
  private final ComponentRequirementExpressions componentRequirementExpressions;
  private final BindingGraph graph;

  @AssistedInject
  DependencyMethodProducerCreationExpression(
      @Assisted ComponentDependencyProductionBinding binding,
      ComponentImplementation componentImplementation,
      ComponentRequirementExpressions componentRequirementExpressions,
      BindingGraph graph) {
    this.binding = checkNotNull(binding);
    this.componentImplementation = componentImplementation;
    this.componentRequirementExpressions = componentRequirementExpressions;
    this.graph = graph;
  }

  @Override
  public CodeBlock creationExpression() {
    ComponentRequirement dependency =
        graph.componentDescriptor().getDependencyThatDefinesMethod(binding.bindingElement().get());
    FieldSpec dependencyField =
        FieldSpec.builder(
                dependency.typeElement().getClassName(), dependency.variableName(), PRIVATE, FINAL)
            .initializer(
                componentRequirementExpressions.getExpressionDuringInitialization(
                    dependency,
                    // This isn't a real class name, but we want the requesting class for the
                    // expression to *not* be the same class as the component implementation,
                    // because it isn't... it's an anonymous inner class.
                    // TODO(cgdecker): If we didn't use an anonymous inner class here but instead
                    // generated a named nested class as with
                    // DependencyMethodProviderCreationExpression, we wouldn't need to deal with
                    // this and might be able to avoid potentially creating an extra field in the
                    // component?
                    componentImplementation.name().nestedClass("Anonymous")))
            .build();
    // TODO(b/70395982): Explore using a private static type instead of an anonymous class.
    TypeName keyType = binding.key().type().xprocessing().getTypeName();
    return CodeBlock.of(
        "$L",
        anonymousClassBuilder("")
            .superclass(dependencyMethodProducerOf(keyType))
            .addField(dependencyField)
            .addMethod(
                methodBuilder("callDependencyMethod")
                    .addAnnotation(Override.class)
                    .addModifiers(PUBLIC)
                    .returns(listenableFutureOf(keyType))
                    .addStatement(
                        "return $N.$L()",
                        dependencyField,
                        asMethod(binding.bindingElement().get()).getJvmName())
                    .build())
            .build());
  }

  @AssistedFactory
  static interface Factory {
    DependencyMethodProducerCreationExpression create(ComponentDependencyProductionBinding binding);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy