How to use dagger 2 in a android library project - java

I have a Core Android Library where I'm defining number of interfaces and its default implementations. All of them are exposed by CoreModule which is defined in CoreComponent.`
Core module
#Module
public class CoreModule {
#Provides
public IAuthenticationViewExtension provideToolsViewExtension() {
return new AuthenticationViewExtension();
}
#Provides
public ISettingsViewExtension provideISettingsViewExtension() {
return new SettingsViewExtension();
}
}
Core component
#Component( modules = {CoreModule.class})
public interface CoreComponent {
CoreComponent coreComponent();
void inject(BaseLauncher baseLauncher);
ISettingsViewExtension iSettingsViewExtension();
}
All implementations are injected only in Core library.
There is also a Ui library which is dependent on Core library. Additionally, Ui library can provide a custom implementation to some of interfaces defined in Core library.
├── Ui Library
└── Core Library
└── Core Library
In order to achieve the goal I have created a custom #component and #module in Ui library
#Component(dependencies = {UiComponent.class},
modules = {UiModule.class})
public interface UiComponent {
}
#Module
public class DemoUiModule {
#Provides
public IAuthenticationViewExtension provideToolsViewExtension() {
return new CustomAuthenticationViewExtension();
}
}
I think that the best solution to provide a custom implementation to Core library is be using a Subcomponent but, unfortunately, it doesn't seem possible because the Core Library has no visibility to the other libraries (Ui library and it's #component) , so I can't inject any of custom implementations in Core library.
Any help?

Related

How to provide components from a library, for consumption by multiple DI frameworks

My team owns a library that provides components that must be referencable by code that consumes the library. Some of our consumers use Spring to instantiate their apps; others use Guice. We'd like some feedback on best-practices on how to provide these components. Two options that present themselves are:
Have our library provide a Spring Configuration that consumers can #Import, and a Guice Module that they can install.
Have our library provide a ComponentProvider singleton, which provides methods to fetch the relevant components the library provides.
Quick sketches of what these would look like:
Present in both approaches
// In their code
#AllArgsConstructor(onConstructor = #__(#Inject))
public class ConsumingClass {
private final FooDependency foo;
...
}
First approach
// In our code
#Configuration
public class LibraryConfiguration {
#Bean public FooDependency foo() {...}
...
}
---
public class LibraryModule extends AbstractModule {
#Provides FooDependency foo() {...}
...
}
========================
========================
// In their code
#Configuration
#Import(LibraryConfiguration.java)
public class ConsumerConfiguration {
// Whatever initiation logic they want - but, crucially, does
// *not* need to define a FooDependency
...
}
---
// *OR*
public class ConsumerModule extends AbstractModule {
#Override
public void configure() {
// Or, simply specify LibraryModule when creating the injector
install(new LibraryModule());
...
// As above, no requirement to define a FooDependency
}
}
Second approach
// In our code
public class LibraryProvider {
public static final INSTANCE = buildInstance();
private static LibraryProvider buildInstance() {...}
private static LibraryProvider getInstance() {return INSTANCE;}
}
========================
========================
// In their code
#Configuration
public class ConsumerConfiguration {
#Bean public FooDependency foo() {
return LibraryProvider.getInstance().getFoo();
}
...
}
// or equivalent for Guice
Is there an accepted Best Practice for this situation? If not, what are some pros and cons of each, or of another option I haven't yet thought of? The first approach has the advantage that consumers don't need to write any code to initialize dependencies, and that DI frameworks can override dependencies (e.g. with mocked dependencies for testing); whereas the second approach has the advantage of being DI-framework agnostic (if a new consumer wanted to use Dagger to instantiate their app, for instance, we wouldn't need to change the library at all)
I think the first option is better. If your library has inter-dependencies between beans then the code of #Configuration in case of spring in the second approach) will be:
Fragile (what if application doesn't know that a certain bean should be created)
Duplicated - this code will appear in each and every consumer's module
When the new version of your library gets released and a consumer wants to upgrade- there might be changes in consumer's configuration ( the lib might expose a new bean, deprecate or even remove some old stuff, etc.)
One small suggestion:
You can use Spring factories and then you don't even need to make an #Import in case of spring boot. just add a maven dependency and it will load the configuration automatically.
Now, make sure that you work correctly with dependencies in case of that approach.
Since you code will include both spring and Juice dependent code, you'll add dependencies on both for your maven/gradle module of the library. This means, that consumer that uses, say, guice, will get all the spring stuff because of your library. There are many ways to overcome this issue depending on the build system of your choice, just want wanted to bring it up

Better Dagger encapsulation

I'm using Dagger across several Gradle modules in an android project. I have a lib and app module. Inside lib module I have two classes PrivateThing and ExposedThing. ExposedThing depends on PrivateThing.
I have a dagger #Module to provide these two things:
#Module
public class LibModule {
#Provides
ExposedThing provideExposedThing(PrivateThing privateThing) {
return new ExposedThing(privateThing);
}
#Provides
PrivateThing providePrivateThing() {
return new PrivateThing();
}
}
In the app module, I have a single class SomeUiElement which depends on ExposedThing and a separate module:
#Module
public class ApplicationModule {
#Provides
SomeUiElement provideSomeUiElement(ExposedThing exposedThing) {
return new SomeUiElement(exposedThing);
}
}
And a component to bring everything together:
#Singleton
#Component(modules = {
ApplicationModule.class,
LibModule.class
})
public interface ApplicationComponent {
void inject(SomeActivity activity);
}
Now I want to enforce that nothing in the app module can depend on PrivateThing. I think I'm asking something similar to this question. One solution was to use component dependency. However the documentation recommends subcomponents see "Subcomponents for encapsulation".
Which is the preferred way to do this? Won't either method mean that lib module supplies it's own Component? I thought this was not a best practice, that libraries should only supply a Module.

