dagger.internal.codegen.writing.ProducerFactoryGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dagger-compiler Show documentation
Show all versions of dagger-compiler Show documentation
A fast dependency injector for Android and Java.
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.writing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.squareup.javapoet.ClassName.OBJECT;
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static com.squareup.javapoet.TypeSpec.classBuilder;
import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.FUTURE_RETURN_VALUE_IGNORED;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
import static dagger.internal.codegen.javapoet.TypeNames.FUTURES;
import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_TOKEN;
import static dagger.internal.codegen.javapoet.TypeNames.VOID_CLASS;
import static dagger.internal.codegen.javapoet.TypeNames.isFutureType;
import static dagger.internal.codegen.javapoet.TypeNames.listOf;
import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PROTECTED;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XFiler;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.base.UniqueNameSet;
import dagger.internal.codegen.binding.ProductionBinding;
import dagger.internal.codegen.binding.SourceFiles;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.model.RequestKind;
import java.util.Optional;
import javax.inject.Inject;
/** Generates {@code Producer} implementations from {@link ProductionBinding} instances. */
public final class ProducerFactoryGenerator extends SourceFileGenerator {
private final CompilerOptions compilerOptions;
private final SourceFiles sourceFiles;
@Inject
ProducerFactoryGenerator(
XFiler filer,
XProcessingEnv processingEnv,
CompilerOptions compilerOptions,
SourceFiles sourceFiles) {
super(filer, processingEnv);
this.compilerOptions = compilerOptions;
this.sourceFiles = sourceFiles;
}
@Override
public XElement originatingElement(ProductionBinding binding) {
// we only create factories for bindings that have a binding element
return binding.bindingElement().get();
}
@Override
public ImmutableList topLevelTypes(ProductionBinding binding) {
// We don't want to write out resolved bindings -- we want to write out the generic version.
checkArgument(!binding.unresolved().isPresent());
checkArgument(binding.bindingElement().isPresent());
FactoryFields factoryFields = FactoryFields.create(binding);
TypeSpec.Builder factoryBuilder =
classBuilder(generatedClassNameForBinding(binding))
.superclass(
ParameterizedTypeName.get(
TypeNames.ABSTRACT_PRODUCES_METHOD_PRODUCER,
callProducesMethodParameter(binding).type,
binding.contributedType().getTypeName()))
.addModifiers(PUBLIC, FINAL)
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.addFields(
factoryFields.getAll().stream()
// The executor and monitor fields are owned by the superclass so they are not
// included as fields in the generated factory subclass.
.filter(field -> !field.equals(factoryFields.executorField))
.filter(field -> !field.equals(factoryFields.monitorField))
.collect(toImmutableList()))
.addMethod(constructorMethod(binding, factoryFields))
.addMethod(staticCreateMethod(binding, factoryFields))
.addMethod(collectDependenciesMethod(binding, factoryFields))
.addMethod(callProducesMethod(binding, factoryFields));
gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
return ImmutableList.of(factoryBuilder);
}
// private FooModule_ProducesFooFactory(
// FooModule module,
// Provider executorProvider,
// Provider productionComponentMonitorProvider,
// Producer fooProducer,
// Producer barProducer) {
// super(
// productionComponentMonitorProvider,
// ProducerToken.create(FooModule_ProducesFooFactory.class),
// executorProvider);
// this.module = module;
// this.fooProducer = Producers.nonCancellationPropagatingViewOf(fooProducer);
// this.barProducer = Producers.nonCancellationPropagatingViewOf(barProducer);
// }
private MethodSpec constructorMethod(ProductionBinding binding, FactoryFields factoryFields) {
MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PRIVATE);
constructorBuilder.addStatement(
"super($N, $L, $N)",
factoryFields.monitorField,
producerTokenConstruction(generatedClassNameForBinding(binding), binding),
factoryFields.executorField);
factoryFields.getAll()
.forEach(
field -> {
constructorBuilder.addParameter(field.type, field.name);
// The executor and monitor fields belong to the super class so they don't need a
// field assignment here.
if (!field.equals(factoryFields.executorField)
&& !field.equals(factoryFields.monitorField)) {
if (TypeNames.rawTypeName(field.type).equals(TypeNames.PRODUCER)) {
constructorBuilder.addStatement(
"this.$1N = $2T.nonCancellationPropagatingViewOf($1N)",
field,
TypeNames.PRODUCERS);
} else {
constructorBuilder.addStatement("this.$1N = $1N", field);
}
}
});
return constructorBuilder.build();
}
// public static FooModule_ProducesFooFactory create(
// FooModule module,
// Provider executorProvider,
// Provider productionComponentMonitorProvider,
// Producer fooProducer,
// Producer barProducer) {
// return new FooModule_ProducesFooFactory(
// module, executorProvider, productionComponentMonitorProvider, fooProducer, barProducer);
// }
private MethodSpec staticCreateMethod(ProductionBinding binding, FactoryFields factoryFields) {
MethodSpec constructor = constructorMethod(binding, factoryFields);
return MethodSpec.methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.returns(parameterizedGeneratedTypeNameForBinding(binding))
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.addParameters(constructor.parameters)
.addStatement(
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
parameterNames(constructor.parameters))
.build();
}
// Example 1: No async dependencies.
// protected ListenableFuture collectDependencies() {
// return Futures.immediateFuture(null);
// }
//
// Example 2: Single async dependency, "fooProducer".
// protected ListenableFuture collectDependencies() {
// return fooProducer.get();
// }
//
// Example 3: Multiple async dependencies, "fooProducer" and "barProducer".
// protected ListenableFuture> collectDependencies() {
// ListenableFuture fooFuture = fooProducer.get();
// ListenableFuture barFuture = barProducer.get();
// return Futures.