Code Monkey home page Code Monkey logo

Comments (24)

gk5885 avatar gk5885 commented on July 19, 2024 3

Here's how members injection methods work:

  1. You can make a members injection method for any type that has @Inject anywhere in its class hierarchy. If it doesn't, you'll get an error.
  2. All @Injected members in the entire type hierarchy will be injected: the argument type and all supertypes
  3. No members will be @Injected for subtypes of the argument type.

So, given the following:

final class Dep {
  @Inject Dep() {}
}

class A {
  @Inject Dep a;
}

class B extends A {
  @Inject Dep b;
}

class C extends B {
  @Inject Dep c;
}

@Component
interface TestComponent {
  B injectB(B instance);
}

The following test will pass:

TestComponent component = Dagger_TestComponent.create();
C instance = component.injectB(new C());
assertThat(instance.a).isNotNull();
assertThat(instance.b).isNotNull();
assertThat(instance.c).isNull();

from dagger.

f2prateek avatar f2prateek commented on July 19, 2024

I should clarify that component has methods for both the subclass and base class.

public interface MyComponent {
  void inject(BaseActivity activity);

  void inject(MainActivity activity);
}

from dagger.

JakeWharton avatar JakeWharton commented on July 19, 2024

So what's the question or what doesn't work?
On Nov 16, 2014 1:22 PM, "Prateek Srivastava" [email protected]
wrote:

I should clarify that component has methods for both subclass and base
class.

public interface MyComponent {
void inject(BaseActivity activity);

void inject(MainActivity activity);
}


Reply to this email directly or view it on GitHub
#73 (comment).

from dagger.

f2prateek avatar f2prateek commented on July 19, 2024

Yeah accidentally hit enter too soon, but is there a pattern for injecting dependencies from a base class, rather than calling inject in each of the subclasses manually.

from dagger.

JakeWharton avatar JakeWharton commented on July 19, 2024

@f2prateek,

In Dagger 1, you could call inject from a base class and have all dependencies satisfied for subclasses.

This is true iff you included all subclasses on a module's injects= which was included in the graph with which you were injecting.

Dagger 2 is no different. You need to include all subclasses in a component so that the generated code can be wired to fulfill the contracts.

from dagger.

rlei avatar rlei commented on July 19, 2024

so this means in Dagger 2 we'll have to explicitly call inject in each of my Activity classes like the following:

    @Singleton
    @Component
    interface AppComponent {
        BaseActivity inject(BaseActivity activity);
        SomeActivity inject(SomeActivity activity);
    }

    class BaseActivity extends Activity {
        [snip]
        void onCreate() {
            super.onCreate(savedInstanceState);
            appComponent = Dagger_AppComponent.builder()
                [snip]
               .build();
            }
        }
        AppComponent getComponent() {
             return appComponent;
        }
    }

    class SomeActivity extends BaseActivity {
        @Inject Dep dep;
        void onCreate() {
            super.onCreate(savedInstanceState);
            getComponent().inject(this);
        }
    }

In Dagger 1 it's only needed to call inject in BaseActivity and the injection to subclass instances are all handled. I can live with Dagger 2's more explicit injection but it would be a bit simpler to convert existing projects with Dagger 1 way.

from dagger.

JakeWharton avatar JakeWharton commented on July 19, 2024

@rlei No, it doesn't. It can still be in the base class.

from dagger.

rlei avatar rlei commented on July 19, 2024

@JakeWharton no it doesn't work, as far as I tested.

Basically what I did is in my last comment. Putting getComponent().inject(this) in BaseActivity.onCreate() only injects for BaseActivity. I had to add getComponent().inject(this) to each subclass onCreate() individually to let the injection happen.

My module and component code is as following:

    @Module
    public class AppModule {
        [snip]
        public AppModule(Application application) {
            this.application = application;
        }
        @Provides @Singleton
        DaoSession provideDaoSession() {
            [snip]
        }
    }

    @Singleton
    @Component(modules = AppModule.class)
    public interface AppComponent {
        void inject(MyApplication application);
        void inject(BaseActivity activity);
        void inject(ExpenseDetailsActivity activity);
        void inject(MainActivity activity);
        [snip]
    }

Did I miss anything?

[EDIT]: also updated my last comment.

from dagger.

JakeWharton avatar JakeWharton commented on July 19, 2024

Ah, right right. This is in the JLS.

@gk5885 The difference in your example is that it would be a method in A calling inject(this) rather than one knowing about C.

Here's a fully working example of the problem:

abstract class BaseThing {
  @Inject String foo;

  void doIt() {
    Dagger_BaseComponent.create().inject(this);
  }
}
class RealThing extends BaseThing {
  @Inject CharSequence bar;
}

@Module
class BaseModule {
  @Provides String provideString() { return "String!"; }
  @Provides CharSequence provideCharSequence() { return "CharSeq!"; }
}

@Component(modules = BaseModule.class)
interface BaseComponent {
  void inject(BaseThing baseThing);
  void inject(RealThing realThing);
}

public class BaseExample {
  public static void main(String... args) {
    RealThing realThing = new RealThing();
    realThing.doIt();
    System.out.println("String? => " + realThing.foo);
    System.out.println("CharSeq? => " + realThing.bar);
  }
}

This was a common pattern in Dagger 1.

from dagger.

gk5885 avatar gk5885 commented on July 19, 2024

Right, this will definitely be a change from how things were done in D1. Essentially, the ObjectGraph used to do a bunch of reflection to figure out the type of the object being injected and dispatch to the right logic. You could do exactly the same thing if you wanted, but the cost of the little extra bit of verbosity makes for a much more efficient code path.

Plus, in experimenting with Android apps in D2 we found that infrastructure around managing components (as opposed to ObjectGraphs) really wasn't worth its weight. We had apps with a base activity that held a reference to a graph, but when we moved it to D2 it just really didn't have as much value since the components are strongly typed and often more granular (i.e. you may end up with separate activity-scoped components per activity rather than a huge graph for all activities). Take a look at https://github.com/gk5885/dagger-android-sample/ and see if the pattern in that (albeit trivial) example works for you.

from dagger.

f2prateek avatar f2prateek commented on July 19, 2024

@gk5885 That sounds good to me! It should be something that should be mentioned in the migration guide when it is released.

from dagger.

serandel avatar serandel commented on July 19, 2024

@f2prateek I made an abstract method in my BaseActivity that creates the Component and calls inject. That way each concrete class only have to do something like Dagger_FooComponent.create().inject(this).

from dagger.

pakoito avatar pakoito commented on July 19, 2024

What is the use case here for library projects? I have a library project with methods accepting and abstract class containing a field the user will need to do some work. That field has to be injected from the library at runtime. The programmer can't go and add those lines of code to the component interface.

from dagger.

gk5885 avatar gk5885 commented on July 19, 2024

@pakoito, I'm not quite following what you're asking. Can you show some example code?

from dagger.

pakoito avatar pakoito commented on July 19, 2024

In a library module:

public abstract class BaseSystem {
  @Inject
  protected World projectWorld;
}

@Singleton
public class World {
 @Inject
  public World(){} 

 public void hey(){}
}

public class Framework {
    @Component
    public interface MyComponent { 
        void inject(BaseSystem system);
    } 

  public Framework(BaseSystem mySystem) {
     // Ideally, but not current
     component.inject(mySystem);
  } 
}

And then in my impl module:

