google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.44k stars 2.02k forks source link

Assisted inject for factory method #4448

Open jakub-bochenski opened 1 month ago

jakub-bochenski commented 1 month ago

I have a factory method (e.g. provided by 3rd party, so I can't change it to constructor):

 public static MyDataService myDataService(DataFetcher dataFetcher, Config config)

I would like to crate an assisted factory out of it

@AssistedFactory
public interface MyDataServiceFactory {
  MyDataService create(Config config);
}

I don't think it's currently possible.

It seems to be this should be possible. I don't see why I should only be able to use assisted inject with constructors.

jakub-bochenski commented 1 month ago

For reference: https://stackoverflow.com/q/78966548/1237617

bcorso commented 1 month ago

Off the top of my head, MyDataService needs to be an @AssistedInject constructor for a few reasons:

  1. Dagger needs to generate factory/proxy classes for the constructor (e.g. to reduce generated code at the root and also to provide proxy methods so that other bindings can access it without forcing your constructor to be public) and without the annotation Dagger's processor doesn't run.
  2. It tells Dagger which constructor to use when creating the object (there could be multiple constructors)
  3. Dagger also needs the assisted parameters to be annotated with @Assisted so that it knows which parameters will be provided by the user (you can't base this off of just the type, e.g. with @AssistedInject MyClass(@Assisted String, String) Dagger wouldn't know which String to inject and which is assisted without the proper annotations.
jakub-bochenski commented 1 month ago

You could enable this on a provider method

@AssistedInject  @Provides MyDataService myDataServiceProvider(@Assisted String foo, String bar) {
     return myDataService(foo,bar)
}
bcorso commented 1 month ago

That's a fair request.

I'll leave this open as a feature request for implementing an @AssistedProvides equivalent of @AssistedInject.

undermark5 commented 1 month ago

In the mean time, isn't a valid workaround here to define a class that uses the @AssistedInject constructor, then provides a method which calls the static function and returns the instance (perhaps maintaining a reference to it if necessary)?

Still like the idea of @AssistedProvides (if we do have that, it would also make sense to have an @AssistedBinds as well IMO, I've got some instances where that would be useful (trying to keep the implementation of a class internal to some modules, but it requires some assisted parameters), but I can also see how that would be quite complicated, and @AssistedProvides should also be able to be used in such a scenario anyway.

jakub-bochenski commented 1 month ago

In the mean time, isn't a valid workaround here to define a class that uses the @AssistedInject constructor, then provides a method which calls the static function and returns the instance (perhaps maintaining a reference to it if necessary)?

Sure it's doable (as in "will work"), but the point is reducing the amount of boilerplate. I think it's not reducing boilerplate.

Personally in this case I just write the MyDataServiceFactory manually.