Skip to content
This repository has been archived by the owner on Oct 17, 2023. It is now read-only.

MembersInjector for late injection #130

Open
mlykotom opened this issue Dec 16, 2019 · 9 comments
Open

MembersInjector for late injection #130

mlykotom opened this issue Dec 16, 2019 · 9 comments

Comments

@mlykotom
Copy link

AssistedInject only works for construction injection.
Dagger on the other hand is able to inject stuff after construction with *_MembersInjector for some @Inject lateinit var dep: Dependency.

Is it somehow possible to have this for AssistedInject?

@JakeWharton
Copy link
Contributor

This is not possible with the library, no. But you don't really need a library to do this. You can members inject the instance and then set whatever other fields you want directly.

The reason assisted inject only works for constructor injection is that you cannot ask Dagger to partially call a constructor and then partially supply the other arguments.

@mlykotom
Copy link
Author

  1. I understand that you don't need the library to do this and can somehow set fields manually, but since Dagger allows this, doesn't AssistedInject kind of breaks the feature?

  2. I'm not sure if I understand your second point.

But.
In the generated factory, there could be added MembersInjector<TheClass> and after instantiating the class, just call injectMembers on it?

public final class TheClass_AssistedFactory implements TheClass.Factory {
  private final Provider<ConstructorDep> constructorDep;

  private final MembersInjector<TheClass> membersInjector;

  @Inject
  public TheClass_AssistedFactory(
        Provider<ConstructorDep> constructorDep,
        MembersInjector<TheClass> membersInjector) {
    this.constructorDep = constructorDep;
    this.membersInjector = membersInjector;
  }

  @Override
  public MViewModel create(AssistedDep assistedDep) {
    TheClass obj = new TheClass(
            constructorDep.get(),
            assistedDep);

    membersInjector.injectMembers(obj);
    return obj;
  }
}

Nice thing about this is, that if you don't have any @Inject lateinit var inside the class, Dagger will use NoOpMembersInjector.INSTANCE which does nothing and also if there's have inheritance, it will include the base member injectors.


Or shouldn't there be at least some warning?

@JakeWharton
Copy link
Contributor

JakeWharton commented Dec 16, 2019

Oh, you're saying you want members injection to be performed on constructor-injected types? I see. I suppose that's reasonable for consistency of behavior.

I thought you wanted assisted injection on a type that was solely members injected.

Can I ask why you are doing this? Members injection is a truly terrible thing.

@mlykotom
Copy link
Author

mlykotom commented Dec 16, 2019

I agree, members injection seems like a terrible thing.

The reason is android ViewModel with inheritance:

  • we have "pure" Dagger with ViewModels
  • all ViewModels inherit from some BaseViewModel class
  • for some historical reason (🤷‍♂ ) there's members injection in the BaseViewModel, therefore when inheriting from the base, it doesn't need to have inject param in all inherited constructors
  • we'd like to add AssistedInject to the project, so that we can use SavedStateHandle
  • if we do that, you never can access the members injection.

I know, that it seem like a terrible thing, but also if (for some reason) you have members injection without inheritance, it's the same - no warning, crashes at runtime.

I was checking briefly how the MembersInjector works and for specific class it includes even parent MembersInjector, e.g for SomeViewModel inheriting BaseViewModel, it properly injects SomeViewModel dependencies and also BaseViewModel dependencies.

This means, that injecting MembersInjector<TheClass> into generated factory should (?) be safe and sufficient.

@JakeWharton
Copy link
Contributor

So one trouble here is that AssistedInject is not Dagger-specific and thus cannot depend on the MembersInjector type. It's purely a javax.inject-based injector, at least in the core.

@mlykotom
Copy link
Author

mlykotom commented Dec 17, 2019

I see the issue. I was thinking, that it would be possible to extend the pure AssistedInject processor to generate the code, but then not sure, how to pass the information about what to generate.

a) pass some data from module to module somehow?
b) AssistedInjectDagger2Processor would generate another annotation for the members injection which AssistedInjectProcessor would parse and generated the data

I don't like either option, but not sure how else could be solved

@JakeWharton
Copy link
Contributor

FYI this is no longer a problem as AssistedInjection has moved to Dagger and all that's left is inflation injection. We can add special handling for MembersInjector now.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants
@JakeWharton @mlykotom and others