Do Guice provider methods honor scope? - java

If I have a module like this:
public class MyModule extends AbstractModule {
#Override
public void configure() {
bind(WhatsThis.class).to(AnAppleOfGold.class);
bind(TellMeYourName.class).to(Bosse.class);
}
#Provides
public AnAppleOfGold providesApple() {
return new AppleOfGold(providesFizz());
}
#Provides
public Bosse providesBosse() {
return new Bosse("Grab a hold of my beard", providesFizz());
}
#Provides #Singleton
public Fizz providesFizz() {
return new Fizz(Math.random());
}
}
Every time Guice uses providesApple and providesBosse to inject AnAppleOfGold and Bosse objects respectively, do they get the same singleton instance of Fizz? In other words, does Guice honor scope between provides methods, or does it only honor scope (in this case, Scopes.SINGLETON) from "outside" the module (the DI client code)? Thanks in advance.

Guice will honor Singleton scope between #Provides methods, providing that Guice is the one calling them.
In your example, you call providesFizz() manually, which works just like any other method call. Guice will inject a new instance each time you try to get a new AnAppleOfGold or Bosse. Meanwhile, it will create a separate new instance when you request a Fizz through Guice, and return that same instance for every Fizz injected through Guice.
So how do you access the common instance from other #Provides methods? Simple: Guice will inject all parameters on your #Provides method, including Fizz or Provider<Fizz>.
#Provides
public AnAppleOfGold providesApple(Fizz fizz) {
return new AppleOfGold(fizz);
}
#Provides
public Bosse providesBosse(Provider<Fizz> fizzProvider) {
return new Bosse("Grab a hold of my beard", fizzProvider.get());
}
#Provides #Singleton
public Fizz providesFizz() {
return new Fizz(Math.random());
}

Related

asEagerSingleton with factory

I'm very new to Guice, but I have a singleton that I believe would normally be created thusly:
#Provides
#Singleton
private SomeClass getSomeClass()
{
return someClassFactory(configuration);
}
However, I want this to be eagerly initialized. When I remove the #Singleton annotation and try to bind(SomeClass.class).asEagerSingleton() I get errors:
1) No implementation for SomeClass was bound.
2) A binding to SomeClass was already configured
How can I provide an Eagerly initialized singleton that is constructed with parameters or a factory?
The #Provides annotation is a separate way to configure a binding for SomeClass; it's conflicting with the bind(SomeClass.class).asEagerSingleton() binding.
To fix it, you'll need to write an explicit provider class and bind it using toProvider:
class MyModule extends AbstractModule {
private static class MyProvider implements Provider<SomeClass> {
private final OtherStuff otherStuff;
#Inject
MyProvider(OtherStuff otherStuff) {
// Inject constructor params if your #Provides method took arguments
this.otherStuff = otherStuff;
}
public SomeClass get() {
return new SomeClass(otherStuff);
}
}
protected void configure() {
bind(SomeClass.class).toProvider(MyProvider.class).asEagerSingleton();
}
}

Understanding the Dagger2 Flow (Sample provided)

I'm trying to wrap my head around the use of Dagger 2 in my project with Retrofit, RxJava, MVP implementation. However, I'm starting small by reading guides and watching videos and just when I thought I understood how it works, it appears I don't. Here is the sample I'm trying to understand.
Module:
#Module
public class AppModule {
private App app;
public AppModule(App app) {
this.app = app;
}
#Provides #Singleton public SharedPreferences provideSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(app);
}
#Provides #Singleton public HelloModel provideHelloModel(SchedulerProvider schedulerProvider,
HelloDiskCache helloDiskCache, HelloService helloService, Clock clock) {
return new HelloModel(schedulerProvider, helloDiskCache, helloService, clock);
}
#Provides public HelloDiskCache provideHelloDiskCache(SharedPreferences prefs) {
return new HelloDiskCache(prefs);
}
#Provides public HelloService provideHelloService() {
return new HelloService();
}
#Provides public SchedulerProvider provideSchedulerProvider() {
return SchedulerProvider.DEFAULT;
}
#Provides public Clock provideClock() {
return Clock.REAL;
}
#Provides #Nullable public LayoutInflaterFactory provideLayoutInflaterFactory() {
return null;
}
Component
#Component(
modules = AppModule.class
)
#Singleton
public interface AppComponent {
HelloModel getHelloModel();
HelloDiskCache getHelloDiskCache();
MainActivity inject(MainActivity activity);
HelloFragment inject(HelloFragment fragment);
}
In the fragment, presenter is injected (where is this coming from?)
#Inject HelloPresenter presenter;
And in the presenter, there is a constructor injection
#Inject HelloPresenter(HelloModel helloModel) {
this.model = helloModel;
}
So, how come we can inject a presenter in the fragment, and why can we inject in the presenter? The answer does not have to be very elaborate I just feel stupid because I can't trace where it is coming from.
#Inject-annotated constructor is an alternative to a #Provides-annotated method for a dependency when there's not much configuration to do.
Since HelloPresenter has such constructor, Dagger discovers it automatically and is able to inject this dependency or use it to construct and provide other objects in the graph.
A class with an #Inject-annotated constructor can itself be annotated with a scope annotation (e.g., #Singleton). In this case, only components with the matching scope will be able to see it.
In general, this type of providing dependencies is less verbose, but not always you can use it (e.g., Activity, SharedPreferences). In such cases you have to go with a #Module and a #Provides method.
You can look at this sample where Dagger2 used with MVP Architecture
Dagger2 Android with MVP

