Comments (3)
This has been discussed previously:
from dagger.
@JakeWharton Thanks for the links! Good to know I'm not alone in wanting such a feature :^)
It seems like #2026 is the most thorough discussion of the limitations and implications that would make such a feature unfeasible; however, I think the approach I suggest mitigates those concerns. I would like to press this a bit, because a feature like I describe would make Dagger significantly less annoying for my use case. If this discussion would be more welcome in one of the linked tickets, please let me know.
Particularly
There's no way for Dagger to know that your type should be added to the set in its normal traversal.
I did anticipate this - I assume it's complicated and prohibitively slow to search the class path for all subtypes of the injected type. I'm sure that injecting Set<Any>
without any constraint on which Any
you're interested in would be a fun corner case. This is why I suggest constraining the @IntoSet
or equivalent annotation with the specific type of the collection to be injected (IntoSet(::ServiceInterface)
in my example). In fact, I see this idea mentioned briefly in #2026
Dagger would either need to ... allow you to pass that information in via the annotation (which doesn't work well with parameterized types)
For my use case, at least, this is a non-issue. And if I did really need to inject a parameterized type, there are workarounds as long as I'm willing to shape my code for Dagger's better understanding, which I am. For example, if we rework the example like
interface ServiceInterface<Result>
interface A
interface A1: A
interface A2: A
interface B
class ServiceA1 @Inject internal constructor(...): ServiceInterface<A1>
class ServiceA2 @Inject internal constructor(...): ServiceInterface<A2>
class ServiceB @Inject internal constructor(...): ServiceInterface<B>
and I want to inject a Set<ServiceInterface<A>>
into my application, I could add an intermediate interface, along the lines of
interface AServiceInterface: ServiceInterface<A>
class ServiceA1 @Inject @IntoSet<AServiceInterface::class> internal constructor(...): AServiceInterface
class ServiceA2 @Inject @IntoSet<AServiceInterface::class> internal constructor(...): AServiceInterface
class App @Inject internal constructor(
private val services: Set<@JvmSuppressWildcards AServiceInterface<*>>,
)
Not ideal, but certainly workable and significantly preferable to enumerating the service implementations in a module.
As for the other concerns raised
There's no way to remove the type from the set. For example, you still want to inject Set but you don't want that particular class in the set. With modules you just remove the module, but with this solution you would have to remove the class from your class path, which can either be difficult or impossible if it's used elsewhere.
One of the useful features of multibindings is that the set can change depending on which component you install the module int. With this solution, you don't choose a component so it's ambiguous where Dagger should install it.
Acknowledged that the modules provide more fine-grained control over what instances are included in the Set, but as I have observed the tradeoff is more boilerplate. It seems to me there is room for both approaches.
from dagger.
I did anticipate this - I assume it's complicated and prohibitively slow to search the class path for all subtypes of the injected type. I'm sure that injecting Set without any constraint on which Any you're interested in would be a fun corner case. This is why I suggest constraining the @IntoSet or equivalent annotation with the specific type of the collection to be injected (IntoSet(::ServiceInterface) in my example).
It isn't just a matter of constraining. Searching the classpath is just something Dagger doesn't do and probably isn't something we want it to do in the future. This basically limits the solution space to Hilt where we could generate a Dagger module.
Not ideal, but certainly workable and significantly preferable to enumerating the service implementations in a module.
The issues with things like qualifiers and parameterized types are things you can workaround, if you know about them. But that is actually the main issue. I don't want to create a new API for doing something just to save on boilerplate, but then in addition to the cognitive overhead of having two ways to do something, you also have the overhead of learning certain features don't work with other features. IMO, it isn't worth the tradeoff as we already know it is difficult for people to get up to speed on Dagger features and there is already a fair amount of multiple ways to do the same thing that adds confusion.
I feel like if we're going to add the cognitive overhead cost of doing something multiple ways, the other way has to be pretty clean and intuitive and cover a lot of cases. So far, I just haven't seen anything or come up with anything that meets that. Closing this since #2026 (comment) I think also covers a lot of the current thoughts on this.
Separate aside:
Separately, I'm going to assume your example falls into this other issue because it is just an example and that this probably doesn't apply to you, but just for others who may be reading this since I have seen this in code before, if you have a single module that defines ALL of your set contributions, you don't need multibindings.
@Module
interface ServiceModule {
@Bind
@IntoSet
fun service1(service: Service1): ServiceInterface
@Bind
@IntoSet
fun service2(service: Service2): ServiceInterface
...
@Bind
@IntoSet
fun serviceN(service: ServiceN): ServiceInterface
}
Should just be rewritten as
@Module
interface ServiceModule {
@Provides
fun services(service1: Service1, service2: Service2, ..., serviceN: ServiceN): Set<ServiceInterface> {
return setOf(service1, service2, ..., serviceN)
}
}
You only need multibindings if you need to make contributions from multiple sites where no single piece of code knows what all of the contributions should be.
from dagger.
Related Issues (20)
- [Dagger-Hilt] Can't get viewModel in composable by Hilt HOT 1
- Why does Provides in a Companion Object work? HOT 6
- Update Dagger guava dependency to address CVE-2023-2976 HOT 2
- Add KMP support for @HiltViewModel annotation HOT 2
- Dagger resolution and dynamic feature module HOT 1
- Feature request: Manually regenerate application component HOT 1
- Using TestContainer.com HOT 2
- Detect dependency cycles containing Lazy or Provider during the compilation time HOT 6
- error when ksp.useKSP2=true HOT 2
- Suppress annotation on @Inject is not honored on the Factory HOT 1
- [KSP2] Dagger and Hilt incompatibility with KSP2 HOT 2
- [KSP2] NullPointerException: null cannot be cast to non-null type androidx.room.compiler.processing.XType HOT 1
- App crashing with NPE for some classes when Lazy Class Key is used HOT 4
- OutOfMemoryError with Maven HOT 1
- DaggerAppComponent not creating in the version 2.51.1 HOT 3
- java.lang.ClassNotFoundException: dagger.spi.shaded.androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor. Hilt 2.49+ HOT 1
- how to manually generate module HOT 1
- Explain how to add dagger jar files manually to the android project HOT 2
- Annotate interface with default Bind implementation HOT 2
- Transitive vulnerability from symbol-processing-api HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dagger.