Can a Dagger 2 dependency be non-injectable? - dagger-2

Is there a way to tell Dagger 2 how to provide something, but not allow it to be injected?
Say I want to inject a Qux. A Qux requires a Foo and a Bar:
#Provides
#Singleton
Foo foo() {
return new Foo();
}
#Provides
#Singleton
Bar bar() {
return new Bar();
}
#Provides
#Singleton
Qux qux(final Foo foo, final Bar bar) {
return new Qux(foo, bar);
}
But what if I don't want Foo and Bar to be injectable? Perhaps exposing them would break the encapsulation of the Qux, or perhaps they're factories of some kind that I only want the Qux to have access to.
I've thought of a couple ways I could achieve this:
If the Foo singleton is needed by other providers, I could make it a class member. But this would get messy if Foo has several dependencies of its own.
If the Bar singleton is not needed by any other providers, I could create the instance inside the Qux provider. But this would get messy if Qux has several dependencies like that.
Neither of these solutions seem very elegant or Daggery. Is there another way?

The easiest way to achieve what you're trying to do is to define a package-private qualifier.
package my.pkg;
#Qualifier
#Retention(RUNTIME)
#interface ForMyPackage {}
Then, use that for your bindings for Foo and Bar:
#Provides
#Singleton
#ForMyPackage
Foo foo() {
return new Foo();
}
#Provides
#Singleton
#ForMyPackage
Bar bar() {
return new Bar();
}
#Provides
#Singleton
Qux qux(final #ForMyPackage Foo foo, final #ForMyPackage Bar bar) {
return new Qux(foo, bar);
}
That way, you can only request that those versions of Foo and Bar be injected if you have access to the qualifier.
If all of these bindings are in a single module, you can even use a private, nested qualifier in the module.
Edit by asker:
I tried the last suggestion.
#Qualifier
#Retention(RUNTIME)
private #interface NoInject {}
#Provides
#Singleton
#NoInject
Foo foo() { return new Foo(); }
Attempting to inject a Foo causes a compile-time error, as desired:
Error:(15, 6) Gradle: error: com.mydomain.myapp.Foo cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
com.mydomain.myapp.MyActivity.foo
[injected field of type: com.mydomain.myapp.Foo foo]
So while the error message is a bit misleading, this technique is neat and effective.

I'd say this sounds a lot like component dependencies.
[..] As an alternative, components can use bindings only from another component interface by declaring a component dependency. When a type is used as a component dependency, each provision method on the dependency is bound as a provider. Note that only the bindings exposed as provision methods are available through component dependencies.
If you really want to hide your Foo and Bar, you could make the module, Foo, and Bar package local. Then create a component that only exposes Qux and use it as a component dependency.
Since Foo and Bar are package local, a SubComponent should not be able to use them, either.
Your component would be the only one able to use the module and thus create and use Foo and Bar in its dependency graph.

A repost of my answer elsewhere...
A simple way to do this is:
#Retention(BINARY)
#Qualifier
private annotation class InternalApi
#Module
object NetworkModule {
#Provides
#InternalApi
fun provideClient(): OkHttpClient {
//...
}
#Provides
fun provideRetrofit(
#InternalApi client: Lazy<OkHttpClient>
): Retrofit {
//...
}
}
culled from here.
Basically, we create private qualifiers- in this case, #InternalApi that is used to qualify the OkHttpClient dependency thus making it private to our module.

Related

How to inject Scala classes in objects?