Using Dagger 2.11 with android modular project

I started working on a new Android project from scratch. After understanding the project scope and requested features, I've came up with a modular architecture (basically wrapping every feature into a feature or android module) that looks as following
Everything looks perfect until I wanted to introduce dagger to glue all the modules. The problem is that I want every module to has its own dagger component/subcomponent and it's modules in order to provide dependencies and expose them the graph to be using by other component or the parent one.
Google official dagger documentation states that subcomponents has direct access to parent component dependencies' and not vice versa. However, in my case the base component require dependencies from the data module and this latter itself require dependencies from the network module.
is there any solution for this problem knowing that i want every android module to have its own sub-component preferably? If not, is there any solution anyway?
Thank you.
Edit:
Here is how my project structure looks like
And this is how I setup my dagger graph
My AppComponent(Dagger root)
#Singleton
#Component(modules = {
AppModule.class,
ActivityBuilder.class,
AndroidSupportInjectionModule.class
})
public interface AppComponent {
void inject(CatApp application);
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
}
My App Module
#Module(subcomponents = DataComponent.class)
public class AppModule {
#Provides
#Singleton
Context provideContext(Application application) {
return application.getApplicationContext();
}
}
My DataComponent (located at the data android module)
#Subcomponent(modules = DataModule.class)
public interface DataComponent {
#Subcomponent.Builder
interface Builder {
DataComponent build();
}
}
Data module (located at data android module) that should provide the implementation of SystemManager
#Module(subcomponents = NetworkComponent.class)
public class DataModule {
#Provides
#Singleton
ISystemManager provideSystemManager(SystemManager systemManager) {
return systemManager;
}
}
Network Component (located at Network Android Module)
#Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {
#Subcomponent.Builder
interface Builder {
NetworkComponent build();
}
}
Network Module (located at Network Android Module) and should provide implementation of INetWorkManager
#Module
public class NetworkModule {
#Provides
#Singleton
INetworkManager provideNetworkManager(NetworkManager networkManager) {
return networkManager;
}
}
I am using #Inject annotation at all constructors so my configurations is all setup but the issue is that dagger doesn't compiles these subcomponent for some reason and I get this error when compiled:
Error:(27, 8) error: [dagger.android.AndroidInjector.inject(T)] com.github.andromedcodes.network.INetworkManager cannot be provided without an #Provides-annotated method.
com.github.andromedcodes.network.INetworkManager is injected at
com.github.andromedcodes.data.SystemManager.<init>(networkManager)
com.github.andromedcodes.data.SystemManager is injected at
com.github.andromedcodes.data.di.DataModule.provideSystemManager(systemManager)
com.github.andromedcodes.domain.managers.ISystemManager is injected at
com.github.andromedcodes.domain.interactors.CheckSystemAvailability.<init>(systemManager)
com.github.andromedcodes.domain.interactors.CheckSystemAvailability is injected at
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter.<init>(checkSystemAvailability)
com.github.andromedcodes.chasseautrsor.views.Splash.SplashPresenter is injected at
com.github.andromedcodes.chasseautrsor.di.SplashModule.bindSplashPresenter(presenter)
com.github.andromedcodes.chasseautrsor.views.Contract.Presenter is injected at
com.github.andromedcodes.mvp.BaseActivity.mPresenter
com.github.andromedcodes.chasseautrsor.views.SplashScreenActivity is injected at
dagger.android.AndroidInjector.inject(arg0)
How can I fix this issue knowing that I want to provide ISystemManager implementation at Data android Module and INetworkManager at Network Android Module?
Thank you.
Subcomponents automatically have access to objects bound in the parent components' graph, which makes sense, because subcomponents have exactly one parent component—there's no ambiguity. Parent components do not have automatic access to subcomponents' graph because you can create as many subcomponent instances as you'd like; it's not clear which instance you're trying to access. In general, unless you need different variations on an object graph (which you'd do with private modules or child injectors in Guice) or unless you wanted to hide implementation details (e.g. internal network objects), you may be better off installing your modules all in the same Component and skipping the subcomponent strategy.
However, if you do want to separate your graph or create multiple subcomponent instances, you could also create a subcomponent instance in a scoped #Provides method. That way NetworkComponent has a separate graph with private bindings, but can also use dependencies you expose in AppComponent, and you can also ensure that there is exactly one copy of NetworkComponent and its relevant bindings in your graph. You'll also need to put a getter (provision method or factory method) on the Subcomponent, so you can access some of its bindings from outside, in exactly the same way that you need a getter or injector method on a #Component for it to be useful.
#Subcomponent(modules = NetworkModule.class)
public interface NetworkComponent {
/** Allow anyone with a NetworkComponent instance to get the INetworkManager. */
INetworkManager getINetworkManager();
#Subcomponent.Builder
interface Builder {
NetworkComponent build();
}
}
/**
* Creates a singleton NetworkComponent. Install this in AppComponent's module,
* or in your data module if that encapsulates network calls.
*/
#Singleton #Provides NetworkComponent networkComponent(
NetworkComponent.Builder builder) {
return builder.build();
}
/** Make the INetworkManager accessible, but not the NetworkManager impl. */
#Provides static provideNetworkManager(NetworkComponent networkComponent) {
return networkComponent.getINetworkManager(); // add this to NetworkComponent
}
For further reference, see the "Subcomponents for Encapsulation" section on in the Dagger 2 docs on Subcomponents:
Another reason to use subcomponents is to encapsulate different parts of your application from each other. For example, if two services in your server (or two screens in your application) share some bindings, say those used for authentication and authorization, but each have other bindings that really have nothing to do with each other, it might make sense to create separate subcomponents for each service or screen, and to put the shared bindings into the parent component.
In the following example, the Database is provided within the #Singleton component, but all of its implementation details are encapsulated within the DatabaseComponent. Rest assured that no UI will have access to the DatabaseConnectionPool to schedule their own queries without going through the Database since that binding only exists in the subcomponent.

