-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
TLDR: This is a feature request for allowing @BindsOptionalOf bindings to be conditionally provided at runtime, akin to how @ElementsIntoSet works for mulltibindings
Background: Conditionally providing multibindings
Say we have 1) a multibinding of Foos; and 2) an injectable implentation of Foo (i.e. FooImpl) :
@Multibinds fun foos(): Set<Foo>
@Provides fun fooImpl(): FooImpl { ... } // where FooImpl : FooSay we'd like to conditionally include FooImpl on Set<Foo> at compile time (e.g. include on beta builds, but not release ones). In this case we can:
// Include this on *beta* builds only
@Binds
@IntoSet
fun intoFoos(impl: FooImpl): FooIt is also possible to conditionally include FooImpl on Set<Foo> at runtime (e.g. depending on a runtime feature flag):
@Provides
@ElementsIntoSet
fun intoFoos(impl: FooImpl): Set<Foo> = if (featureEnabled) setOf(impl) else emptySet()Problem: Conditionally providing optional bindings
Let's change the example above slightly so that we have an optional Foo rather than a set of Foos:
@BindsOptionalOf fun optionalFoo(): Foo // ← change this
@Provides fun fooImpl(): FooImpl { ... } // where FooImpl : FooWe can still conditionally provide an Optional<Foo> at compile-time as follows:
// Include this on *beta* builds only
@Binds fun foo(impl: FooImpl): FooThe problem: there's no easy way to conditionally provide an Optional<Foo> at runtime. This is because there's no equivalent to @ElementsIntoSet for optional bindings.
Workaround
Fortunatelly there's a way to overcome the problem above. We need to replace @BindsOptionalOf fun optionalFoo(): Foo with:
@Provides
fun optionalFoo(@Bar foo: Optional<Optional<Foo>>): Optional<Foo> // ← change this
= if (foo.isPresent() && foo.get().isPresent()) foo.get().get() else Optional.empty
@Qualifier annotation class Bar // ← needed for disambiguating `Optional<Foo>` bindings
@BindsOptionalOf
@Bar
fun optionalOptionalFoo(): Optional<Foo> // ← add thisThen, we can conditionally provide an Optional<Foo> at runtime as follows:
@Provides
@Bar
fun foo(impl: FooImpl): Optional<Foo> = if (featureEnabled) Optional.of(impl) else Optional.empty()Potential solution (feature request)
The workaround above works, but it's far from ideal (e.g. having to use a qualifier, nested optionals, intermediate binding). Ideally I'd like to be able to write something like this:
@BindsOptionalOf fun optionalFoo(): Foo
@ProvidesOptionalOf // ← this doesn't exist
fun foo(impl: FooImpl): Optional<Foo> = if (featureEnabled) Optional.of(impl) else Optional.empty()Would it be possible to implement this feature?