Skip to content

Commit 2d64067

Browse files
samebGuice Team
authored andcommitted
Use linked bindings for MapBinder/Multibinder/OptionalBinder aliases, instead of linking to the same internal factory implementation. (Reusing the internal factory results in some quirks that we want to avoid.)
PiperOrigin-RevId: 530977598
1 parent be0141c commit 2d64067

3 files changed

Lines changed: 63 additions & 143 deletions

File tree

core/src/com/google/inject/internal/RealMapBinder.java

Lines changed: 31 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -290,39 +290,37 @@ public LinkedBindingBuilder<V> addBinding(K key) {
290290
return binder.bind(getKeyForNewValue(key));
291291
}
292292

293+
@SuppressWarnings({"unchecked", "rawtypes"}) // we use raw Key to link bindings.
293294
@Override
294295
public void configure(Binder binder) {
295296
checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized");
296297

297298
// Binds a Map<K, Provider<V>>
298-
RealProviderMapProvider<K, V> providerMapProvider =
299-
new RealProviderMapProvider<>(bindingSelection);
300-
binder.bind(bindingSelection.getProviderMapKey()).toProvider(providerMapProvider);
299+
binder
300+
.bind(bindingSelection.getProviderMapKey())
301+
.toProvider(new RealProviderMapProvider<>(bindingSelection));
301302

302303
// The map this exposes is internally an ImmutableMap, so it's OK to massage
303304
// the guice Provider to jakarta Provider in the value (since Guice provider
304305
// implements jakarta Provider).
305-
@SuppressWarnings({"unchecked", "rawtypes"})
306-
Provider<Map<K, jakarta.inject.Provider<V>>> jakartaProviderMapProvider =
307-
(Provider) providerMapProvider;
308306
binder
309307
.bind(bindingSelection.getJakartaProviderMapKey())
310-
.toProvider(jakartaProviderMapProvider);
308+
.to((Key) bindingSelection.getProviderMapKey());
311309

312-
RealMapProvider<K, V> mapProvider = new RealMapProvider<>(bindingSelection);
313310
// Bind Map<K, V> to the provider w/ extension support.
314311
binder
315312
.bind(bindingSelection.getMapKey())
316-
.toProvider(new ExtensionRealMapProvider<>(mapProvider));
313+
.toProvider(new ExtensionRealMapProvider<>(bindingSelection));
317314
// Bind Map<K, ? extends V> to the provider w/o the extension support.
318-
binder.bind(bindingSelection.getMapOfKeyExtendsValueKey()).toProvider(mapProvider);
315+
binder
316+
.bind(bindingSelection.getMapOfKeyExtendsValueKey())
317+
.to((Key) bindingSelection.getMapKey());
319318

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

328326
@Override
@@ -737,8 +735,14 @@ protected Map<K, Provider<V>> doProvision(InternalContext context, Dependency<?>
737735
}
738736
}
739737

740-
private static final class RealMapProvider<K, V>
741-
extends RealMapBinderProviderWithDependencies<K, V, Map<K, V>> {
738+
/**
739+
* Implementation of a provider instance for the map that also exposes details about the MapBinder
740+
* using the extension SPI, delegating to another provider instance for non-extension (e.g, the
741+
* actual provider instance info) data.
742+
*/
743+
private static final class ExtensionRealMapProvider<K, V>
744+
extends RealMapBinderProviderWithDependencies<K, V, Map<K, V>>
745+
implements ProviderWithExtensionVisitor<Map<K, V>>, MapBinderBinding<Map<K, V>> {
742746
Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES;
743747

744748
/**
@@ -752,14 +756,10 @@ private static final class RealMapProvider<K, V>
752756

753757
private boolean initialized = false;
754758

755-
RealMapProvider(BindingSelection<K, V> bindingSelection) {
759+
ExtensionRealMapProvider(BindingSelection<K, V> bindingSelection) {
756760
super(bindingSelection);
757761
}
758762

759-
BindingSelection<K, V> getBindingSelection() {
760-
return bindingSelection;
761-
}
762-
763763
@Override
764764
protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException {
765765
if (initialized) {
@@ -821,43 +821,11 @@ protected Map<K, V> doProvision(InternalContext context, Dependency<?> dependenc
821821
public Set<Dependency<?>> getDependencies() {
822822
return dependencies;
823823
}
824-
}
825-
826-
/**
827-
* Implementation of a provider instance for the map that also exposes details about the MapBinder
828-
* using the extension SPI, delegating to another provider instance for non-extension (e.g, the
829-
* actual provider instance info) data.
830-
*/
831-
private static final class ExtensionRealMapProvider<K, V>
832-
extends RealMapBinderProviderWithDependencies<K, V, Map<K, V>>
833-
implements ProviderWithExtensionVisitor<Map<K, V>>, MapBinderBinding<Map<K, V>> {
834-
final RealMapProvider<K, V> delegate;
835-
836-
ExtensionRealMapProvider(RealMapProvider<K, V> delegate) {
837-
super(delegate.bindingSelection);
838-
this.delegate = delegate;
839-
}
840824

841825
BindingSelection<K, V> getBindingSelection() {
842826
return bindingSelection;
843827
}
844828

845-
@Override
846-
protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException {
847-
delegate.doInitialize(injector, errors);
848-
}
849-
850-
@Override
851-
protected Map<K, V> doProvision(InternalContext context, Dependency<?> dependency)
852-
throws InternalProvisionException {
853-
return delegate.doProvision(context, dependency);
854-
}
855-
856-
@Override
857-
public Set<Dependency<?>> getDependencies() {
858-
return delegate.getDependencies();
859-
}
860-
861829
@Override
862830
@SuppressWarnings("unchecked")
863831
public <B, W> W acceptExtensionVisitor(
@@ -1041,42 +1009,34 @@ private MultimapBinder(BindingSelection<K, V> bindingSelection) {
10411009
this.bindingSelection = bindingSelection;
10421010
}
10431011

1012+
@SuppressWarnings({"unchecked", "rawtypes"}) // we use raw Key to link bindings together.
10441013
@Override
10451014
public void configure(Binder binder) {
10461015
// Binds a Map<K, Set<Provider<V>>>
1047-
Provider<Map<K, Set<Provider<V>>>> multimapProvider =
1048-
new RealProviderMultimapProvider<K, V>(bindingSelection.getMapKey());
1049-
binder.bind(bindingSelection.getProviderSetMultimapKey()).toProvider(multimapProvider);
1016+
binder
1017+
.bind(bindingSelection.getProviderSetMultimapKey())
1018+
.toProvider(new RealProviderMultimapProvider<K, V>(bindingSelection.getMapKey()));
10501019

10511020
// Provide links from a few different public keys to the providerMultimapKey.
10521021
// The collection this exposes is internally an ImmutableMap, so it's OK to massage
10531022
// the guice Provider to jakarta Provider in the value (since the guice Provider implements
10541023
// jakarta Provider).
1055-
@SuppressWarnings({"unchecked", "rawtypes"})
1056-
Provider<Map<K, Set<jakarta.inject.Provider<V>>>> jakartaProvider =
1057-
(Provider) multimapProvider;
10581024
binder
10591025
.bind(bindingSelection.getJakartaProviderSetMultimapKey())
1060-
.toProvider(jakartaProvider);
1026+
.to((Key) bindingSelection.getProviderSetMultimapKey());
10611027

1062-
@SuppressWarnings({"unchecked", "rawtypes"})
1063-
Provider<Map<K, Collection<Provider<V>>>> collectionProvider = (Provider) multimapProvider;
10641028
binder
10651029
.bind(bindingSelection.getProviderCollectionMultimapKey())
1066-
.toProvider(collectionProvider);
1030+
.to((Key) bindingSelection.getProviderSetMultimapKey());
10671031

1068-
@SuppressWarnings({"unchecked", "rawtypes"})
1069-
Provider<Map<K, Collection<jakarta.inject.Provider<V>>>> collectionJakartaProvider =
1070-
(Provider) multimapProvider;
10711032
binder
10721033
.bind(bindingSelection.getJakartaProviderCollectionMultimapKey())
1073-
.toProvider(collectionJakartaProvider);
1034+
.to((Key) bindingSelection.getProviderSetMultimapKey());
10741035

10751036
// Binds a Map<K, Set<V>>
1076-
@SuppressWarnings({"unchecked", "rawtypes"})
1077-
Provider<Map<K, Set<V>>> realMultimapProvider =
1078-
new RealMultimapProvider(bindingSelection.getMapKey());
1079-
binder.bind(bindingSelection.getMultimapKey()).toProvider(realMultimapProvider);
1037+
binder
1038+
.bind(bindingSelection.getMultimapKey())
1039+
.toProvider(new RealMultimapProvider(bindingSelection.getMapKey()));
10801040
}
10811041

10821042
@Override

core/src/com/google/inject/internal/RealMultibinder.java

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -96,35 +96,27 @@ static <T> TypeLiteral<Set<? extends T>> setOfExtendsOf(TypeLiteral<T> elementTy
9696
this.bindingSelection = new BindingSelection<>(key);
9797
}
9898

99+
@SuppressWarnings({"unchecked", "rawtypes"}) // we use raw Key to link bindings together.
99100
@Override
100101
public void configure(Binder binder) {
101102
checkConfiguration(!bindingSelection.isInitialized(), "Multibinder was already initialized");
102103

103-
RealMultibinderProvider<T> setProvider = new RealMultibinderProvider<T>(bindingSelection);
104104
// Bind the setKey to the provider wrapped w/ extension support.
105105
binder
106106
.bind(bindingSelection.getSetKey())
107-
.toProvider(new ExtensionRealMultibinderProvider<>(setProvider));
108-
// Bind the <? extends T> to the provider w/o extension support.
109-
// It's important the exactly one binding implement the extension support and show
110-
// the other keys as aliases, to adhere to the extension contract.
111-
binder.bind(bindingSelection.getSetOfExtendsKey()).toProvider(setProvider);
112-
113-
Provider<Collection<Provider<T>>> collectionOfProvidersProvider =
114-
new RealMultibinderCollectionOfProvidersProvider<T>(bindingSelection);
107+
.toProvider(new RealMultibinderProvider<>(bindingSelection));
108+
binder.bind(bindingSelection.getSetOfExtendsKey()).to(bindingSelection.getSetKey());
109+
115110
binder
116111
.bind(bindingSelection.getCollectionOfProvidersKey())
117-
.toProvider(collectionOfProvidersProvider);
112+
.toProvider(new RealMultibinderCollectionOfProvidersProvider<T>(bindingSelection));
118113

119114
// The collection this exposes is internally an ImmutableList, so it's OK to massage
120115
// the guice Provider to jakarta Provider in the value (since the guice Provider implements
121116
// jakarta Provider).
122-
@SuppressWarnings("unchecked")
123-
Provider<Collection<jakarta.inject.Provider<T>>> jakartaProvider =
124-
(Provider) collectionOfProvidersProvider;
125117
binder
126118
.bind(bindingSelection.getCollectionOfJakartaProvidersKey())
127-
.toProvider(jakartaProvider);
119+
.to((Key) bindingSelection.getCollectionOfProvidersKey());
128120
}
129121

130122
public void permitDuplicates() {
@@ -218,7 +210,8 @@ public int hashCode() {
218210
* so it can be used to supply a {@code Set<T>} and {@code Set<? extends T>}, the latter being
219211
* useful for Kotlin support.
220212
*/
221-
private static final class RealMultibinderProvider<T> extends BaseFactory<T, Set<T>> {
213+
private static final class RealMultibinderProvider<T> extends BaseFactory<T, Set<T>>
214+
implements ProviderWithExtensionVisitor<Set<T>>, MultibinderBinding<Set<T>> {
222215
List<Binding<T>> bindings;
223216
SingleParameterInjector<T>[] injectors;
224217
boolean permitDuplicates;
@@ -281,33 +274,6 @@ private InternalProvisionException newDuplicateValuesException(T[] values) {
281274
bindingSelection.getSetKey(), bindings, values, ImmutableList.of(getSource())));
282275
return new InternalProvisionException(message);
283276
}
284-
}
285-
286-
/**
287-
* Implementation of BaseFactory that exposes details about the multibinder through the extension
288-
* SPI.
289-
*/
290-
private static final class ExtensionRealMultibinderProvider<T> extends BaseFactory<T, Set<T>>
291-
implements ProviderWithExtensionVisitor<Set<T>>, MultibinderBinding<Set<T>> {
292-
final RealMultibinderProvider<T> delegate;
293-
294-
ExtensionRealMultibinderProvider(RealMultibinderProvider<T> delegate) {
295-
// Note: method reference doesn't work for the 2nd arg for some reason when compiling on java8
296-
super(delegate.bindingSelection, bs -> bs.getDependencies());
297-
this.delegate = delegate;
298-
}
299-
300-
@Override
301-
protected void doInitialize() {
302-
delegate.doInitialize();
303-
}
304-
305-
@Override
306-
protected ImmutableSet<T> doProvision(InternalContext context, Dependency<?> dependency)
307-
throws InternalProvisionException {
308-
return delegate.doProvision(context, dependency);
309-
}
310-
311277
@SuppressWarnings("unchecked")
312278
@Override
313279
public <B, V> V acceptExtensionVisitor(

core/src/com/google/inject/internal/RealOptionalBinder.java

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ public LinkedBindingBuilder<T> setBinding() {
183183
return binder.bind(getKeyForActualBinding());
184184
}
185185

186+
@SuppressWarnings({"unchecked", "rawtypes"}) // we use raw Key to link bindings together.
186187
@Override
187188
public void configure(Binder binder) {
188189
bindingSelection.checkNotInitialized();
@@ -196,45 +197,34 @@ public void configure(Binder binder) {
196197
// * T is bound
197198

198199
// cgcb.Optional<c.g.i.Provider<T>>
199-
InternalProviderInstanceBindingImpl.Factory<Optional<Provider<T>>> optionalProviderFactory =
200-
new RealOptionalProviderProvider<>(bindingSelection);
201-
binder.bind(key.ofType(optionalOfProvider(typeLiteral))).toProvider(optionalProviderFactory);
200+
Key<Optional<Provider<T>>> guavaOptProviderKey = key.ofType(optionalOfProvider(typeLiteral));
201+
binder
202+
.bind(guavaOptProviderKey)
203+
.toProvider(new RealOptionalProviderProvider<>(bindingSelection));
202204
// ju.Optional<c.g.i.Provider<T>>
203-
InternalProviderInstanceBindingImpl.Factory<java.util.Optional<Provider<T>>>
204-
javaOptionalProviderFactory = new JavaOptionalProviderProvider<>(bindingSelection);
205+
Key<java.util.Optional<Provider<T>>> javaOptProviderKey =
206+
key.ofType(javaOptionalOfProvider(typeLiteral));
205207
binder
206-
.bind(key.ofType(javaOptionalOfProvider(typeLiteral)))
207-
.toProvider(javaOptionalProviderFactory);
208+
.bind(javaOptProviderKey)
209+
.toProvider(new JavaOptionalProviderProvider<>(bindingSelection));
208210

209211
// Provider is assignable to jakarta.inject.Provider and the provider that the factory contains
210212
// cannot be modified so we can use some rawtypes hackery to share the same implementation.
211213
// cgcb.Optional<jakarta.inject.Provider<T>>
212-
@SuppressWarnings("unchecked")
213-
InternalProviderInstanceBindingImpl.Factory<Optional<jakarta.inject.Provider<T>>>
214-
optionalJakartaProviderFactory =
215-
(InternalProviderInstanceBindingImpl.Factory) optionalProviderFactory;
216-
binder
217-
.bind(key.ofType(optionalOfJakartaProvider(typeLiteral)))
218-
.toProvider(optionalJakartaProviderFactory);
214+
binder.bind(key.ofType(optionalOfJakartaProvider(typeLiteral))).to((Key) guavaOptProviderKey);
219215
// ju.Optional<jakarta.inject.Provider<T>>
220-
@SuppressWarnings("unchecked")
221-
InternalProviderInstanceBindingImpl.Factory<java.util.Optional<jakarta.inject.Provider<T>>>
222-
javaOptionalJakartaProviderFactory =
223-
(InternalProviderInstanceBindingImpl.Factory) javaOptionalProviderFactory;
224216
binder
225217
.bind(key.ofType(javaOptionalOfJakartaProvider(typeLiteral)))
226-
.toProvider(javaOptionalJakartaProviderFactory);
218+
.to((Key) javaOptProviderKey);
227219

228220
// cgcb.Optional<T>
229-
Key<Optional<T>> optionalKey = key.ofType(optionalOf(typeLiteral));
221+
Key<Optional<T>> guavaOptKey = key.ofType(optionalOf(typeLiteral));
230222
binder
231-
.bind(optionalKey)
232-
.toProvider(new RealOptionalKeyProvider<>(bindingSelection, optionalKey));
223+
.bind(guavaOptKey)
224+
.toProvider(new RealOptionalKeyProvider<>(bindingSelection, guavaOptKey));
233225
// ju.Optional<T>
234-
Key<java.util.Optional<T>> javaOptionalKey = key.ofType(javaOptionalOf(typeLiteral));
235-
binder
236-
.bind(javaOptionalKey)
237-
.toProvider(new JavaOptionalProvider<>(bindingSelection, javaOptionalKey));
226+
Key<java.util.Optional<T>> javaOptKey = key.ofType(javaOptionalOf(typeLiteral));
227+
binder.bind(javaOptKey).toProvider(new JavaOptionalProvider<>(bindingSelection, javaOptKey));
238228
}
239229

240230
/** Provides the binding for {@code java.util.Optional<T>}. */
@@ -661,8 +651,7 @@ Dependency<?> getDependency() {
661651

662652
/** Implementation of {@link OptionalBinderBinding#containsElement}. */
663653
boolean containsElement(Element element) {
664-
// All of our bindings are ProviderInstanceBindings whose providers extend
665-
// RealOptionalBinderProviderWithDependencies and have 'this' as its binding selection.
654+
// We contain it if the provider is us.
666655
if (element instanceof ProviderInstanceBinding) {
667656
jakarta.inject.Provider<?> providerInstance =
668657
((ProviderInstanceBinding<?>) element).getUserSuppliedProvider();
@@ -671,11 +660,16 @@ boolean containsElement(Element element) {
671660
.bindingSelection.equals(this);
672661
}
673662
}
663+
674664
if (element instanceof Binding) {
665+
TypeLiteral<?> typeLiteral = key.getTypeLiteral();
675666
Key<?> elementKey = ((Binding) element).getKey();
676-
// if it isn't one of the things we bound directly it might be an actual or default key
667+
// if it isn't one of the things we bound directly it might be an actual or default key,
668+
// or the javax or jakarta aliases of the optional provider.
677669
return elementKey.equals(getKeyForActualBinding())
678-
|| elementKey.equals(getKeyForDefaultBinding());
670+
|| elementKey.equals(getKeyForDefaultBinding())
671+
|| elementKey.equals(key.ofType(javaOptionalOfJakartaProvider(typeLiteral)))
672+
|| elementKey.equals(key.ofType(optionalOfJakartaProvider(typeLiteral)));
679673
}
680674
return false; // cannot match;
681675
}

0 commit comments

Comments
 (0)