Guice Provider Interception

I need to access to an instance provided via Guice #Provides, so i'm testing a way to access the #Provides Method via a Interceptor...but no way, the interceptor never distpaches.
Also i can't change Provider Method Signature , cause inherits from another class ....
public class MyModule extends AbstractModule{
public static class MyInterceptor implements MethodInterceptor{
#Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
System.out.println("MyModule ::: Intercepted#invoke! : "+ methodInvocation.getMethod().getName());
return methodInvocation.proceed();
}
}
#Provides
StampInterface getStamp(){
StampExampleImpl se = new StampExampleImpl();
se.setId("theID");
se.setTst(System.currentTimeMillis());
return se;
}
#Override
protected void configure() {
bindInterceptor(Matchers.any(),
Matchers.annotatedWith(Provides.class),
new MyInterceptor());
}
public static void main(String... args) {
StampInterface s = Guice.createInjector(new MyModule()).getInstance(StampInterface.class);
System.out.println( s.getTst());
System.out.println("---------------------------");
}
}
Please check the limitations of guice aop as described here: https://github.com/google/guice/wiki/AOP#limitations
Instances must be created by Guice by an #Inject-annotated or no-argument constructor It is not possible to use method interception on instances that aren't constructed by Guice.
You are creating the StampExampleImpl yourself via "new" (doesn't matter that you do so inside a produces method). Thus guice does not know about it in regard to interception.
Quick fix: let guice create the impl instance for you:
#Provides
StampInterface getStamp(StampExampleImpl se){
se.setId("theID");
se.setTst(System.currentTimeMillis());
return se;
}
2nd Problem: why matching on "annotatedWith(Provides)"? You want to intercept the getTsd() method of your StampInterface, and that is not annotated. The annotation is on the producer method of your module, which is a different thing.

What determines the lifecycle of a component (object graph) in Dagger 2?

I'm trying to wrap my head around scopes in Dagger 2, specifically the lifecycle of scoped graphs. How do you create a component that will be cleaned up when you leave the scope.
In the case of an Android application, using Dagger 1.x you generally have a root scope at the application level which you'd extend to create a child scope at the activity level.
public class MyActivity {
private ObjectGraph mGraph;
public void onCreate() {
mGraph = ((MyApp) getApplicationContext())
.getObjectGraph()
.plus(new ActivityModule())
.inject(this);
}
public void onDestroy() {
mGraph = null;
}
}
The child scope existed as long as you kept a reference to it, which in this case was the lifecycle of your Activity. Dropping the reference in onDestroy ensured the scoped graph was free to be garbage collected.
EDIT
Jesse Wilson recently posted a mea culpa
Dagger 1.0 badly screwed up its scope names ... The #Singleton annotation is used for both root graphs and custom graphs, so it's tricky to figure out what the actual scope of a thing is.
and everything else I've read/heard points towards Dagger 2 improving the way scopes work, but I'm struggling to understand the difference. According to #Kirill Boyarshinov's comment below, the lifecycle of a component or dependency is still determined, as usual, by concrete references. So is the difference between Dagger 1.x and 2.0 scopes purely a matter of semantic clarity?
My understanding
Dagger 1.x
Dependencies were either #Singleton or not. This was equally true of dependencies in the root graph and subgraphs, leading to ambiguity as to which graph the dependency was bound to (see In Dagger are Singletons within the sub-graph cached or will they always be recreated when a new activity sub-graph is constructed?)
Dagger 2.0
Custom scopes allow you to create semantically clear scopes, but are functionally equivalent to applying #Singleton in Dagger 1.x.
// Application level
#Singleton
#Component( modules = MyAppModule.class )
public interface MyAppComponent {
void inject(Application app);
}
#Module
public class MyAppModule {
#Singleton #Named("SingletonScope") #Provides
StringBuilder provideStringBuilderSingletonScope() {
return new StringBuilder("App");
}
}
// Our custom scope
#Scope public #interface PerActivity {}
// Activity level
#PerActivty
#Component(
dependencies = MyAppComponent.class,
modules = MyActivityModule.class
)
public interface MyActivityComponent {
void inject(Activity activity);
}
#Module
public class MyActivityModule {
#PerActivity #Named("ActivityScope") #Provides
StringBuilder provideStringBuilderActivityScope() {
return new StringBuilder("Activity");
}
#Name("Unscoped") #Provides
StringBuilder provideStringBuilderUnscoped() {
return new StringBuilder("Unscoped");
}
}
// Finally, a sample Activity which gets injected
public class MyActivity {
private MyActivityComponent component;
#Inject #Named("AppScope")
StringBuilder appScope
#Inject #Named("ActivityScope")
StringBuilder activityScope1
#Inject #Named("ActivityScope")
StringBuilder activityScope2
#Inject #Named("Unscoped")
StringBuilder unscoped1
#Inject #Named("Unscoped")
StringBuilder unscoped2
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
appScope.append(" > Activity")
appScope.build() // output matches "App (> Activity)+"
activityScope1.append("123")
activityScope1.build() // output: "Activity123"
activityScope2.append("456")
activityScope1.build() // output: "Activity123456"
unscoped1.append("123")
unscoped1.build() // output: "Unscoped123"
unscoped2.append("456")
unscoped2.build() // output: "Unscoped456"
}
public void onDestroy() {
component = null;
}
}
The takeaway being that using #PerActivity communicates your intention regarding the lifecycle of this component, but ultimately you can use the component anywhere/anytime. Dagger's only promise is that, for a given component, scope annotated methods will return a single instance. I also assume Dagger 2 uses the scope annotation on the component to verify that modules only provide dependencies that are either in the same scope or non-scoped.
In Summary
Dependencies are still either singleton or non-singleton, but #Singleton is now intended for application-level singleton instances and custom scopes are the preferred method for annotating singleton dependencies with a shorter lifecycle.
The developer is responsible for managing the lifecycle of components/dependencies by dropping references that are no longer needed and responsible for ensuring that components are only created once in the scope for which they are intended, but custom scope annotations make it easier to identify that scope.
The $64k Question*
Is my understanding of Dagger 2 scopes and lifecycles correct?
* Not actually a $64'000 question.
As for your question
What determines the lifecycle of a component (object graph) in Dagger 2?
The short answer is you determine it. Your components can be given a scope, such as
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ApplicationScope {
}
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope {
}
These are useful for you for two things:
Validation of scope: a component can only have unscoped providers, or scoped providers of the same scope as your component.
.
#Component(modules={ApplicationModule.class})
#ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
#Module
public class ApplicationModule {
#ApplicationScope //application-scoped provider, only one can exist per component
#Provides
public Something something() {
return new Something();
}
#Provides //unscoped, each INJECT call creates a new instance
public AnotherThing anotherThing() {
return new AnotherThing();
}
}
Allows for sub-scoping your scoped dependencies, thus allowing you to create a "subscoped" component that uses the provided instances from the "superscoped" component.
This can be done with #Subcomponent annotation, or component dependencies. I personally prefer dependencies.
#Component(modules={ApplicationModule.class})
#ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method
}
#Subcomponent(modules={ActivityModule.class})
#ActivityScope
public interface ActivityComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
#Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));
Or you can use component dependencies like so
#Component(modules={ApplicationModule.class})
#ApplicationScope
public class ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
#Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class})
#ActivityScope
public interface ActivityComponent extends ApplicationComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
#Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();
Important things to know:
A scoped provider creates one instance for that given scope for each component. Meaning a component keeps track of its own instances, but other components don't have a shared scope pool or some magic. To have one instance in a given scope, you need one instance of the component. This is why you must provide the ApplicationComponent to access its own scoped dependencies.
A component can subscope only one scoped component. Multiple scoped component dependencies are not allowed.

