Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Dagger-genenerated factories to have an additional create method 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. #4541

Merged
merged 1 commit into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading