Skip to content

Commit

Permalink
Fix issue with jakarta.inject.Provider support where in certain cas…
Browse files Browse the repository at this point in the history
…es requests for a `Map<K, Provider<V>>` would fail to compile. Similarly, fix support for `@LazyClassKey` with `jakarta.inject.Provider`.

Fixes #4572.

RELNOTES=Fixes #4572. Fix issue with `jakarta.inject.Provider` support where in certain cases requests for a `Map<K, Provider<V>>` would fail to compile.
PiperOrigin-RevId: 715952799
  • Loading branch information
Chang-Eric authored and Dagger Team committed Jan 16, 2025
1 parent aa70ca8 commit 523a454
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 9 deletions.
12 changes: 9 additions & 3 deletions java/dagger/internal/codegen/base/MapType.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ public boolean valuesAreFrameworkType() {
return valueRequestKind() != RequestKind.INSTANCE;
}

/** Returns {@code true} if the raw type of {@link #valueType()} is a provider type.*/
public boolean valuesAreProvider() {
return valuesAreTypeOf(TypeNames.PROVIDER) || valuesAreTypeOf(TypeNames.JAKARTA_PROVIDER);
}

/**
* Returns the map's {@link #valueType()} without any wrapping framework type, if one exists.
*
Expand Down Expand Up @@ -124,19 +129,20 @@ public RequestKind valueRequestKind() {
}
}

/** {@code true} if {@code type} is a {@link java.util.Map} type. */
/** Returns {@code true} if {@code type} is a {@link java.util.Map} type. */
public static boolean isMap(XType type) {
return isTypeOf(type, TypeNames.MAP);
}

/** {@code true} if {@code key.type()} is a {@link java.util.Map} type. */
/** Returns {@code true} if {@code key.type()} is a {@link java.util.Map} type. */
public static boolean isMap(Key key) {
return isMap(key.type().xprocessing());
}

