-1

I am using dagger2 framework for dependency injection.

How to create instance of dependency objectB (AND INJECT) with a constructor injection. Class B has a parameter constructor. Please find the example below.

//This is class A, which is dependent on Class B.
//This has to create instance of B, with a (int) parameter.
class A {
    @Inject
    public B objectB;

    public A(int some_value){
        //This one I want to make it through dagger2
        //objectB = new B(some_value);

        BComponent bComponent = DaggerBComponent.builder().build();
        bComponent.provideB(this);
    }
}

//This is Class B, which has constructor injection.
//Constructor has a int parameter. 
class B {

    @Inject
    public B(int var){
        other_method(var);
    }
}

//This is dagger module, which provides Object B
@Module
public class BProvider {

    @Provides
    public B getB() {
        return new B();
    }
}

//This is dagger component, provide class-B dependency to class-A 
@Component(modules = {BProvider.class})
public interface BComponent {
    void provideB(A objA);
}
David Medenjak
  • 33,993
  • 14
  • 106
  • 134
Annada
  • 1,075
  • 1
  • 18
  • 21
  • What is `int some_value` and where does it come from? What is `int var` and where does it come from? If `B` has an Inject constructor, then why is there also a Module? Why does the Module call a constructor that doesn't exist??? – EpicPandaForce May 18 '18 at 22:32
  • 1
    Though EpicPandaForce's observations are very apt, and makes it a little hard to follow your question, it looks like you might be asking how to combine parameters from the object graph with one-off parameters that you previously passed in through the constructor. This is sometimes called _assisted injection_, and Dagger recommends a similar code generator called [AutoFactory](https://github.com/google/auto/tree/master/factory). I wrote about it in [this SO answer](https://stackoverflow.com/q/29175014/1426891). – Jeff Bowman May 18 '18 at 22:45
  • I am trying constructor injection to achieve dependency. ClassA depends on ClassB. And ClassB has parameter constructor, say ClassB(int param). This parameter is provided at runtime, so my confusion is how dagger is able to create object B. I am not sure, whether this is possible, as Dagger is a fully static, compile-time dependency injection framework.(https://google.github.io/dagger/) – Annada May 21 '18 at 09:47

1 Answers1

1

From the elaboration in the comments:

I am trying constructor injection to achieve dependency. ClassA depends on ClassB. And ClassB has parameter constructor, say ClassB(int param). This parameter is provided at runtime, so my confusion is how dagger is able to create object B.

If B's param is the same every time, across your object graph

This might be the case if your param is a key, ID, or other configuration setting. If so, you can use a @Provides method in a Module to teach Dagger how to provide a ClassB object when you ask for one.

@Module
public abstract class YourModule {
  @Provides static ClassB provideClassB() {
    return new ClassB(/* your constant here */);
  }
}

Because @Provides methods can take parameters that come from the object graph, you can even get your value from somewhere else:

@Module
public abstract class YourModule {
  @Provides static ClassB provideClassB(SomeDependendency someDep) {
    return new ClassB(someDep.getParameterForClassB());
  }
}

If B only takes custom parameters

This might be the case if your ClassB is a data object or disposable object, especially if you don't need to replace ClassB for testing. (Don't mock data objects.) If all of that is true, then ClassB doesn't need to be a part of your object graph. Call the constructor directly.

ClassB myB = new ClassB(someParameter);

Sometimes this distinction is called injectables versus newables: If you have complicated and interconnected classes that need to access one another, you have an injectable, and references to it should be provided externally. If you have a tightly-contained class that doesn't need substitution, you have a newable, and can call the constructor or static factory method directly.

If B has injected parameters AND constructor parameters

In some cases, a class like ClassB needs both one-off constructor parameters and injected parameters from the graph at the same time. Though this might be a subtle hint that the class is doing too much, there are common workarounds that combine those two inputs into the same list of constructor parameters. This is known as assisted injection, and allows for the creation of factory objects where the DI framework provides the factory and you use it to get the value you want.

/* in ClassB */ public ClassB(DepA a, DepB b, int param) { /* ... */ }

/* ClassBFactory */
public ClassBFactory {
  Provider<DepA> depAProvider;
  Provider<DepB> depBProvider;
  public ClassBFactory(
      Provider<DepA> depAProvider,
      Provider<DepB> depBProvider) {
    /* set depAProvider and depBProvider */
  }

  public ClassB get(int param) {
    return new ClassB(depAProvider.get(), depBProvider.get(), param);
  }
}

Because this is similar boilerplate-generation to Dagger, but more reusable in other dependency injection frameworks, Dagger recommends the Google project AutoFactory to generate that implementation based on inspecting the dependencies and classes. You'll need to add some annotations to ClassB to get that to work, but it will allow you to distinguish between graph-provided deps and one-off deps, and insulate you from having to change constructor calls if your dep list changes.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251