Skip to content

Commit

Permalink
Support injecting jakarta.inject.Provider type in the places `javax…
Browse files Browse the repository at this point in the history
….inject.Provider` can be used.

RELNOTES=Support injecting `jakarta.inject.Provider`
PiperOrigin-RevId: 710101199
  • Loading branch information
Chang-Eric authored and Dagger Team committed Dec 27, 2024
1 parent 3ac3681 commit caa7e17
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 29 deletions.
17 changes: 11 additions & 6 deletions java/dagger/internal/codegen/base/FrameworkTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package dagger.internal.codegen.base;

import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;

import androidx.room.compiler.processing.XType;
Expand All @@ -32,7 +31,11 @@
public final class FrameworkTypes {
// TODO(erichang): Add the Jakarta Provider here
private static final ImmutableSet<ClassName> PROVISION_TYPES =
ImmutableSet.of(TypeNames.PROVIDER, TypeNames.LAZY, TypeNames.MEMBERS_INJECTOR);
ImmutableSet.of(
TypeNames.PROVIDER,
TypeNames.JAKARTA_PROVIDER,
TypeNames.LAZY,
TypeNames.MEMBERS_INJECTOR);

// NOTE(beder): ListenableFuture is not considered a producer framework type because it is not
// defined by the framework, so we can't treat it specially in ordinary Dagger.
Expand All @@ -42,13 +45,15 @@ public final class FrameworkTypes {
private static final ImmutableSet<ClassName> ALL_FRAMEWORK_TYPES =
ImmutableSet.<ClassName>builder().addAll(PROVISION_TYPES).addAll(PRODUCTION_TYPES).build();

private static final ImmutableSet<ClassName> SET_VALUE_FRAMEWORK_TYPES =
public static final ImmutableSet<ClassName> SET_VALUE_FRAMEWORK_TYPES =
ImmutableSet.of(TypeNames.PRODUCED);

public static final ImmutableSet<ClassName> MAP_VALUE_FRAMEWORK_TYPES =
MapType.VALID_FRAMEWORK_REQUEST_KINDS.stream()
.map(RequestKinds::frameworkClassName)
.collect(toImmutableSet());
ImmutableSet.of(
TypeNames.PRODUCED,
TypeNames.PRODUCER,
TypeNames.PROVIDER,
TypeNames.JAKARTA_PROVIDER);

/** Returns true if the type represents a producer-related framework type. */
public static boolean isProducerType(XType type) {
Expand Down
21 changes: 15 additions & 6 deletions java/dagger/internal/codegen/base/MapType.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@
@AutoValue
public abstract class MapType {
// TODO(b/28555349): support PROVIDER_OF_LAZY here too
// TODO(b/376124787): We could consolidate this with a similar list in FrameworkTypes
// if we had a better way to go from RequestKind to framework ClassName or vice versa
/** The valid framework request kinds allowed on a multibinding map value. */
public static final ImmutableSet<RequestKind> VALID_FRAMEWORK_REQUEST_KINDS =
private static final ImmutableSet<RequestKind> VALID_FRAMEWORK_REQUEST_KINDS =
ImmutableSet.of(RequestKind.PROVIDER, RequestKind.PRODUCER, RequestKind.PRODUCED);

private XType type;
Expand Down Expand Up @@ -107,12 +109,19 @@ public XType unwrappedFrameworkValueType() {
*/
public RequestKind valueRequestKind() {
checkArgument(!isRawType());
for (RequestKind frameworkRequestKind : VALID_FRAMEWORK_REQUEST_KINDS) {
if (valuesAreTypeOf(RequestKinds.frameworkClassName(frameworkRequestKind))) {
return frameworkRequestKind;
}
RequestKind requestKind = RequestKinds.getRequestKind(valueType());
if (VALID_FRAMEWORK_REQUEST_KINDS.contains(requestKind)) {
return requestKind;
} else if (requestKind == RequestKind.PROVIDER_OF_LAZY) {
// This is kind of a weird case. We don't support Map<K, Lazy<V>>, so we also don't support
// Map<K, Provider<Lazy<V>>> directly. However, if the user bound that themselves, we don't
// want that to get confused as a normal instance request, so return PROVIDER here.
return RequestKind.PROVIDER;
} else {
// Not all RequestKinds are supported, so if there's a map value that matches an unsupported
// RequestKind, just treat it like it is a normal instance request.
return RequestKind.INSTANCE;
}
return RequestKind.INSTANCE;
}

/** {@code true} if {@code type} is a {@link java.util.Map} type. */
Expand Down
9 changes: 8 additions & 1 deletion java/dagger/internal/codegen/base/RequestKinds.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public static TypeName requestTypeName(RequestKind requestKind, TypeName keyType

private static final ImmutableMap<RequestKind, ClassName> FRAMEWORK_CLASSES =
ImmutableMap.of(
// Default to the javax Provider since that is what is used for the binding graph
// representation.
PROVIDER, TypeNames.PROVIDER,
LAZY, TypeNames.LAZY,
PRODUCER, TypeNames.PRODUCER,
Expand All @@ -111,10 +113,15 @@ public static RequestKind getRequestKind(XType type) {
return RequestKind.INSTANCE;
}

if (isTypeOf(type, TypeNames.PROVIDER) && isTypeOf(unwrapType(type), TypeNames.LAZY)) {
if ((isTypeOf(type, TypeNames.PROVIDER) || isTypeOf(type, TypeNames.JAKARTA_PROVIDER))
&& isTypeOf(unwrapType(type), TypeNames.LAZY)) {
return RequestKind.PROVIDER_OF_LAZY;
}

if (isTypeOf(type, TypeNames.JAKARTA_PROVIDER)) {
return RequestKind.PROVIDER;
}

return FRAMEWORK_CLASSES.keySet().stream()
.filter(kind -> isTypeOf(type, FRAMEWORK_CLASSES.get(kind)))
.collect(toOptional())
Expand Down
13 changes: 5 additions & 8 deletions java/dagger/internal/codegen/binding/ComponentDeclarations.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimaps;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.WildcardTypeName;
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.FrameworkTypes;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.model.DaggerAnnotation;
import dagger.internal.codegen.model.Key;
Expand All @@ -39,11 +41,6 @@

/** Stores the bindings and declarations of a component by key. */
final class ComponentDeclarations {
private static final ImmutableSet<TypeName> MAP_FRAMEWORK_TYPENAMES =
ImmutableSet.of(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED);
private static final ImmutableSet<TypeName> SET_FRAMEWORK_TYPENAMES =
ImmutableSet.of(TypeNames.PRODUCED);

private final KeyFactory keyFactory;
private final ImmutableSetMultimap<Key, ContributionBinding> bindings;
private final ImmutableSetMultimap<Key, DelegateDeclaration> delegates;
Expand Down Expand Up @@ -322,14 +319,14 @@ private static TypeName unwrapMultibindingTypeName(TypeName typeName) {
return ParameterizedTypeName.get(
mapTypeName.rawType,
mapKeyTypeName,
unwrapFrameworkTypeName(mapValueTypeName, MAP_FRAMEWORK_TYPENAMES));
unwrapFrameworkTypeName(mapValueTypeName, FrameworkTypes.MAP_VALUE_FRAMEWORK_TYPES));
}
if (isValidSetMultibindingTypeName(typeName)) {
ParameterizedTypeName setTypeName = (ParameterizedTypeName) typeName;
TypeName setValueTypeName = getOnlyElement(setTypeName.typeArguments);
return ParameterizedTypeName.get(
setTypeName.rawType,
unwrapFrameworkTypeName(setValueTypeName, SET_FRAMEWORK_TYPENAMES));
unwrapFrameworkTypeName(setValueTypeName, FrameworkTypes.SET_VALUE_FRAMEWORK_TYPES));
}
return typeName;
}
Expand All @@ -356,7 +353,7 @@ private static boolean isValidSetMultibindingTypeName(TypeName typeName) {
}

private static TypeName unwrapFrameworkTypeName(
TypeName typeName, ImmutableSet<TypeName> frameworkTypeNames) {
TypeName typeName, ImmutableSet<ClassName> frameworkTypeNames) {
if (typeName instanceof ParameterizedTypeName) {
ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
if (frameworkTypeNames.contains(parameterizedTypeName.rawType)) {
Expand Down
11 changes: 3 additions & 8 deletions java/dagger/internal/codegen/binding/KeyFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import dagger.Binds;
import dagger.BindsOptionalOf;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.FrameworkTypes;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.base.RequestKinds;
Expand Down Expand Up @@ -97,10 +98,7 @@ private XType optionalOf(XType type) {

/** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */
private XType mapOfFrameworkType(XType keyType, ClassName frameworkClassName, XType valueType) {
checkArgument(
MapType.VALID_FRAMEWORK_REQUEST_KINDS.stream()
.map(RequestKinds::frameworkClassName)
.anyMatch(frameworkClassName::equals));
checkArgument(FrameworkTypes.MAP_VALUE_FRAMEWORK_TYPES.contains(frameworkClassName));
return mapOf(
keyType,
processingEnv.getDeclaredType(
Expand Down Expand Up @@ -317,10 +315,7 @@ public Key unwrapMapValueType(Key key) {
* type.
*/
private Key wrapMapValue(Key key, ClassName frameworkClassName) {
checkArgument(
MapType.VALID_FRAMEWORK_REQUEST_KINDS.stream()
.map(RequestKinds::frameworkClassName)
.anyMatch(frameworkClassName::equals));
checkArgument(FrameworkTypes.MAP_VALUE_FRAMEWORK_TYPES.contains(frameworkClassName));
if (MapType.isMap(key)) {
MapType mapType = MapType.from(key);
if (!mapType.isRawType() && !mapType.valuesAreTypeOf(frameworkClassName)) {
Expand Down
13 changes: 13 additions & 0 deletions javatests/dagger/functional/jakarta/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,16 @@ GenJavaTests(
"@maven//:jakarta_inject_jakarta_inject_api",
],
)

GenJavaTests(
name = "JakartaProviderTest",
srcs = ["JakartaProviderTest.java"],
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
"//:dagger_with_compiler",
"//third_party/java/guava/base",
"//third_party/java/junit",
"//third_party/java/truth",
"@maven//:jakarta_inject_jakarta_inject_api",
],
)
Loading

0 comments on commit caa7e17

Please sign in to comment.