Skip to content

Commit

Permalink
Bind the Provider from Jakarta when creating bindings with a Multibin…
Browse files Browse the repository at this point in the history
…der, MapBinder & OptionalBinder.

(This is a slightly modified version of @kashike's original PR @ #1715, expanding tests for MapBinder & adding support for OptionalBinder.)

Fixes #1715

COPYBARA_INTEGRATE_REVIEW=#1715 from kashike:fix/jakarta-multibinder 5d7226e
PiperOrigin-RevId: 528762998
  • Loading branch information
kashike authored and Guice Team committed May 2, 2023
1 parent 104a113 commit 4cea397
Show file tree
Hide file tree
Showing 7 changed files with 573 additions and 39 deletions.
135 changes: 134 additions & 1 deletion core/src/com/google/inject/internal/RealMapBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(
TypeLiteral.get(Types.mapOf(keyType.getType(), Types.providerOf(valueType.getType())));
}

// provider map <K, V> is safely a Map<K, jakarta.inject.Provider<V>>>
@SuppressWarnings("unchecked")
static <K, V> TypeLiteral<Map<K, jakarta.inject.Provider<V>>> mapOfJakartaProviderOf(
TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
return (TypeLiteral<Map<K, jakarta.inject.Provider<V>>>)
TypeLiteral.get(
Types.mapOf(
keyType.getType(),
newParameterizedType(jakarta.inject.Provider.class, valueType.getType())));
}

// provider map <K, V> is safely a Map<K, javax.inject.Provider<V>>>
@SuppressWarnings("unchecked")
static <K, V> TypeLiteral<Map<K, javax.inject.Provider<V>>> mapOfJavaxProviderOf(
Expand All @@ -144,6 +155,15 @@ static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(
Types.mapOf(keyType.getType(), Types.setOf(Types.providerOf(valueType.getType()))));
}

@SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
static <K, V> TypeLiteral<Map<K, Set<jakarta.inject.Provider<V>>>> mapOfSetOfJakartaProviderOf(
TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
return (TypeLiteral<Map<K, Set<jakarta.inject.Provider<V>>>>)
TypeLiteral.get(
Types.mapOf(
keyType.getType(), Types.setOf(Types.jakartaProviderOf(valueType.getType()))));
}

@SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
static <K, V> TypeLiteral<Map<K, Set<javax.inject.Provider<V>>>> mapOfSetOfJavaxProviderOf(
TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
Expand All @@ -162,6 +182,17 @@ static <K, V> TypeLiteral<Map<K, Collection<Provider<V>>>> mapOfCollectionOfProv
keyType.getType(), Types.collectionOf(Types.providerOf(valueType.getType()))));
}

@SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
static <K, V>
TypeLiteral<Map<K, Collection<jakarta.inject.Provider<V>>>>
mapOfCollectionOfJakartaProviderOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
return (TypeLiteral<Map<K, Collection<jakarta.inject.Provider<V>>>>)
TypeLiteral.get(
Types.mapOf(
keyType.getType(),
Types.collectionOf(Types.jakartaProviderOf(valueType.getType()))));
}

@SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
static <K, V>
TypeLiteral<Map<K, Collection<javax.inject.Provider<V>>>> mapOfCollectionOfJavaxProviderOf(
Expand All @@ -184,6 +215,26 @@ static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(
Types.providerOf(valueType.getType())));
}

@SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfJakartaProviderOf(
TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
return (TypeLiteral<Map.Entry<K, Provider<V>>>)
TypeLiteral.get(
newParameterizedTypeWithOwner(
Map.class,
Map.Entry.class,
keyType.getType(),
Types.jakartaProviderOf(valueType.getType())));
}

@SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
static <K, V>
TypeLiteral<Set<Map.Entry<K, jakarta.inject.Provider<V>>>> setOfEntryOfJakartaProviderOf(
TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
return (TypeLiteral<Set<Map.Entry<K, jakarta.inject.Provider<V>>>>)
TypeLiteral.get(Types.setOf(entryOfJakartaProviderOf(keyType, valueType).getType()));
}

@SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfJavaxProviderOf(
TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
Expand Down Expand Up @@ -216,7 +267,6 @@ private static <T> Key<Provider<T>> getKeyOfProvider(Key<T> valueKey) {
// instance.
static <K, V> RealMapBinder<K, V> newRealMapBinder(
Binder binder, TypeLiteral<K> keyType, Key<V> valueTypeAndAnnotation) {
binder = binder.skipSources(RealMapBinder.class);
TypeLiteral<V> valueType = valueTypeAndAnnotation.getTypeLiteral();
return newRealMapBinder(
binder,
Expand Down Expand Up @@ -299,6 +349,14 @@ public void configure(Binder binder) {
new RealProviderMapProvider<>(bindingSelection);
binder.bind(bindingSelection.getProviderMapKey()).toProvider(providerMapProvider);

// The map this exposes is internally an ImmutableMap, so it's OK to massage
// the guice Provider to jakarta Provider in the value (since Guice provider
// implements jakarta Provider).
@SuppressWarnings({"unchecked", "rawtypes"})
Provider<Map<K, jakarta.inject.Provider<V>>> jakartaProviderMapProvider =
(Provider) providerMapProvider;
binder.bind(bindingSelection.getJakartaProviderMapKey()).toProvider(jakartaProviderMapProvider);

// The map this exposes is internally an ImmutableMap, so it's OK to massage
// the guice Provider to javax Provider in the value (since Guice provider
// implements javax Provider).
Expand All @@ -315,6 +373,13 @@ public void configure(Binder binder) {
// Bind Map<K, ? extends V> to the provider w/o the extension support.
binder.bind(bindingSelection.getMapOfKeyExtendsValueKey()).toProvider(mapProvider);

// The Map.Entries are all ProviderMapEntry instances which do not allow setValue, so it is
// safe to massage the return type like this
@SuppressWarnings({"unchecked", "rawtypes"})
Key<Set<Map.Entry<K, jakarta.inject.Provider<V>>>> jakartaEntrySetProviderKey =
(Key) bindingSelection.getEntrySetBinder().getSetKey();
binder.bind(bindingSelection.getEntrySetJakartaProviderKey()).to(jakartaEntrySetProviderKey);

// The Map.Entries are all ProviderMapEntry instances which do not allow setValue, so it is
// safe to massage the return type like this
@SuppressWarnings({"unchecked", "rawtypes"})
Expand Down Expand Up @@ -360,13 +425,18 @@ private enum InitializationState {
private final Key<Map<K, V>> mapKey;

// Lazily computed
private Key<Map<K, jakarta.inject.Provider<V>>> jakartaProviderMapKey;
private Key<Map<K, javax.inject.Provider<V>>> javaxProviderMapKey;
private Key<Map<K, Provider<V>>> providerMapKey;
private Key<Map<K, Set<V>>> multimapKey;
private Key<Map<K, Set<Provider<V>>>> providerSetMultimapKey;
private Key<Map<K, Set<jakarta.inject.Provider<V>>>> jakartaProviderSetMultimapKey;
private Key<Map<K, Set<javax.inject.Provider<V>>>> javaxProviderSetMultimapKey;
private Key<Map<K, Collection<Provider<V>>>> providerCollectionMultimapKey;
private Key<Map<K, Collection<jakarta.inject.Provider<V>>>>
jakartaProviderCollectionMultimapKey;
private Key<Map<K, Collection<javax.inject.Provider<V>>>> javaxProviderCollectionMultimapKey;
private Key<Set<Map.Entry<K, jakarta.inject.Provider<V>>>> entrySetJakartaProviderKey;
private Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> entrySetJavaxProviderKey;
private Key<Map<K, ? extends V>> mapOfKeyExtendsValueKey;

Expand Down Expand Up @@ -533,13 +603,17 @@ private boolean containsElement(Element element) {

return key.equals(getMapKey())
|| key.equals(getProviderMapKey())
|| key.equals(getJakartaProviderMapKey())
|| key.equals(getJavaxProviderMapKey())
|| key.equals(getMultimapKey())
|| key.equals(getProviderSetMultimapKey())
|| key.equals(getJakartaProviderSetMultimapKey())
|| key.equals(getJavaxProviderSetMultimapKey())
|| key.equals(getProviderCollectionMultimapKey())
|| key.equals(getJakartaProviderCollectionMultimapKey())
|| key.equals(getJavaxProviderCollectionMultimapKey())
|| key.equals(entrySetBinder.getSetKey())
|| key.equals(getEntrySetJakartaProviderKey())
|| key.equals(getEntrySetJavaxProviderKey())
|| key.equals(getMapOfKeyExtendsValueKey())
|| matchesValueKey(key);
Expand All @@ -562,6 +636,14 @@ private Key<Map<K, Provider<V>>> getProviderMapKey() {
return local;
}

private Key<Map<K, jakarta.inject.Provider<V>>> getJakartaProviderMapKey() {
Key<Map<K, jakarta.inject.Provider<V>>> local = jakartaProviderMapKey;
if (local == null) {
local = jakartaProviderMapKey = mapKey.ofType(mapOfJakartaProviderOf(keyType, valueType));
}
return local;
}

private Key<Map<K, javax.inject.Provider<V>>> getJavaxProviderMapKey() {
Key<Map<K, javax.inject.Provider<V>>> local = javaxProviderMapKey;
if (local == null) {
Expand All @@ -586,6 +668,16 @@ private Key<Map<K, Set<Provider<V>>>> getProviderSetMultimapKey() {
return local;
}

private Key<Map<K, Set<jakarta.inject.Provider<V>>>> getJakartaProviderSetMultimapKey() {
Key<Map<K, Set<jakarta.inject.Provider<V>>>> local = jakartaProviderSetMultimapKey;
if (local == null) {
local =
jakartaProviderSetMultimapKey =
mapKey.ofType(mapOfSetOfJakartaProviderOf(keyType, valueType));
}
return local;
}

private Key<Map<K, Set<javax.inject.Provider<V>>>> getJavaxProviderSetMultimapKey() {
Key<Map<K, Set<javax.inject.Provider<V>>>> local = javaxProviderSetMultimapKey;
if (local == null) {
Expand All @@ -606,6 +698,18 @@ private Key<Map<K, Collection<Provider<V>>>> getProviderCollectionMultimapKey()
return local;
}

private Key<Map<K, Collection<jakarta.inject.Provider<V>>>>
getJakartaProviderCollectionMultimapKey() {
Key<Map<K, Collection<jakarta.inject.Provider<V>>>> local =
jakartaProviderCollectionMultimapKey;
if (local == null) {
local =
jakartaProviderCollectionMultimapKey =
mapKey.ofType(mapOfCollectionOfJakartaProviderOf(keyType, valueType));
}
return local;
}

private Key<Map<K, Collection<javax.inject.Provider<V>>>>
getJavaxProviderCollectionMultimapKey() {
Key<Map<K, Collection<javax.inject.Provider<V>>>> local = javaxProviderCollectionMultimapKey;
Expand All @@ -617,6 +721,16 @@ private Key<Map<K, Collection<Provider<V>>>> getProviderCollectionMultimapKey()
return local;
}

private Key<Set<Map.Entry<K, jakarta.inject.Provider<V>>>> getEntrySetJakartaProviderKey() {
Key<Set<Map.Entry<K, jakarta.inject.Provider<V>>>> local = entrySetJakartaProviderKey;
if (local == null) {
local =
entrySetJakartaProviderKey =
mapKey.ofType(setOfEntryOfJakartaProviderOf(keyType, valueType));
}
return local;
}

private Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> getEntrySetJavaxProviderKey() {
Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> local = entrySetJavaxProviderKey;
if (local == null) {
Expand Down Expand Up @@ -862,11 +976,14 @@ public Key<Map<K, V>> getMapKey() {
@Override
public Set<Key<?>> getAlternateMapKeys() {
return ImmutableSet.of(
(Key<?>) bindingSelection.getJakartaProviderMapKey(),
(Key<?>) bindingSelection.getJavaxProviderMapKey(),
(Key<?>) bindingSelection.getProviderMapKey(),
(Key<?>) bindingSelection.getProviderSetMultimapKey(),
(Key<?>) bindingSelection.getJakartaProviderSetMultimapKey(),
(Key<?>) bindingSelection.getJavaxProviderSetMultimapKey(),
(Key<?>) bindingSelection.getProviderCollectionMultimapKey(),
(Key<?>) bindingSelection.getJakartaProviderCollectionMultimapKey(),
(Key<?>) bindingSelection.getJavaxProviderCollectionMultimapKey(),
(Key<?>) bindingSelection.getMultimapKey(),
(Key<?>) bindingSelection.getMapOfKeyExtendsValueKey());
Expand Down Expand Up @@ -1041,12 +1158,28 @@ public void configure(Binder binder) {
Provider<Map<K, Set<javax.inject.Provider<V>>>> javaxProvider = (Provider) multimapProvider;
binder.bind(bindingSelection.getJavaxProviderSetMultimapKey()).toProvider(javaxProvider);

// Provide links from a few different public keys to the providerMultimapKey.
// The collection this exposes is internally an ImmutableMap, so it's OK to massage
// the guice Provider to jakarta Provider in the value (since the guice Provider implements
// jakarta Provider).
@SuppressWarnings({"unchecked", "rawtypes"})
Provider<Map<K, Set<jakarta.inject.Provider<V>>>> jakartaProvider =
(Provider) multimapProvider;
binder.bind(bindingSelection.getJakartaProviderSetMultimapKey()).toProvider(jakartaProvider);

@SuppressWarnings({"unchecked", "rawtypes"})
Provider<Map<K, Collection<Provider<V>>>> collectionProvider = (Provider) multimapProvider;
binder
.bind(bindingSelection.getProviderCollectionMultimapKey())
.toProvider(collectionProvider);

@SuppressWarnings({"unchecked", "rawtypes"})
Provider<Map<K, Collection<jakarta.inject.Provider<V>>>> collectionJakartaProvider =
(Provider) multimapProvider;
binder
.bind(bindingSelection.getJakartaProviderCollectionMultimapKey())
.toProvider(collectionJakartaProvider);

@SuppressWarnings({"unchecked", "rawtypes"})
Provider<Map<K, Collection<javax.inject.Provider<V>>>> collectionJavaxProvider =
(Provider) multimapProvider;
Expand Down
30 changes: 30 additions & 0 deletions core/src/com/google/inject/internal/RealMultibinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ static <T> TypeLiteral<Collection<Provider<T>>> collectionOfProvidersOf(
return (TypeLiteral<Collection<Provider<T>>>) TypeLiteral.get(type);
}

@SuppressWarnings("unchecked")
static <T> TypeLiteral<Collection<jakarta.inject.Provider<T>>> collectionOfJakartaProvidersOf(
TypeLiteral<T> elementType) {
Type providerType =
Types.newParameterizedType(jakarta.inject.Provider.class, elementType.getType());
Type type = Types.collectionOf(providerType);
return (TypeLiteral<Collection<jakarta.inject.Provider<T>>>) TypeLiteral.get(type);
}

@SuppressWarnings("unchecked")
static <T> TypeLiteral<Collection<javax.inject.Provider<T>>> collectionOfJavaxProvidersOf(
TypeLiteral<T> elementType) {
Expand Down Expand Up @@ -116,6 +125,14 @@ public void configure(Binder binder) {
.bind(bindingSelection.getCollectionOfProvidersKey())
.toProvider(collectionOfProvidersProvider);

// The collection this exposes is internally an ImmutableList, so it's OK to massage
// the guice Provider to jakarta Provider in the value (since the guice Provider implements
// jakarta Provider).
@SuppressWarnings("unchecked")
Provider<Collection<jakarta.inject.Provider<T>>> jakartaProvider =
(Provider) collectionOfProvidersProvider;
binder.bind(bindingSelection.getCollectionOfJakartaProvidersKey()).toProvider(jakartaProvider);

// The collection this exposes is internally an ImmutableList, so it's OK to massage
// the guice Provider to javax Provider in the value (since the guice Provider implements
// javax Provider).
Expand Down Expand Up @@ -326,6 +343,7 @@ public Key<Set<T>> getSetKey() {
public ImmutableSet<Key<?>> getAlternateSetKeys() {
return ImmutableSet.of(
(Key<?>) bindingSelection.getCollectionOfProvidersKey(),
(Key<?>) bindingSelection.getCollectionOfJakartaProvidersKey(),
(Key<?>) bindingSelection.getCollectionOfJavaxProvidersKey(),
(Key<?>) bindingSelection.getSetOfExtendsKey());
}
Expand Down Expand Up @@ -390,6 +408,7 @@ private static final class BindingSelection<T> {
// these are all lazily allocated
private String setName;
private Key<Collection<Provider<T>>> collectionOfProvidersKey;
private Key<Collection<jakarta.inject.Provider<T>>> collectionOfJakartaProvidersKey;
private Key<Collection<javax.inject.Provider<T>>> collectionOfJavaxProvidersKey;
private Key<Set<? extends T>> setOfExtendsKey;
private Key<Boolean> permitDuplicatesKey;
Expand Down Expand Up @@ -507,6 +526,16 @@ Key<Collection<Provider<T>>> getCollectionOfProvidersKey() {
return local;
}

Key<Collection<jakarta.inject.Provider<T>>> getCollectionOfJakartaProvidersKey() {
Key<Collection<jakarta.inject.Provider<T>>> local = collectionOfJakartaProvidersKey;
if (local == null) {
local =
collectionOfJakartaProvidersKey =
setKey.ofType(collectionOfJakartaProvidersOf(elementType));
}
return local;
}

Key<Collection<javax.inject.Provider<T>>> getCollectionOfJavaxProvidersKey() {
Key<Collection<javax.inject.Provider<T>>> local = collectionOfJavaxProvidersKey;
if (local == null) {
Expand Down Expand Up @@ -564,6 +593,7 @@ boolean containsElement(com.google.inject.spi.Element element) {
|| binding.getKey().equals(getPermitDuplicatesKey())
|| binding.getKey().equals(setKey)
|| binding.getKey().equals(collectionOfProvidersKey)
|| binding.getKey().equals(collectionOfJakartaProvidersKey)
|| binding.getKey().equals(collectionOfJavaxProvidersKey)
|| binding.getKey().equals(setOfExtendsKey);
} else {
Expand Down
Loading

0 comments on commit 4cea397

Please sign in to comment.