Search code examples
kotlindagger-2

Dagger @Singleton in object module


I have a question if there is any significal difference between using @Module object without @Singleton functions and @Module class with @Singleton functions.

So like:

@Module
object ApiModule {

    @Provides
    fun test()
}
@Module
class ApiModule {

    @Singleton
    @Provides
    fun test()
}

Do I have to mark @Singleton in object ?


Solution

  • With Dagger being an Annotation Processor often the simplest and easiest solution is to just have a look at the generated code.

    I prepared a minimal sample to demonstrate:

    class Foo()
    class Bar()
    
    @Component(modules = [ClassModule::class, ObjectModule::class])
    interface FooComponent {
    
        val foo: Foo
        val bar: Bar
    }
    
    @Module
    class ClassModule {
    
        @Provides
        fun foo() = Foo()
    }
    
    @Module
    object ObjectModule {
    
        @Provides
        fun bar() = Bar()
    }
    

    If we take a look at the generated code we can see the following (I removed some irrelevant bits, just compile the above code yourself and look at the implementation if you want to see it all)

    public final class DaggerFooComponent implements FooComponent {
      private final ClassModule classModule;
    
      private DaggerFooComponent(ClassModule classModuleParam) {
        this.classModule = classModuleParam;
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      @Override
      public Foo getFoo() {
        return ClassModule_FooFactory.foo(classModule);}
    
      @Override
      public Bar getBar() {
        return ObjectModule_BarFactory.bar();}
    
      public static final class Builder {
        private ClassModule classModule;
    
        private Builder() {
        }
    
        public Builder classModule(ClassModule classModule) {
          this.classModule = Preconditions.checkNotNull(classModule);
          return this;
        }
    
        public FooComponent build() {
          if (classModule == null) {
            this.classModule = new ClassModule();
          }
          return new DaggerFooComponent(classModule);
        }
      }
    }
    

    What you will notice is that Dagger creates an object for ClassModule, but uses ObjectModule with its static method directly. Does this matter? Well, creating a new object is slow, not so much that it really matters, but we don't need to reduce performance unnecessarily either. So if you can, you should definitely prefer object or interface as modules for better performance.

    As for the scope, it really doesn't matter what your modules look like, it's the method signature that counts. Dagger looks at the return type of the method along with any annotation to it. So yes, of course you need to set a scope no matter what you use for your module, object, class, or interface. Ideally you'd add the scope on the class itself, though, and use constructor injection to avoid modules altogether.


    tl;dr class Modules result in an additional object being created, so interface or object modules should be preferred if possible.