How to inject implementations from another module

I'm having a project based on Dagger 2 which consists of two modules. The core module includes some interfaces and some classes that have member injections declared for these interfaces.
The actual implementations of these interfaces are included in the second module which is an Android project. So, naturally the provide methods for these are included in the Android project.
Dagger will complain during compilation about not knowing how to inject these in the core module.
Any thoughts on how to achieve this without using constructor injections?
In short, I just tried this, and it works. Be sure to check the exact error messages and make sure you are providing these interfaces and #Inject annotations are present.
There is probably just some wrong named interface or a missing annotation. Following up is a full sample using your described architecture that is compiling just fine. The issue you are currently experiencing is probably the one described in the last part of this post. If possible, you should go with the first solution though and just add those annotations.
The library
For reproducability this sample has minimalist models. First, the interface needed by my class in the library module:
public interface MyInterface {
}
Here is my class that needs that interface. Make sure to declare it in the constructor and provide the #Inject annotation!
#MyScope // be sure to add scopes in your class if you use constructor injection!
public class MyClassUsingMyInterface {
private MyInterface mMyInterface;
#Inject
public MyClassUsingMyInterface(MyInterface myInterface) {
mMyInterface = myInterface;
}
}
The idea is that the interface will be implemented by the app using MyClassUsingMyInterface and provided by dagger. The code is nicely decoupled, and my awesome library with not so many features is complete.
The application
Here need to supply the actual coupling. This means to get MyClassUsingMyInterface we have to make sure we can supply MyInterface. Let's start with the module supplying that:
#Module
public class MyModule {
#Provides
MyInterface providesMyInterface() {
return new MyInterface() {
// my super awesome implementation. MIT license applies.
};
}
}
And to actually use this, we provide a component that can inject into MyTestInjectedClass that is going to need MyClassUsingMyInterface.
#Component(modules = MyModule.class)
public interface MyComponent {
void inject(MyTestInjectedClass testClass);
}
Now we have a way to provide the requested interface. We declared that interface needed by the library class in a constructor marked with #Inject. Now I want a class that requires my awesome library class to use. And I want to inject it with dagger.
public class MyTestInjectedClass {
#Inject
MyClassUsingMyInterface mMyClassUsingMyInterface;
void onStart() {
DaggerMyComponent.create().inject(this);
}
}
Now we hit compile...and dagger will create all the factories needed.
Inject Libraries you can not modify
To just provide the full scale of dagger, this sample could also have been without actual access to the source code of the library. If there is no #Inject annotation dagger will have a hard time creating the object. Notice the missing annotation:
public class MyClassUsingMyInterface {
private MyInterface mMyInterface;
public MyClassUsingMyInterface(MyInterface myInterface) {
mMyInterface = myInterface;
}
}
In that case we have to manually provide the class. The module would be needed to be modified like the following:
#Module
public class MyModule {
#Provides
MyInterface providesMyInterface() {
return new MyInterface() {
};
}
#Provides
MyClassUsingMyInterface providesMyClass(MyInterface myInterface) {
return new MyClassUsingMyInterface(myInterface);
}
}
This introduces more code for us to write, but will make those classes available that you can not modify.

