Search code examples
javaandroiddependency-injectiondagger-2dagger

Dagger 2 How to solve constructor dependency


I am an Android developer and trying to learn Dagger2. I have gone through some tutorials and got some basic understanding. I developed a basic java app using Dagger2. And below is my app code.

Logger.java: Logger is simple java class which will print logs with some tag.

public class Logger {

    private String tag;

    @Inject
    public Logger(String tag) {
        this.tag = tag;
    }

    public void log(String msg) {
        System.out.println(tag + "::" + msg);
    }
}

InvertNumber.java: It will invert the passed number and prints log using Logger

public class InvertNumber {

    private Logger logger;

    @Inject
    public InvertNumber(Logger logger) {
        this.logger = logger;
    }

    public void invert(int i) {
        logger.log("Inverted value is " + (i * -1));
    }
}

Now I added Dagger2 depency classes (Module and component) like below

@Module
public class NumberModule {

    private String tag;

    public NumberModule(String tag) {
        this.tag = tag;
    }

    @Provides
    Logger provideLogger(){
        Logger logger = new Logger(tag);
        return logger;
    }

    @Provides
    InvertNumber provideTempManager(Logger logger){
        return new InvertNumber(logger);
    }
}

@Component(modules = NumberModule.class)
public interface NumberComponent {

    InvertNumber getInvertNumber();

}

Now below is my main method.

public static void main(String[] args) {

    NumberComponent numberComponent = DaggerNumberComponent.builder()
            .numberModule(new NumberModule("MyMain"))
            .build();

    InvertNumber invertNumber = numberComponent.getInvertNumber();

    invertNumber.invert(10);
}

To print logs in console, I have to provide tag to the logger. For this I am creating instance of NumberModule class and passing to NumberComponent builder.

Now my questions are:

  1. Is this correct way to pass tag using NumberModule instance
  2. If it is correct, according to DI concept, it is not encouraged to use new operator to create objects (new NumberModule())
  3. If the above code is wrong, what is the correct way?

Solution

  • Your way of solving problem is right, but there is one more using @Component.Buidler. (please, note that in your case @Inject annotation in Logger and InvertNumber constructor not working - you call them by hand).

    Rewrite dagger stuff like that

    @Module
    public class NumberModule {
        @Inject
        public NumberModule() {}
    
        @Provides
        Logger provideLogger(@Named("logger_tag") String tag){
            Logger logger = new Logger(tag);
            return logger;
        }
    
        @Provides
        InvertNumber provideTempManager(Logger logger){
            return new InvertNumber(logger);
        }
    }
    
    @Component(modules = NumberModule.class)
    public interface NumberComponent {
    
        InvertNumber getInvertNumber();
    
        @Component.Builder
        interface Builder {
            @BindsInstance
            Builder loggerTag(@Named("logger_tag") String tag);
    
            NumberComponent build();
        }
    }
    

    and use it

    NumberComponent numberComponent = DaggerNumberComponent.builder()
                .loggerTag("MyMain")
                .build();
    

    To allow dagger create Logger and InvertNumber for you (not manually calling their constructors), you need interfaces for each of them.