In guice is there a difference between #provides and bind()?

I am wondering what the difference is between using #provides on a method and using bind() in my guice modules.
I usually override AbstractModule.configure() and bind all my implementations to my interfaces like this:
public class MyModule extends AbstractModule
{
#Override
protected void configure()
{
this.bind(myIface.class).to(myIfaceImpl.class);
this.bind(myOtherIface.class).to(myOtherIfaceImpl.class).asEagerSingleton();
}
...
}
However, I have noticed a pattern in the codebase I'm currently working with where implementations aren't bound explicitly they are being returned from providers like this:
public class MyModule extends AbstractModule
{
#Provides
#Singleton
myIface iFaceProvider()
{
return new myIfaceImpl();
}
...
}
Is there a reason to prefer one over the other? Are there cases that force a particular method?
If you do
bind(MyInterface.class).to(MyImplementation.class)
Guice creates the instance for you. This enables certiain things like AOP. If you do
#Provides
MyInterface provideMyInterface() {
return new MyImplementation();
}
then Guice didn't create the instance so AOP won't work. Also, it requires an accessible constructor for MyImplementation. Generally, this form is only used when you can't edit MyImplementation to make it Guice-compatible.
There's a third form:
#Provides
MyInterface provideMyInterface(MyImplementation impl) {
return impl;
}
which is almost totally equivalent to the bind(...).to(...) form. It is commonly used in frameworks like Dagger that do not have the bind syntax.

Categories