public abstract class ImplSystem extends BaseSystem {
  public void doWork(){
      projectWorld.hey();
  }

At the impl module we have no access to MyComponent to add new classes to be injected.

from dagger.

pakoito avatar pakoito commented on July 19, 2024

My current implementation uses Artemis-odb for this injections, but they use Reflection so it's a tradeoff Dagger may not want to make.

from dagger.

svenjacobs avatar svenjacobs commented on July 19, 2024

Performing the dependency injection in an abstract base class of Activity, Fragment, etc. seems to be a common pattern in Android development with Dagger 1 because it's very handy. I'm using it, too.

How this can be achieved with Dagger 2 respectively alternative patterns should be clearly documented in a (migration) guide.

from dagger.

svenjacobs avatar svenjacobs commented on July 19, 2024

Maybe injecting dependencies in a base class would work if a component supports generics? See #65.

from dagger.

tbroyer avatar tbroyer commented on July 19, 2024

FYI, I've just pushed out a 1.0-SNAPSHOT of Bullet • to the Sonatype OSS repository, so you can make @JakeWharton's example above work (well, it should work, I haven't tested):

abstract class BaseThing {
  @Inject String foo;

  void doIt() {
    // Wrap the Component into the generated ObjectGraph:
    new Bullet_BaseComponent(Dagger_BaseComponent.create()).inject(this);
  }
}

class RealThing extends BaseThing {
  @Inject CharSequence bar;
}

@Module
class BaseModule {
  @Provides String provideString() { return "String!"; }
  @Provides CharSequence provideCharSequence() { return "CharSeq!"; }
}

@Component(modules = BaseModule.class)
interface BaseComponent {
  // You don't need to include a method for BaseThing here, only your concrete subclasses.
  void inject(RealThing realThing);
}

public class BaseExample {
  public static void main(String... args) {
    RealThing realThing = new RealThing();
    realThing.doIt();
    System.out.println("String? => " + realThing.foo);
    System.out.println("CharSeq? => " + realThing.bar);
  }
}

from dagger.

cgruber avatar cgruber commented on July 19, 2024

This is less an issue, and more a discussion - I'm not sure where to go from here, but I'm going to close the issue for now, and if there's a feature request and/or further relevant discussion, it can be reopened. Given that #102 seems to be related, maybe further discussion can happen there.

from dagger.

ralph-bergmann avatar ralph-bergmann commented on July 19, 2024

@JakeWharton your example does not work for me.

The DaggerBaseComponent.create().inject(this) call in BaseThing uses the inject(BaseThing baseThing)method and not the inject(RealThing realThing) so realThing.bar is null.

I fixed it with a doIt()method in RealThing.

But I have another question.

How does the code look like if RealThing want's to add it's own Component / Modul? If I create a RealComponent / Modul the BaseThing injection doesn't work. Do I have to add all subclass injections in the BaseModul?

from dagger.

mcfongtw avatar mcfongtw commented on July 19, 2024

Tried the example posted by @JakeWharton, and member in SubClass was not injected. However, as I explore more in the generated code, that could possibly be done via the following:

abstract class BaseThing {
    @Inject
    String foo;

    public BaseThing() {
        this(DaggerBaseComponent.create());
    }

    public BaseThing(BaseComponent component) {
        component.inject(this);
    }
}
class RealThing extends BaseThing {
    @Inject CharSequence bar;

    public RealThing() {
        this(DaggerBaseComponent.create());
    }

    public RealThing(BaseComponent component) {
        component.inject(this);
    }
}

@Module
class BaseModule {
    @Provides
    String provideString() { return "String!"; }
    @Provides CharSequence provideCharSequence() { return "CharSeq!"; }
}

@Component(modules = BaseModule.class)
interface BaseComponent {
    void inject(BaseThing baseThing);
    void inject(RealThing realThing);
}

public class BaseExample {
    public static void main(String... args) {
        RealThing realThing = new RealThing();

        System.out.println("String? => " + realThing.foo);
        System.out.println("CharSeq? => " + realThing.bar);
    }
}

This way, bar is injected properly.

from dagger.

vinhnemo avatar vinhnemo commented on July 19, 2024
@Singleton
@Component(modules = {ABC.class})
public interface BaseComponent<T extends Base> {
    void inject(T handler);
}

I tried to do something like this but compiled error. Any approach for this? Thanks

from dagger.

bcorso avatar bcorso commented on July 19, 2024

@vinhnemo Dagger's job is to generate an implementation of your interface, but Dagger has no idea what T is so there's no way for Dagger to know how to "inject" T.

You probably want to start a new issue since this seems like a different question, and please add more details about what you're actually trying to accomplish.

from dagger.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.