I want to use a singleton class in a Scala companion object but I am using Guice dependency injection and, as far as I know, it has no explicit usage in these scenarios.
As an example, let's say we have Singleton (using Guice) class as follows:
#Singleton
class Foo Inject()(foo2: Foo2) {
def func = { ... }
}
I can use it in other classes as:
class MyClass Inject()(foo: Foo) {
foo.func()
}
What about objects? I need to create an instance with new as:
object MyObject {
val foo2 = new Foo2()
val foo = new Foo(foo2)
foo.func()
}
In this case, does Foo still have just one instance? I mean, does new Foo(foo2) return the same instance as Guice returns in #Inject()(foo: Foo)?
By the way, there are already questions about this (e.g., link) but I want to use objects and access the singleton instances inside them.
In this case, does Foo still have just one instance? I mean, does new Foo(foo2) return the same instance as Guice returns in #Inject()(foo: Foo)?
No. Just as if you call new Foo(...) elsewhere. My suggestion would just be not to mix it; if you want to use Guice's instances inside MyObject, make it a Guice singleton class as well. Or make Foo an object, you can still access it from Guice-using classes.
If you really need it, the way I can think of is really ugly; to store the Injector from your main (or wherever you create it) somewhere MyObject can access it, i.e.
object Main {
var injector: Injector = null
def main(args: Array[String]): Unit = {
// make sure this happens before MyObject is accessed
injector = Guice.createInjector(...)
...
}
}
object MyObject {
val foo = Main.injector.getInstance(classOf[Foo])
foo.func()
}
If you don't even create the Injector yourself, but are using some framework which uses Guice, check if it gives you access to the Injector.

Guice Scala DI, understanding how

Will default constructor be called in scala if I have #Provides annotation in my Module file to return an object but I never inject it anywhere?
According to official Google Guice documentation: https://github.com/google/guice/wiki/ProvidesMethods
#Provides Methods When you need code to create an object, use an #Provides method. The method must be defined within a module, and it must have an #Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method.
So, the constructor will never have been invoked.
If you need to construct the object anyway, use com.google.inject.Singleton annotation:
import com.google.inject._
class DbModule extends AbstractModule {
#Provides
#Singleton
def helloWorld: HelloWorld = new HelloWorld();
}
class HelloWorld() {
println("Hello world!")
}
will print:
Hello world!

Injecting the same object with different interfaces using Dagger

Let's say I have a singleton created by Dagger 2 which implements the interfaces Foo and Bar. There are places in the code which use Foo, and other places that use Bar, but whichever interface is injected I want the same singleton. Is this possible?
Yes, this is easy to do, but it's also easy to do incorrectly. The trick is that you need to be careful which you make #Singleton: Foo, Bar, or FooBarImpl.
In Dagger, any particular binding can be marked Singleton, and that's where Dagger interferes to say "let me cache this instance". Interfaces like Foo and Bar will have it marked on the #Binds or #Provides method, and concrete classes like FooBarImpl will have it marked on a #Provides method or on the actual class that has an #Inject annotation.
Ideal: Mark your implementation #Singleton
#Singleton public class FooBarImpl implements Foo, Bar { /* ... */ }
// in your module:
#Binds Foo bindFoo(FooBarImpl impl);
#Binds Bar bindBar(FooBarImpl impl);
This way, whether a consumer asks for a Foo, Bar, or FooBarImpl, they'll always go to Dagger's internal double-check-locked caching instance ("DoubleCheck"). Foo and Bar can be marked #Singleton as well, but it's a little wasteful, because the internal FooBarImpl provider will always return the same instance anyway. There's no need to keep a separate copy on the Foo Provider or the Bar Provider.
If FooBarImpl is external or otherwise outside of your control, you can mark #Singleton on the #Provides method instead.
Less ideal: Mark one and bind the other to it
/* not Singleton */ public class FooBarImpl implements Foo, Bar { /* ... */ }
// in your module:
#Binds #Singleton Foo bindFoo(FooBarImpl impl);
#Binds Bar bindBar(Foo foo);
Assuming Foo extends Bar, you could bind Bar to Foo. Here, the singleton instance is kept in the Foo provider, injections of FooBarImpl will return new instances, and injections of Bar will consult Foo (and its caching provider) every time.
This sounds strictly worse, but there are valid use-cases: Imagine if FooBarImpl were a CacheImpl of some sort, and you want Foo and Bar to return one instance but #Named("accounts") ListeningCache and #Named("accounts") Cache to both return the same distinct instance.
Not what you want: Separate singleton bindings
For completeness:
/* not Singleton */ public class FooBarImpl implements Foo, Bar { /* ... */ }
// in your module:
#Binds #Singleton Foo bindFoo(FooBarImpl impl);
#Binds #Singleton Bar bindBar(FooBarImpl impl);
Here, Foo and Bar will each return a separate Singleton instance, and injections of FooBarImpl will return a new instance each time. This is great for use-cases where you want two or more objects, but be careful not to accidentally implement this solution when you're trying to implement the "less ideal" solution above. They look really similar, but behave very differently.
interface FooBar extends Foo, Bar
class FooBarImpl implements FooBar {...}
#SomeScope #Binds FooBar bindsFooBar(impl: FooBarImpl)
#SomeScope #Binds Foo bindsFoo(fooBar: FooBar)
#SomeScope #Binds Bar bindsBar(fooBar: FooBar)