/** Returns {@code true} if the given type is a {@code Map<K, Provider<V>>}. */
public static boolean isMapOfProvider(XType keyType) {
if (MapType.isMap(keyType)) {
return MapType.from(keyType).valuesAreTypeOf(TypeNames.PROVIDER);
return MapType.from(keyType).valuesAreProvider();
}
return false;
}
Expand Down
3 changes: 1 addition & 2 deletions java/dagger/internal/codegen/binding/SourceFiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import static com.google.common.base.Verify.verify;
import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER_OF_LAZY;
import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
import static dagger.internal.codegen.model.BindingKind.INJECTION;
Expand Down Expand Up @@ -280,7 +279,7 @@ public static XClassName mapFactoryClassName(MultiboundMapBinding binding) {
MapType mapType = MapType.from(binding.key());
switch (binding.bindingType()) {
case PROVISION:
return mapType.valuesAreTypeOf(PROVIDER)
return mapType.valuesAreProvider()
? XTypeNames.MAP_PROVIDER_FACTORY : XTypeNames.MAP_FACTORY;
case PRODUCTION:
return mapType.valuesAreFrameworkType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.binding.DependencyRequestFormatter;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.Binding;
import dagger.internal.codegen.model.BindingGraph;
import dagger.internal.codegen.model.BindingGraph.ComponentNode;
Expand Down Expand Up @@ -242,7 +241,7 @@ private boolean breaksCycle(XType requestedType, RequestKind requestKind) {

case INSTANCE:
if (MapType.isMap(requestedType)) {
return MapType.from(requestedType).valuesAreTypeOf(TypeNames.PROVIDER);
return MapType.from(requestedType).valuesAreProvider();
}
// fall through

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private static ClassName lazyMapFactoryClassName(MultiboundMapBinding binding) {
MapType mapType = MapType.from(binding.key());
switch (binding.bindingType()) {
case PROVISION:
return mapType.valuesAreTypeOf(TypeNames.PROVIDER)
return mapType.valuesAreProvider()
? TypeNames.LAZY_CLASS_KEY_MAP_PROVIDER_FACTORY
: TypeNames.LAZY_CLASS_KEY_MAP_FACTORY;
case PRODUCTION:
Expand Down
37 changes: 36 additions & 1 deletion javatests/dagger/functional/jakarta/JakartaProviderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.LazyClassKey;
import dagger.multibindings.StringKey;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
Expand Down Expand Up @@ -75,6 +76,10 @@ interface TestComponent {

Map<String, javax.inject.Provider<Bar>> getJavaxProviderMap();

Map<Class<?>, Provider<Bar>> getJakartaProviderClassMap();

Map<Class<?>, javax.inject.Provider<Bar>> getJavaxProviderClassMap();

Map<String, Provider<Lazy<Bar>>> getJakartaProviderLazyMap();

Map<String, javax.inject.Provider<Lazy<Bar>>> getJavaxProviderLazyMap();
Expand Down Expand Up @@ -103,10 +108,17 @@ public static final class Bar {
Bar() {}
}

// Scoped as this forces the generated code to use a Provider instead of inlining
// in default mode
@TestScope
public static final class InjectUsages {
Provider<Bar> jakartaBar;
Provider<Bar> jakartaQualifiedBar;
javax.inject.Provider<Bar> javaxQualifiedBar;
Map<String, javax.inject.Provider<Bar>> javaxProviderMap;
Map<String, Provider<Bar>> jakartaProviderMap;
Map<Class<?>, javax.inject.Provider<Bar>> javaxProviderClassMap;
Map<Class<?>, Provider<Bar>> jakartaProviderClassMap;

@Inject
InjectUsages(Provider<Bar> jakartaBar) {
Expand All @@ -117,9 +129,18 @@ public static final class InjectUsages {

@Inject
void injectBar(
Provider<Bar> jakartaQualifiedBar, javax.inject.Provider<Bar> javaxQualifiedBar) {
Provider<Bar> jakartaQualifiedBar,
javax.inject.Provider<Bar> javaxQualifiedBar,
Map<String, javax.inject.Provider<Bar>> javaxProviderMap,
Map<String, Provider<Bar>> jakartaProviderMap,
Map<Class<?>, javax.inject.Provider<Bar>> javaxProviderClassMap,
Map<Class<?>, Provider<Bar>> jakartaProviderClassMap) {
this.jakartaQualifiedBar = jakartaQualifiedBar;
this.javaxQualifiedBar = javaxQualifiedBar;
this.javaxProviderMap = javaxProviderMap;
this.jakartaProviderMap = jakartaProviderMap;
this.javaxProviderClassMap = javaxProviderClassMap;
this.jakartaProviderClassMap = jakartaProviderClassMap;
}
}

Expand All @@ -146,6 +167,11 @@ static Bar provideBar(
@StringKey("bar")
abstract Bar bindBarIntoMap(Bar bar);

@Binds
@IntoMap
@LazyClassKey(Bar.class)
abstract Bar bindBarIntoClassMap(Bar bar);

// TODO(b/65118638): Use @Binds @IntoMap Lazy<T> once that works properly.
@Provides
@IntoMap
Expand Down Expand Up @@ -210,9 +236,18 @@ public void testJakartaProviders() {
assertThat(testComponent.getJakartaProviderMap().get("bar").get()).isSameInstanceAs(
testComponent.getJavaxProviderMap().get("bar").get());

assertThat(testComponent.getJakartaProviderClassMap().get(Bar.class).get()).isSameInstanceAs(
testComponent.getJavaxProviderClassMap().get(Bar.class).get());

assertThat(testComponent.getJakartaProviderLazyMap().get("bar").get().get()).isSameInstanceAs(
testComponent.getJavaxProviderLazyMap().get("bar").get().get());

assertThat(injectUsages.jakartaProviderMap.get("bar").get()).isSameInstanceAs(
injectUsages.javaxProviderMap.get("bar").get());

assertThat(injectUsages.jakartaProviderClassMap.get(Bar.class).get()).isSameInstanceAs(
injectUsages.javaxProviderClassMap.get(Bar.class).get());

Map<Long, Provider<Long>> manualJakartaMap = testComponent.getManuallyProvidedJakartaMap();
assertThat(manualJakartaMap.keySet()).containsExactly(9L);

Expand Down

0 comments on commit 523a454

Please sign in to comment.