How to use dagger in a android library project

I'm currently trying to add Dagger to my android projects. For the apps projects its easy and clear to me, how to build the ObjectGraph. But I dont quite know whats the best way to do this in my android library projects.
Should I keep building the ObjectGraph in the Application class of the apps and pass the OG over to a LibraryModule - plussing the OG of library to the Apps OG? Or should i build the whole ObjectGraph in the library?
What if I need to inject a class in the library by ObjectGraph.inject(this)? In my Apps projects I can get the OG from the Application class. But how to handle this in the library? Should I add a #Provides method for the ObjectGraph?
Big thanks for your help.
Edit:
In short: How can I call ObjectGraph.inject(this) in my library project where I don't have access to the OG because it is being builded in the Application Class?
In case someone using Dagger 2 gets here, this is the way I've done in my App:
In the library module I've created the following Module and Component:
#Module
public class ModuleUtil {
#Provides
public RestTemplate provideRestTemplate() {
return new RestTemplate();
}
}
#Singleton
#Component(
modules = {
ModuleUtil.class
})
public interface MainComponent {
void inject(Postman postman);
}
And then I've created the Singleton below in order to manage the injections:
public class DaggerWrapper {
private static MainComponent mComponent;
public static MainComponent getComponent() {
if (mComponent == null) {
initComponent();
}
return mComponent;
}
private static void initComponent () {
mComponent = DaggerMainComponent
.builder()
.utilModule(new ModuleUtil())
.build();
}
}
When some class from the library module needs to inject its members, I simply call DaggerWrapper.getComponent().inject(this); and that't it.
I'm doing this way:
#Module classes belong to the main project and they provide implementations which you are injecting to library elements, so there are no #Module classes in the library projects
Library elements which are expecting dependency must have access to ObjectGraph and call .inject() on themselves, but main project should give ObjectGraph instance to the library with provided #Module dependency
How to get ObjectGraph from main project into the library? You could have interface like this:
interface Injector {
void inject(Object object);
public ObjectGraph getObjectGraph();
}
Context objects like Activity or Application class implements this interface (holders of ObjectGraph objects).
If you have example of Activity in the library module which needs something to inject from the main project this would look like this:
class LibraryActivity extends Activity {
#Inject ActivationModule instance;
void onCreate(... ) {
Injector injector = (Injector)getApplicationContext();
injector.inject(this)
}
}
ActivationModule is the class/interface in the library project.
Main project has application class which implements Injector interface and creates ObjectGraph with provided dependecy for ActivationModule in the library project.
class MyApplicationInTheMainProject extends Application implements Injector {
ObjectGraph graph;
#Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(new ActivationModuleImpl(this));
}
#Override public void inject(Object object) {
graph.inject(object);
}
#Override public ObjectGraph getObjectGraph() {
return graph;
}
}
#Module(injects = {
LibraryActivity.class
}, library = true)
class ActivationModuleImpl implements ActivationModule {
....
}
if you are giving this library to people and they dont know nothing about your scenario so you must write it in a way that your Dagger works perfectly without any help from user. (the easier to work with the better practice)
i just wrote some library for you to show how to do it. i wrote the library in a way that you can even run it standalone and see the result in the messages tab. user of your library doesnt need to know nothing about dagger and does nothing he just uses the library and dagger will be configured:
https://github.com/amirziaratii/libraryUsingDagger.git
if this library is something you use it yourself and for your own project, the best practice is do it like in this project of my friend:
https://github.com/mmirhoseini/trakt.tv
all your questions are answered in these two projects. ask any question and ill answer in comment.

Categories