Dagger component body - dagger-2

I am pretty new to Dagger and finding the component body a bit difficult to understand,having 2 specific questions related to the component implementation:
1)
#Singleton
#Component(modules = { UserModule.class, BackEndServiceModule.class })
public interface MyComponent {
BackendService provideBackendService();// Line 1
void inject(Main main); // Line 2
}
What is the purpose of Line 2? also will an instance of backendService be created even if line 1 is removed?
and also in the below code where the implementation of the above interface is generated , what does the component.inject(this) actually do?
public class Main {
#Inject
BackendService backendService; //
private MyComponent component;
private Main() {
component = DaggerMyComponent.builder().build();
component.inject(this);
}
private void callServer() {
boolean callServer = backendService.callServer();
if (callServer) {
System.out.println("Server call was successful. ");
} else {
System.out.println("Server call failed. ");
}
}
and also why has the backendservice not obtained using component.provideBackendService()

What is the purpose of void inject(Main main);?
It lets you perform field injection on concrete class Main, assuming that Main is a class that cannot be created by Dagger
where the implementation of the above interface is generated , what does the component.inject(this) actually do?
It uses MemberInjectors to inject the package-protected or public fields marked with #Inject. You can see the implementation of inject(Main) method in DaggerMyComponent class.
Of course, if possible it is better to make it so that:
1.) Main does not instantiate/know about its own injector
2.) Main is created by the Dagger component and #Inject constructor is used
#Singleton
public class Main {
private final BackendService backendService;
#Inject
Main(BackendService backendService) {
this.backendService = backendService;
}
}

Related

Infinite recursion when using subcomponent for encapsulation

I'm trying to achieve encapsulation by using subcomponent which is described here, but I got infinite recursion.
Here is my code:
//tried adding #ScopeA, still the same.
public class A {
#Inject
A(B b) {
}
}
#ScopeA
public class B {
#Inject
B() {
}
}
#Component(modules = AModule.class)
#Singleton
public interface AComponent {
public A a();
}
#Module(subcomponents = SComponent.class)
class AModule {
#Provides
#Singleton
A a(SComponent.Factory factory) {
return factory.component().a();
}
}
#Subcomponent
#ScopeA
interface SComponent {
#ScopeA
A a();
#Subcomponent.Factory
interface Factory {
SComponent component();
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAComponent.create().a();
}
}
After checking generated dagger code, I found this:
private final class SComponentImpl implements SComponent {
private SComponentImpl() {}
#Override
public A a() {
return DaggerAComponent.this.aProvider.get();
}
}
It seeems that SComponent are getting A from parent component, which is not what I wanted, where is the problem of my code?
Note that the example from the Subcomponents for Encapsulation page uses a qualifier annotation, #PrivateToDatabase, which is not a scoping annotation and which distinguishes the binding of Database from the binding of #PrivateToDatabase Database.
Subcomponents inherit all of the bindings from their parent components, so you currently do have A available from the parent component and also A available from the subcomponent. This is especially tricky if anything in your subcomponent needs to inject A, if it weren't marked #Singleton: Do you want the A from the parent component, or the A from the subcomponent?
Another tricky part of this situation is that you can't use qualifier annotations on classes that use #Inject constructors.
I'd recommend that you do the following:
Extract an interface from A, so then you have A and AImpl.
Keep your #Provides method that gets an A instance from the subcomponent.
Have the subcomponent expose AImpl, and (to best avoid ambiguity) only inject AImpl in the classes in your subcomponent, not A.
If you'd rather not extract an interface, you could also work around this problem by removing #Inject from A and writing a #Provides method in a module in the subcomponent that returns a qualified A, so the unqualified A goes through the top-level component and the qualified A is only available within the subcomponent.

Dagger2 Android subcomponent injection in nonAndroid classes

