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.
/*
* 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 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.writing.GwtCompatibility.gwtIncompatibleAnnotation;
import static dagger.internal.codegen.xprocessing.XAnnotationSpecs.Suppression.FUTURE_RETURN_VALUE_IGNORED;
import static dagger.internal.codegen.xprocessing.XAnnotationSpecs.Suppression.UNCHECKED;
import static dagger.internal.codegen.xprocessing.XAnnotationSpecs.suppressWarnings;
import static dagger.internal.codegen.xprocessing.XCodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.xprocessing.XCodeBlocks.parameterNames;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XFunSpecs.constructorBuilder;
import static dagger.internal.codegen.xprocessing.XFunSpecs.methodBuilder;
import static dagger.internal.codegen.xprocessing.XTypeNames.isFutureType;
import static dagger.internal.codegen.xprocessing.XTypeNames.listOf;
import static dagger.internal.codegen.xprocessing.XTypeNames.listenableFutureOf;
import static dagger.internal.codegen.xprocessing.XTypeNames.producedOf;
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.codegen.VisibilityModifier;
import androidx.room.compiler.codegen.XClassName;
import androidx.room.compiler.codegen.XCodeBlock;
import androidx.room.compiler.codegen.XFunSpec;
import androidx.room.compiler.codegen.XParameterSpec;
import androidx.room.compiler.codegen.XPropertySpec;
import androidx.room.compiler.codegen.XTypeName;
import androidx.room.compiler.codegen.XTypeSpec;
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 com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
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.model.DependencyRequest;
import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.xprocessing.XAnnotationSpecs.Suppression;
import dagger.internal.codegen.xprocessing.XFunSpecs;
import dagger.internal.codegen.xprocessing.XParameterSpecs;
import dagger.internal.codegen.xprocessing.XTypeNames;
import dagger.internal.codegen.xprocessing.XTypeSpecs;
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);
XTypeSpecs.Builder factoryBuilder =
XTypeSpecs.classBuilder(generatedClassNameForBinding(binding))
.superclass(
XTypeNames.ABSTRACT_PRODUCES_METHOD_PRODUCER.parametrizedBy(
callProducesMethodParameter(binding).getType(),
binding.contributedType().asTypeName()))
.addModifiers(PUBLIC, FINAL)
.addTypeVariableNames(bindingTypeElementTypeVariableNames(binding))
.addProperties(
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()))
.addFunction(constructorMethod(binding, factoryFields))
.addFunction(staticCreateMethod(binding, factoryFields))
.addFunction(collectDependenciesMethod(binding, factoryFields))
.addFunction(callProducesMethod(binding, factoryFields));
gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
return ImmutableList.of(factoryBuilder.build());
}
// 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 XFunSpec constructorMethod(ProductionBinding binding, FactoryFields factoryFields) {
XFunSpecs.Builder constructorBuilder =
constructorBuilder()
.addModifiers(PRIVATE)
.addParameters(constructorParameters(binding, factoryFields));
constructorBuilder.addStatement(
"super(%N, %L, %N)",
factoryFields.monitorField,
producerTokenConstruction(generatedClassNameForBinding(binding), binding),
factoryFields.executorField);
factoryFields.getAll().stream()
// The executor and monitor fields belong to the super class so they don't need a field
// assignment here.
.filter(field -> !field.equals(factoryFields.executorField))
.filter(field -> !field.equals(factoryFields.monitorField))
.forEach(
field -> {
if (field.getType().getRawTypeName().equals(XTypeNames.PRODUCER)) {
constructorBuilder.addStatement(
"this.%1N = %2T.nonCancellationPropagatingViewOf(%1N)",
field, XTypeNames.PRODUCERS);
} else {
constructorBuilder.addStatement("this.%1N = %1N", field);
}
});
return constructorBuilder.build();
}
ImmutableList constructorParameters(
ProductionBinding binding, FactoryFields factoryFields) {
return factoryFields.getAll().stream()
.map(
field ->
XParameterSpecs.of(field.getName(), field.getType())) // SUPPRESS_GET_NAME_CHECK
.collect(toImmutableList());
}
// 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 XFunSpec staticCreateMethod(ProductionBinding binding, FactoryFields factoryFields) {
ImmutableList params = constructorParameters(binding, factoryFields);
return XFunSpecs.methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.returns(parameterizedGeneratedTypeNameForBinding(binding))
.addTypeVariableNames(bindingTypeElementTypeVariableNames(binding))
.addParameters(params)
.addStatement(
"return %L",
XCodeBlock.ofNewInstance(
parameterizedGeneratedTypeNameForBinding(binding), "%L", parameterNames(params)))
.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.
© 2015 - 2025 Weber Informatics LLC | Privacy Policy