Guice: Getting Dependencies inside provides method

I am writing a Guice Module and in that module I have a provides method.
class FooModule extends ScalaModule {
#Provides
#Singleton
def providesFoo() : Foo = {
new Foo()
}
}
The problem is that the constructor of new Foo takes a Type Bar as parameter.
I want to know how do I ask guice to give me an instance of Bar so that I can do a new on Foo in the Module
Request those parameters by specifying them as method parameters. From the Provides method wiki documentation:
Dependencies can be passed in as parameters to the method. The injector will exercise the bindings for each of these before invoking the method.
So:
#Provides
#Singleton
def providesFoo(val bar : Bar) : Foo = {
new Foo(bar)
}

How to create a dependent Guice (Play / Scala) binding?

I am using Scala + Play and the out of box Guice set up for dependency injection. I am also using Akka Persistence behind the scenes and would like to create a binding for a custom read journal that I can then inject around my application.
Unfortunately, the read journal constructor (which I do not control) requires an explicit reference to the actor system:
PersistenceQuery(actorSystem).readJournalFor[CustomReadJournal]("custom-key")
How do I get a reference to the underlying actorSystem from within a binding definition class (Module)? Is this possible? More generally, is it possible to define interdependent bindings (a la Scaldi?)
My Module class entry currently looks like:
bind(classOf[CustomReadJournal]).toInstance(PersistenceQuery(<what do i put here?>).readJournalFor[CustomReadJournal]("custom-journal"))
Thanks in advance for the help!
If you need to do some kind of logic to create a dependency injection it is useful to use the #Provides annotation. For example:
trait MyProvider {
#Provides
def provideThing(): Thing = {
//make the thing and return it
}
}
class MyModule extends AbstractModule with MyProvider {
override def configure() {
bind(classOf[TraitYYY]).to(classOf[ClassThatTakesThingAsParameter])
}
}
A useful thing to know is that #Provides methods can themselves take parameters and get their arguments injected. For example:
#Provides
def provideThingNeedingParameter(param: P): ThingNeedingParam = {
new ThingNeedingParam(param)
}
Which is relevant to your situation I believe since you want to provide an actor system to an instance of some class.
// You can use #Singleton with #Provides if you need this to be one as well!
#Provides
def provideActorSystem(app: Application): ActorSystem = {
play.api.libs.concurrent.Akka.system(app)
}
#Provides
def providePersistenceQuery(actorSystem: ActorSystem): PersistenceQuery = {
PersistenceQuery(actorSystem)
}
#Provides
def provideCustomReadJournal(persistenceQuery: PersistenceQuery):CustomReadJournal = {
persistenceQuery.readJournalFor[CustomReadJournal]("custom-key")
}
By creating an #Provides annotated method for your CustomReadJournal you can avoid the bind call from configure entirely and control the parameters a bit more. Also, if you need to, #Provides works with #Singleton. I haven't used Akka persistence, but I think this should help you