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)
Related
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!
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)
}
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.
i needed two instances that has access to each other privates. i naturaly thought of a companion object that grants access to a one and only instance of it's companion class. the class itself i made private, so users cannot just create instances using new.
object A {
def apply = dual
lazy val dual = new A
}
private class A {
//some irrelevant logic...
}
this code does not compile. i get: class A escapes its defining scope as part of type A error, which i don't really understand. my current workaround was to define a trait with every method declaration the class should have and make class A extend that trait, while dual is of the trait type, and not class A type.
what's the theoretic problem i'm missing here? why is this forbiden?
Paolo's solution is good (+1), but he didn't explain the error message, so let me try that. The problem stems from the fact that every method needs a return type. Your original definition of apply and dual returned an object of class A, thus the implicit return type of both was A. That implies that A must be visible to clients - how else could they call the function or access the val? Moreover, as both - and their parent object too - are public, they are globally visible. However, you declared A private which means it must not be visible outside its package. So there is a conflict which can't be resolved by the compiler.
The general rule is that all parameter and return type of functions / members must have (at least) the same scope of visibility as the referring member itself*. Thus one trivial way to solve this problem would be to reduce the visibility of apply and dual to private. This would satisfy the compiler, but not you :-)
Your solution gets around the problem by changing the static return type to a public trait, which thus has the same visibility as the members referring to it. The dynamic type of the returned object is still class A, however, this need not be visible to clients. This is a classic example of the principle "program to interfaces, not implementations".
Note that to apply this principle to the full extent, one could turn class A into a private inner class of object A, thus making it innaccessible even for other classes within the same package:
trait A {
//...
}
object A {
def apply: A = dual
lazy val dual: A = new AImpl
private class AImpl extends A {
//some irrelevant logic...
}
}
* To be pedantic, the enclosing class / object may reduce the visibility of its members, like here:
private class Holder {
def member = new Hidden
}
private class Hidden
where member is public but its enclosing class is private, effectively hiding its members from the external world. So the compiler emits no complaints here.
I think you don't want a private class, but a class with a private constructor.
class A private()
object A {
def apply = dual
lazy val dual = new A
}
Now your class is "visible" to outside code, but only your companion object can create instances of it.
I've been curious about the impact of not having an explicit primary constructor in Scala, just the contents of the class body.
In particular, I suspect that the private or protected constructor pattern, that is, controlling construction through the companion object or another class or object's methods might not have an obvious implementation.
Am I wrong? If so, how is it done?
You can declare the default constructor as private/protected by inserting the appropriate keyword between the class name and the parameter list, like this:
class Foo private () {
/* class body goes here... */
}
Aleksander's answer is correct, but Programming in Scala offers an additional alternative:
sealed trait Foo {
// interface
}
object Foo {
def apply(...): Foo = // public constructor
private class FooImpl(...) extends Foo { ... } // real class
}