Skip to content

Commit

Permalink
Change Dagger-genenerated factories to have an additional create meth…
Browse files Browse the repository at this point in the history
…od that takes in `dagger.internal.Provider` types. Since the components already pass in `dagger.internal.Provider` types, this will automatically make those components use the new method even though the component code hasn't change.

`javax.inject.Provider` methods are left to solve linking errors across Dagger versions. These methods will be removed in the future though.

RELNOTES=Make factory classes use `dagger.internal.Provider`.
PiperOrigin-RevId: 707611594
  • Loading branch information
Chang-Eric authored and Dagger Team committed Dec 18, 2024
1 parent 6ee6092 commit d60729d
Show file tree
Hide file tree
Showing 78 changed files with 670 additions and 100 deletions.
4 changes: 4 additions & 0 deletions java/dagger/internal/Providers.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
public final class Providers {

/** Converts a javax provider to a Dagger internal provider. */
@SuppressWarnings("unchecked")
public static <T extends @Nullable Object> Provider<T> asDaggerProvider(
final javax.inject.Provider<T> provider) {
checkNotNull(provider);
if (provider instanceof Provider) {
return (Provider) provider;
}
return new Provider<T>() {
@Override public T get() {
return provider.get();
Expand Down
9 changes: 0 additions & 9 deletions java/dagger/internal/codegen/binding/SourceFiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.xprocessing.XTypeNames;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;

Expand Down Expand Up @@ -100,14 +99,6 @@ public final class SourceFiles {
dependency -> {
XClassName frameworkClassName =
frameworkTypeMapper.getFrameworkType(dependency.kind()).frameworkClassName();
// Remap factory fields back to javax.inject.Provider to maintain backwards compatibility
// for now. In a future release, we should change this to Dagger Provider. This will still
// be a breaking change, but keeping compatibility for a while should reduce the
// likelihood of breakages as it would require components built at much older versions
// using factories built at newer versions to break.
if (frameworkClassName.equals(XTypeNames.DAGGER_PROVIDER)) {
frameworkClassName = XTypeNames.PROVIDER;
}
return FrameworkField.create(
DependencyVariableNamer.name(dependency),
frameworkClassName,
Expand Down
Binary file not shown.
1 change: 1 addition & 0 deletions java/dagger/internal/codegen/javapoet/TypeNames.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public final class TypeNames {
public static final ClassName MEMBERS_INJECTORS =
ClassName.get("dagger.internal", "MembersInjectors");
public static final ClassName PROVIDER = ClassName.get("javax.inject", "Provider");
public static final ClassName JAKARTA_PROVIDER = ClassName.get("jakarta.inject", "Provider");
public static final ClassName DAGGER_PROVIDER = ClassName.get("dagger.internal", "Provider");
public static final ClassName DAGGER_PROVIDERS = ClassName.get("dagger.internal", "Providers");
public static final ClassName PROVIDER_OF_LAZY =
Expand Down
84 changes: 81 additions & 3 deletions java/dagger/internal/codegen/writing/FactoryGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
import static dagger.internal.codegen.javapoet.TypeNames.factoryOf;
import static dagger.internal.codegen.model.BindingKind.INJECTION;
Expand Down Expand Up @@ -61,12 +62,14 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.squareup.javapoet.AnnotationSpec;
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.Preconditions;
Expand All @@ -88,6 +91,7 @@
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
import dagger.internal.codegen.xprocessing.Nullability;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
Expand Down Expand Up @@ -150,7 +154,7 @@ private TypeSpec.Builder factoryBuilder(ContributionBinding binding) {

return factoryBuilder
.addMethod(getMethod(binding, factoryFields))
.addMethod(staticCreateMethod(binding, factoryFields))
.addMethods(staticCreateMethod(binding, factoryFields))
.addMethod(staticProxyMethod(binding));
}

Expand Down Expand Up @@ -208,10 +212,12 @@ private MethodSpec constructorMethod(FactoryFields factoryFields) {
// Provider<Baz> bazProvider) {
// return new FooModule_ProvidesFooFactory(module, barProvider, bazProvider);
// }
private MethodSpec staticCreateMethod(ContributionBinding binding, FactoryFields factoryFields) {
private ImmutableList<MethodSpec> staticCreateMethod(
ContributionBinding binding, FactoryFields factoryFields) {
// We use a static create method so that generated components can avoid having to refer to the
// generic types of the factory. (Otherwise they may have visibility problems referring to the
// types.)
ImmutableList.Builder<MethodSpec> methodsBuilder = ImmutableList.builder();
MethodSpec.Builder createMethodBuilder =
methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
Expand All @@ -234,8 +240,32 @@ private MethodSpec staticCreateMethod(ContributionBinding binding, FactoryFields
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
parameterNames(parameters));
// If any of the parameters take a Dagger Provider type, we also need to make a
// Javax Provider type for backwards compatibility with components generated at
// an older version.
// Eventually, we will need to remove this and break backwards compatibility
// in order to fully cut the Javax dependency.
if (hasDaggerProviderParams(parameters)) {
methodsBuilder.add(javaxCreateMethod(binding, parameters));
}
}
return createMethodBuilder.build();
methodsBuilder.add(createMethodBuilder.build());
return methodsBuilder.build();
}

private MethodSpec javaxCreateMethod(
ContributionBinding binding, ImmutableList<ParameterSpec> parameters) {
ImmutableList<ParameterSpec> remappedParams = remapParamsToJavaxProvider(parameters);
return methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.returns(parameterizedGeneratedTypeNameForBinding(binding))
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.addParameters(remappedParams)
.addStatement(
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
wrappedParametersCodeBlock(remappedParams))
.build();
}

// Example 1: Provision binding.
Expand Down Expand Up @@ -478,6 +508,54 @@ private static Optional<TypeName> factoryTypeName(ContributionBinding binding) {
: Optional.of(factoryOf(providedTypeName(binding)));
}

// Open for sharing with ProducerFactoryGenerator and MembersInjectorGenerator
static boolean hasDaggerProviderParams(List<ParameterSpec> params) {
return params.stream().anyMatch(param -> isDaggerProviderType(param.type));
}

// Open for sharing with ProducerFactoryGenerator and MembersInjectorGenerator
// Returns a code block that represents a parameter list where any javax Provider
// types are wrapped in an asDaggerProvider call
static CodeBlock wrappedParametersCodeBlock(List<ParameterSpec> params) {
return makeParametersCodeBlock(
Lists.transform(
params,
input ->
isProviderType(input.type)
? CodeBlock.of(
"$T.asDaggerProvider($N)", TypeNames.DAGGER_PROVIDERS, input)
: CodeBlock.of("$N", input)));
}

// Open for sharing with ProducerFactoryGenerator and MembersInjectorGenerator
static ImmutableList<ParameterSpec> remapParamsToJavaxProvider(List<ParameterSpec> params) {
return params.stream()
.map(param -> ParameterSpec.builder(
remapDaggerProviderToProvider(param.type), param.name).build())
.collect(toImmutableList());
}

private static boolean isDaggerProviderType(TypeName type) {
return type instanceof ParameterizedTypeName
&& ((ParameterizedTypeName) type).rawType.equals(TypeNames.DAGGER_PROVIDER);
}

private static boolean isProviderType(TypeName type) {
return type instanceof ParameterizedTypeName
&& ((ParameterizedTypeName) type).rawType.equals(TypeNames.PROVIDER);
}

private static TypeName remapDaggerProviderToProvider(TypeName type) {
if (type instanceof ParameterizedTypeName) {
ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) type;
if (parameterizedTypeName.rawType.equals(TypeNames.DAGGER_PROVIDER)) {
return ParameterizedTypeName.get(
TypeNames.PROVIDER, parameterizedTypeName.typeArguments.toArray(new TypeName[0]));
}
}
return type;
}

/** Represents the available fields in the generated factory class. */
private static final class FactoryFields {
static FactoryFields create(ContributionBinding binding) {
Expand Down
34 changes: 29 additions & 5 deletions java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
import static dagger.internal.codegen.javapoet.TypeNames.membersInjectorOf;
import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
import static dagger.internal.codegen.writing.FactoryGenerator.hasDaggerProviderParams;
import static dagger.internal.codegen.writing.FactoryGenerator.remapParamsToJavaxProvider;
import static dagger.internal.codegen.writing.FactoryGenerator.wrappedParametersCodeBlock;
import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
import static dagger.internal.codegen.writing.InjectionMethods.copyParameter;
import static dagger.internal.codegen.writing.InjectionMethods.copyParameters;
Expand Down Expand Up @@ -83,6 +86,7 @@
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
import dagger.internal.codegen.xprocessing.Nullability;
import dagger.internal.codegen.xprocessing.XAnnotations;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;

Expand Down Expand Up @@ -126,7 +130,7 @@ public ImmutableList<TypeSpec.Builder> topLevelTypes(MembersInjectionBinding bin
.addSuperinterface(membersInjectorOf(binding.key().type().xprocessing().getTypeName()))
.addFields(frameworkFields.values())
.addMethod(constructor(frameworkFields))
.addMethod(createMethod(binding, frameworkFields))
.addMethods(createMethod(binding, frameworkFields))
.addMethod(injectMembersMethod(binding, frameworkFields))
.addMethods(
binding.injectionSites().stream()
Expand Down Expand Up @@ -260,22 +264,42 @@ private MethodSpec constructor(ImmutableMap<DependencyRequest, FieldSpec> framew
// @SuppressWarnings("RAW_TYPE") Provider dep3Provider) {
// return new MyClass_MembersInjector(dep1Provider, dep2Provider, dep3Provider);
// }
private MethodSpec createMethod(
private ImmutableList<MethodSpec> createMethod(
MembersInjectionBinding binding,
ImmutableMap<DependencyRequest, FieldSpec> frameworkFields) {
MethodSpec constructor = constructor(frameworkFields);
ImmutableList.Builder<MethodSpec> methodsBuilder = ImmutableList.builder();
List<ParameterSpec> params = constructor(frameworkFields).parameters;
// We use a static create method so that generated components can avoid having
// to refer to the generic types of the factory.
// (Otherwise they may have visibility problems referring to the types.)
methodsBuilder.add(methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.returns(membersInjectorOf(binding.key().type().xprocessing().getTypeName()))
.addParameters(params)
.addStatement(
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
parameterNames(params))
.build());
if (hasDaggerProviderParams(params)) {
methodsBuilder.add(javaxCreateMethod(binding, params));
}
return methodsBuilder.build();
}

private MethodSpec javaxCreateMethod(
MembersInjectionBinding binding, List<ParameterSpec> params) {
ImmutableList<ParameterSpec> remappedParams = remapParamsToJavaxProvider(params);
return methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.returns(membersInjectorOf(binding.key().type().xprocessing().getTypeName()))
.addParameters(constructor.parameters)
.addParameters(remappedParams)
.addStatement(
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
parameterNames(constructor.parameters))
wrappedParametersCodeBlock(remappedParams))
.build();
}

Expand Down
39 changes: 34 additions & 5 deletions java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
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.FactoryGenerator.hasDaggerProviderParams;
import static dagger.internal.codegen.writing.FactoryGenerator.remapParamsToJavaxProvider;
import static dagger.internal.codegen.writing.FactoryGenerator.wrappedParametersCodeBlock;
import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
Expand Down Expand Up @@ -77,6 +80,7 @@
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.model.RequestKind;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;

Expand Down Expand Up @@ -126,7 +130,7 @@ public ImmutableList<TypeSpec.Builder> topLevelTypes(ProductionBinding binding)
.filter(field -> !field.equals(factoryFields.monitorField))
.collect(toImmutableList()))
.addMethod(constructorMethod(binding, factoryFields))
.addMethod(staticCreateMethod(binding, factoryFields))
.addMethods(staticCreateMethod(binding, factoryFields))
.addMethod(collectDependenciesMethod(binding, factoryFields))
.addMethod(callProducesMethod(binding, factoryFields));

Expand Down Expand Up @@ -186,17 +190,42 @@ private MethodSpec constructorMethod(ProductionBinding binding, FactoryFields fa
// return new FooModule_ProducesFooFactory(
// module, executorProvider, productionComponentMonitorProvider, fooProducer, barProducer);
// }
private MethodSpec staticCreateMethod(ProductionBinding binding, FactoryFields factoryFields) {
MethodSpec constructor = constructorMethod(binding, factoryFields);
private ImmutableList<MethodSpec> staticCreateMethod(
ProductionBinding binding, FactoryFields factoryFields) {
ImmutableList.Builder<MethodSpec> methodsBuilder = ImmutableList.builder();
List<ParameterSpec> params = constructorMethod(binding, factoryFields).parameters;
methodsBuilder.add(MethodSpec.methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.returns(parameterizedGeneratedTypeNameForBinding(binding))
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.addParameters(params)
.addStatement(
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
parameterNames(params))
.build());
// If any of the parameters take a Dagger Provider type, we also need to make a
// Javax Provider type for backwards compatibility with components generated at
// an older version.
// Eventually, we will need to remove this and break backwards compatibility
// in order to fully cut the Javax dependency.
if (hasDaggerProviderParams(params)) {
methodsBuilder.add(javaxCreateMethod(binding, params));
}
return methodsBuilder.build();
}

private MethodSpec javaxCreateMethod(ProductionBinding binding, List<ParameterSpec> params) {
ImmutableList<ParameterSpec> remappedParams = remapParamsToJavaxProvider(params);
return MethodSpec.methodBuilder("create")
.addModifiers(PUBLIC, STATIC)
.returns(parameterizedGeneratedTypeNameForBinding(binding))
.addTypeVariables(bindingTypeElementTypeVariableNames(binding))
.addParameters(constructor.parameters)
.addParameters(remappedParams)
.addStatement(
"return new $T($L)",
parameterizedGeneratedTypeNameForBinding(binding),
parameterNames(constructor.parameters))
wrappedParametersCodeBlock(remappedParams))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package test;

import dagger.internal.DaggerGenerated;
import dagger.internal.Provider;
import dagger.internal.Providers;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;

@ScopeMetadata
@QualifierMetadata
Expand Down Expand Up @@ -33,6 +34,10 @@ public final class Foo_Factory {
return newInstance(argProvider.get(), argProvider2);
}

public static Foo_Factory create(javax.inject.Provider<Bar> argProvider) {
return new Foo_Factory(Providers.asDaggerProvider(argProvider));
}

public static Foo_Factory create(Provider<Bar> argProvider) {
return new Foo_Factory(argProvider);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package test;

import dagger.internal.DaggerGenerated;
import dagger.internal.Provider;
import dagger.internal.Providers;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
import javax.annotation.processing.Generated;
import javax.inject.Provider;

@ScopeMetadata
@QualifierMetadata
Expand Down Expand Up @@ -33,6 +34,10 @@ public final class Foo_Factory {
return newInstance(argProvider.get(), argProvider2);
}

public static Foo_Factory create(javax.inject.Provider<Bar> argProvider) {
return new Foo_Factory(Providers.asDaggerProvider(argProvider));
}

public static Foo_Factory create(Provider<Bar> argProvider) {
return new Foo_Factory(argProvider);
}
Expand Down
Loading

0 comments on commit d60729d

Please sign in to comment.