Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @Singleton without @Provides in Dagger

A small example of a module that injects a class Foo:

@Module(complete = false, injects = { Foo.class })
class MyModule { }

class Foo {
    @Inject
    Foo(Bar bar, Baz baz) { }
}

(assuming that Bar and Baz are provided by a different module)

I now want Foo to be a singleton.

I could add a @Provides method and annotate it with @Singleton ...

@Module(complete = false, injects = { Foo.class })
class MyModule {
    @Provides @Singleton Foo provideFoo(Bar bar, Baz baz) {
        return new Foo(bar, baz);
    }
}

... but having to write that constructor invocation myself kind of defeats the purpose of using an injection framework. Is there a shorter way to accomplish this?

like image 479
Chris Martin Avatar asked Oct 20 '22 18:10

Chris Martin


1 Answers

tl;dr

You can add @Singleton to class Foo {} and when Foo is instantiated via implicit binding, it will be bound as @Singleton. eg:

@Module(complete = false, injects = { Foo.class })
class MyModule { }

@Singleton
class Foo {
  @Inject
  Foo(Bar bar, Baz baz) { }
}

Scope

The caveat here is that if it is implicitly bound, but not referred to, in a root graph, extension graphs (.plus() generated graphs) may inadvertently instantiate it, so you need to either declare it as an entry-point (injects=) (which you did in your example), or it needs to be consumed by something reachable by an entry-point.

If you're not using .plus() for scoping/lifetime management, then this last point is not that important. But @Singleton means one-per-graph, and graphs' implicit bindings are only realized on-demand. An upcoming feature to allow custom scope annotations to be used will catch these errors.

like image 145
Christian Gruber Avatar answered Oct 28 '22 19:10

Christian Gruber