Learning Dagger2 and maybe going off the rails here. I have a class - MapRoute that may or may not be needed in a Fragment. If MapRoute is needed, I want to create it and when the MapRoute is instantiated I want to inject it with dependencies created at the application level. I am also using Builder pattern to populate MapRouter.
Perhaps the generic question is when you are in nonAndroid classes (not Activity/Fragment/...) how can you inject dependencies from above? How to you construct the nonAndroid injector in place of AndroidInjection.inject(this)?
So my fragment is:
public class ActivityMapFragment extends DaggerFragment ... {
#Inject
MapRoute.Builder mapRouteBuilder;
private void plotRouteForMap(Cursor csr){
MapRoute.Builder builder = new MapRoute.Builder();
builder.setSupportMapFragment(supportMapFragment)
.setLocationExerciseRecord(ler)
.setMapType(mapType)
.setUseCurrentLocationLabel(useCurrentLocationLabel)
.setCursor(csr)
.setTitle(activityTitle)
.setActivityPhotosCallback(this);
mapRoute = builder.build();
mapRoute.plotGpsRoute();
}
...
MapRoute is: (Edit) added Builder code snippet
public class MapRoute ... {
#Inject
public DisplayUnits displayUnits; <<< Created at app level
#Inject
public PhotoUtils photoUtils; <<<< Create at app level
public MapRoute() {
// Use subcomponent builder
MapRouteSubcomponent component =
DaggerMapRouteSubComponent.builder().build(); <<< Want to do this
component.inject(this);
}
public static class Builder {
SupportMapFragment supportMapFragment;
LocationExerciseRecord ler;
boolean useCurrentLocationLabel;
int mapType;
Cursor cursor;
ActivityPhotosCallback activityPhotosCallback;
String title;
#Inject
public Builder() {
}
public Builder setSupportMapFragment(SupportMapFragment supportMapFragment){
this.supportMapFragment = supportMapFragment;
return this;
}
....
MapRouteSubcomponent best guess:
#Subcomponent(modules = {MapRouteModule.class, ApplicationModule.class})
public interface MapRouteSubcomponent {
// allow to inject into our MapRoute class
void inject(MapRoute mapRoute);
#Subcomponent.Builder
interface Builder extends SubComponentBuilder<MapRouteSubcomponent> {
Builder mapRouteModule(MapRouteModule mapRouteModule);
}
#Module
public class MapRouteModule {
// What to put here?
}
And finally a subcomponent builder:
// from https://github.com/Zorail/SubComponent/blob/master/app/src/main/java/zorail/rohan/com/subcomponent/SubComponentBuilder.java
public interface SubComponentBuilder<V> {
V build();
}
At this point I am at a stand on where to go from here.

Dagger 2.11 ContributesAndroidInjector Singleton dependency injection fails

I am exploring the new dagger.android from Dagger 2.11. I hope not to have to create custom scope annotation like #PerActivity. So far I was able to do the following:
1) Define Application scope Singletons and injecting them into activities.
2) Define Activity scope non-Singleton dependencies and injecting them into their activities using #ContributesAndroidInjector
What I cannot figure out is how to have an Application scope Singleton and Activity scope non-Singletons using it.
In the example below, I would like my Activity scope MyActivityDependencyA and MyActivityDependencyB to have access to a Singleton MyActivityService
The setup below results in:
Error:(24, 3) error: com.example.di.BuildersModule_BindMyActivity.MyActivitySubcomponent
(unscoped) may not reference scoped bindings:
#Singleton #Provides com.example.MyActivityService
com.example.MyActivitySingletonsModule.provideMyActivityService()
Here is my setup. Note, I defined separate MyActivitySingletonsModule and MyActivityModule since I could not mix Singleton and non-Singleton dependencies in the same Module file.
#Module
public abstract class BuildersModule {
#ContributesAndroidInjector(modules = {MyActivitySingletonsModule.class, MyActivityModule.class})
abstract MyActivity bindMyActivity();
}
}
and
#Module
public abstract class MyActivityModule {
#Provides
MyActivityDependencyA provideMyActivityDependencyA(MyActivityService myActivityService){
return new MyActivityDependencyA(myActivityService);
}
#Provides
MyActivityDependencyB provideMyActivityDependencyB(MyActivityService myActivityService) {
return new MyActivityDependencyB(myActivityService);
}
}
and
#Module
public abstract class MyActivitySingletonsModule {
#Singleton
#Provides
MyActivityService provideMyActivityService() {
return new MyActivityService();
}
}
and
#Singleton
#Component(modules = {
AndroidSupportInjectionModule.class,
AppModule.class,
BuildersModule.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(App application);
AppComponent build();
}
void inject(App app);
}
Is it even possible to do what I am trying to do without defining custom scope annotations?
Thanks in advance!
Why avoid custom scopes? Custom scopes are still required for the new dagger.android dependency injection framework introduced in Dagger 2.10+.
"My understanding is #ContributesAndroidInjector removes the need for custom annotation and I was able to prove it by using non-singletons defined in the activity scope without any issues."
#ContributesAndroidInjector (available in v2.11) does not remove the need for custom scopes. It merely replaces the need to declare #Subcomponent classes that does not make use of #Subcomponent.Builder to inject dependencies required by the component at runtime. Take a look at the below snippet from the official dagger.android user guide about #ContributesAndroidInjector;
"Pro-tip: If your subcomponent and its builder have no other methods or supertypes than the ones mentioned in step #2, you can use #ContributesAndroidInjector to generate them for you. Instead of steps 2 and 3, add an abstract module method that returns your activity, annotate it with #ContributesAndroidInjector, and specify the modules you want to install into the subcomponent. If the subcomponent needs scopes, apply the scope annotations to the method as well."
#ActivityScope
#ContributesAndroidInjector(modules = { /* modules to install into the subcomponent */ })
abstract YourActivity contributeYourActivityInjector();
The key here is "If the subcomponent needs scopes, apply the scope annotations to the method as well."
Take a look at the following code for an overview of how to use #Singleton, #PerActivity, #PerFragment, and #PerChildFragment custom scopes with the new dagger.android injection framework.
// Could also extend DaggerApplication instead of implementing HasActivityInjector
// App.java
public class App extends Application implements HasActivityInjector {
#Inject
AppDependency appDependency;
#Inject
DispatchingAndroidInjector<Activity> activityInjector;
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.create().inject(this);
}
#Override
public AndroidInjector<Activity> activityInjector() {
return activityInjector;
}
}
// AppModule.java
#Module(includes = AndroidInjectionModule.class)
abstract class AppModule {
#PerActivity
#ContributesAndroidInjector(modules = MainActivityModule.class)
abstract MainActivity mainActivityInjector();
}
// AppComponent.java
#Singleton
#Component(modules = AppModule.class)
interface AppComponent {
void inject(App app);
}
// Could also extend DaggerActivity instead of implementing HasFragmentInjector
// MainActivity.java
public final class MainActivity extends Activity implements HasFragmentInjector {
#Inject
AppDependency appDependency; // same object from App
#Inject
ActivityDependency activityDependency;
#Inject
DispatchingAndroidInjector<Fragment> fragmentInjector;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
if (savedInstanceState == null) {
addFragment(R.id.fragment_container, new MainFragment());
}
}
#Override
public final AndroidInjector<Fragment> fragmentInjector() {
return fragmentInjector;
}
}
// MainActivityModule.java
#Module
public abstract class MainActivityModule {
#PerFragment
#ContributesAndroidInjector(modules = MainFragmentModule.class)
abstract MainFragment mainFragmentInjector();
}
// Could also extend DaggerFragment instead of implementing HasFragmentInjector
// MainFragment.java
public final class MainFragment extends Fragment implements HasFragmentInjector {
#Inject
AppDependency appDependency; // same object from App
#Inject
ActivityDependency activityDependency; // same object from MainActivity
#Inject
FragmentDependency fragmentDepency;
#Inject
DispatchingAndroidInjector<Fragment> childFragmentInjector;
#SuppressWarnings("deprecation")
#Override
public void onAttach(Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Perform injection here before M, L (API 22) and below because onAttach(Context)
// is not yet available at L.
AndroidInjection.inject(this);
}
super.onAttach(activity);
}
#Override
public void onAttach(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Perform injection here for M (API 23) due to deprecation of onAttach(Activity).
AndroidInjection.inject(this);
}
super.onAttach(context);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState == null) {
addChildFragment(R.id.child_fragment_container, new MainChildFragment());
}
}
#Override
public final AndroidInjector<Fragment> fragmentInjector() {
return childFragmentInjector;
}
}
// MainFragmentModule.java
#Module
public abstract class MainFragmentModule {
#PerChildFragment
#ContributesAndroidInjector(modules = MainChildFragmentModule.class)
abstract MainChildFragment mainChildFragmentInjector();
}
// MainChildFragment.java
public final class MainChildFragment extends Fragment {
#Inject
AppDependency appDependency; // same object from App
#Inject
ActivityDependency activityDependency; // same object from MainActivity
#Inject
FragmentDependency fragmentDepency; // same object from MainFragment
#Inject
ChildFragmentDependency childFragmentDepency;
#Override
public void onAttach(Context context) {
AndroidInjection.inject(this);
super.onAttach(context);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_child_fragment, container, false);
}
}
// MainChildFragmentModule.java
#Module
public abstract class MainChildFragmentModule {
}
// PerActivity.java
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerActivity {
}
// PerFragment.java
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerFragment {
}
// PerChildFragment.java
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerChildFragment {
}
// AppDependency.java
#Singleton
public final class AppDependency {
#Inject
AppDependency() {
}
}
// ActivityDependency.java
#PerActivity
public final class ActivityDependency {
#Inject
ActivityDependency() {
}
}
// FragmentDependency.java
#PerFragment
public final class FragmentDependency {
#Inject
FragmentDependency() {
}
}
// ChildFragmentDependency.java
#PerChildFragment
public final class ChildFragmentDependency {
#Inject
ChildFragmentDependency() {
}
}
For a complete dagger.android 2.11 setup guide using #ContributesAndroidInjector and custom scopes mentioned above, read this article.
There are some problems here: firstly, ActivitySingleton doesn't make much sense. A dependency is either a singleton (per app, or app scoped) or not.
If it is not a singleton it could be activity scoped (per activity). This would mean it lived and died with the Activity i.e., that its lifecycle was congruent with that of the Activity itself and hence it would be destroyed with the onDestroy of the Activity.
That doesn't mean that everything that is injected inside an Activity must be #PerActivity. You can still inject #Singleton dependencies there (like per app OkHttpClient for instance). However, these #Singleton dependencies will not be bound in the module set that composes a #PerActivity component. Instead, they will be bound in the module set for parent components and obtained through the component hierarchy (dependent components or sub-components).
These means that your ActivitySingletonsModule is incorrect, see the comments in the code below:
#Module
public abstract class MyActivitySingletonsModule {
//#Singleton
//^^ remove the annotation here if you want to use the
//in your ActivityComponent
//If you need this as a per-app singleton, then include
//this module at the AppComponent level
#Provides
MyActivityService provideMyActivityService() {
return new MyActivityService();
}
}
I do not understand the reluctance to define a custom scope. These are extremely lightweight and can improve readability. Here is the single line of code you would need to create a #PerActivity scope.
#Scope #Retention(RetentionPolicy.RUNTIME) public #interface PerActivity {}
I suspect the concept of scopes is unclear and this is leading to the reluctance. Admittedly, it can be rather confusing. However there are some really good canonical answers that help clarify. I would suggest this question as a start:
Dagger2 Custom Scopes : How do custom-scopes (#ActivityScope) actually work?

About Dagger 2. Connection of #inject and #provide

If there is #inject, then it means there must be #provide?
inject field gets its value from #provide method of module?
Yes if you use Module
#Module
public class SomeModule {
#Provides
Unscoped unscoped() {
return new Unscoped();
}
#Provides
#Singleton
Scoped scoped() {
return Scoped();
}
}
BUT classes with #Inject constructor get automatically appended to your scoped component even if no module is specified for it:
#Singleton
public class Scoped {
#Inject
public Scoped() {
}
}
public class Unscoped {
#Inject
public Unscoped() {
}
}
If there is #Inject annotation then it's dependency can be provided in two ways :
By Using Provides annotation in module
#Provides
TasksPresenter provide TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
return new TasksPresenter(tasksRepository,tasksView);
}
By Using Constructor Injection
#Inject
TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
mTasksRepository = tasksRepository;
mTasksView = tasksView;
}
One thing to observe here is Constructor Injection solve two thing
Instantiate object
Provides the object by adding it to Object graph.

Tapestry IoC constructor and injection

I have the following class:
public class MyClass {
#Inject
private MyAnotherClass myAnotherClass;
public MyClass() {
//Perform operations on myAnotherClass.
}
}
I need to do some things in constructor which require an instance of myAnotherClass. Unfortunately myAnotherClass is injected after code in constructor is ran, which means I am performing operations on null...
I could of course instantiate it the classic way (MyAnotherClass myAnotherClass = new MyAnotherClass()) directly in constructor, but I don't think it is the right thing to do in this situation.
What solutions would you suggest to solve this problem?
Best option:
public class MyClass {
private final MyAnotherClass myAnotherClass;
public MyClass(MyAnotherClass other) {
this.myAnotherClass = other;
// And so forth
}
}
T5-IoC will then use constructor injection so there's no need to 'new' up MyClass yourself. See Defining Tapestry IOC Services for more info.
Alternatively:
public class MyClass {
#Inject
private MyAnotherClass myAnotherClass;
#PostInjection
public void setupUsingOther() {
// Called last, after fields are injected
}
}