While exploring Guice, I had a question on the way the dependencies are injected.
Based on my understanding, one of the important aspects of DI is that, the dependency is known and is injected at runtime.
In Guice, to inject a dependency we either need to add the binding or implement a provider. Adding a dependency takes a class object which adds a compile time dependency on that class. One way to avoid that is to implement it as a provider and let the provider use reflection to dynamic load the class.
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
bind(CreditCardProcessor.class).toProvider(
BofACreditCardProcessorProvider.class);
bind(CreditCardProcessor.class).annotatedWith(BofA.class).toProvider(
BofACreditCardProcessorProvider.class);
bind(CreditCardProcessor.class).annotatedWith(Amex.class).toProvider(
AmexCreditCardProcessorProvider.class);
}
#Provides
PaymentProcessor createPaymentProcessor() {
return new PayPalPaymentProcessor();
}
#Provides
PayPalPaymentProcessor createPayPalPaymentProcessor() {
return new PayPalPaymentProcessor();
}}
Is there a reason why Guice choose class object over class name? That could have removed the compile time dependency right?
If your interface and implementation are defined in the same dependency (that is, in the same JAR file) then you already have a hard build dependency on the implementation, whether you use Guice or not.
Basically, as soon as you have:
public final class MyClass {
public void doSomething(Foo foo);
}
Then to compile MyClass a definition of Foo needs to be on the compile-time classpath.
The way to resolve this is to separate out the interface from the implementation. For example, if Foo is an interface, and FooImpl is the implementation of it, you would put FooImpl in a different dependency (that is, a different JAR file) from Foo.
Now, let's say you have two sub-projects in Maven:
foo-api/
pom.xml
src/main/java/com/foo/Foo.java
foo-impl/
pom.xml
src/main/java/com/foo/FooImpl.java
Where should the Guice module that binds Foo live? It shouldn't live in the foo-api project, it should live in the foo-impl project, alongside FooImpl.
Now suppose you have a separate implementation of Foo (let's call it SuperFoo), and your project needs a Foo, but it could be either FooImpl or SuperFoo.
If we make SuperFoo its own project:
super-foo/
pom.xml
src/main/java/com/super/foo/SuperFoo.java
src/main/java/com/super/foo/SuperFooModule.java
Now all your application code can simply #Inject Foo and use the foo. In your main() method (or wherever you create your Injector) you need to decide whether to install FooModule (from foo-impl) or SuperFooModule (from super-foo).
That is the place where reflection may be warranted. For example, you could have a configuration flag foo_module which could be set to either "com.foo.FooModule" or "com.super.foo.SuperFooModule". You could decide which one to install using code like this:
public static void main(String[] args) {
Config config = parseConfig(args);
List<Module> modules = new ArrayList<>();
modules.add(...); // application modules
String fooModuleName = config.get("foo_module");
Class<? extends Module> moduleClass =
Class.forName(fooModuleName).asSubclass(Module.class);
modules.add(moduleClass.newInstance());
Injector injector = Guice.createInjector(modules);
injector.getInstance(MyApplication.class).run();
}
Of course, you could also use any other mechanism you like to select which module to install. In many cases, you don't even really want to do this reflectively, you can simply change the code at the same time you change the build dependency.
Related
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
I'm starting to use Dagger 2 in an application I'm developing but I have some questions about how Dagger 2 works.
I get the all the logic behind the #Provides methods and the #Inject annotation for initialising your dependencies, but the #Inject annotation to class constructors kind of bugs my mind.
For example:
Im my app, I have one module defined, the ContextModule, to retrieve the context of my application:
ContextModule.java
#Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
#Provides
public Context context() {
return this.context;
}
}
This module is used by my BaseActivityComponent:
BaseActivityComponent.java
#BaseActivityScope
#Component(modules = ContextModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
}
So far so good.. then I have an AuthController class, that depends on the context and I want to inject it in my BaseActivity. So in my AuthControllers.class I have something like:
public class AuthController {
private Context context;
#Inject
public AuthController(Context context) {
this.context = context;
}
public void auth() {
// DO STUFF WITH CONTEXT
}
}
And I inject it in my BaseActivity like:
public class BaseActivity extends AppCompatActivity {
#Inject
AuthController authController;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseActivityComponent component = DaggerBaseActivityComponent.builder()
.contextModule(new ContextModule(this))
.build();
component.injectBaseActivity(this);
authController.auth();
}
}
Now my question is, how does dagger knows that my AuthControllers is a dependency for BaseActivity? Just by declaring
#Inject
AuthController authController;
it's like the same thing as if I created a ControllerModule like:
#Module(includes = ContextModule.class)
public class ControllerModule {
#Provides
AuthController authController(Context context) {
return new AuthController(context);
}
}
And then in my BaseActivityComponent I would add my AuthController getter and change my dependency module to ControllersModule:
#BaseActivityScope
#Component(modules = ControllersModule.class)
public interface BaseActivityComponent {
void injectBaseActivity(BaseActivity baseActivity);
AuthController getAuthController();
}
When I call injectBaseActivity(this) it "tells" dagger that all #Inject annotations are dependencies of my class, and then it searchers my project for #Inject annotated constructors that matches that type?
I thought a good thing about Dagger 2 is that the Module files could be used as a "documentation" of my dependencies three. But if just add #Inject in all the constructors I have control of, couldn't it get a little confusing in the future, since you don't know what actually depends on what? (I mean, you know what depends on what, you just have to browse a lot of files to really find out)
Is there any best practices for when using #Inject annotations in constructors or when to add the #Provides method in Modules files?
I get that using #Inject in constructor I don't need to change the constructor definition in my Module file, but is there any downside?
Thanks.
When I call injectBaseActivity(this) it "tells" dagger that all #Inject annotations are dependencies of my class, and then it searches my project for #Inject annotated constructors that matches that type?
Exactly. But it's not done when you call injectBaseActivity, but it all happens during compile time. This is one way of annotation processing (another makes use of reflection at runtime).
When you build your project the dagger-annotation-processor you include (as a dependency)in your build.gradle file gets called with a list of all your fields, classes, etc annotated by the #Inject annotation and builds a dependency graph with it. It then resolves the graph, generating source code that provides all the dependencies for the items on the graph.
injectBaseActivity just executes the code which was generated before, and assigns all the dependencies to your object. It is proper source code, which you can read, and debug.
The reason this is a compile step—simply put—is performance and validation. (e.g. If you have some dependency cycle, you get a compile error)
how does dagger knows that my AuthControllers is a dependency for BaseActivity?
#Inject
AuthController authController;
By annotating the field #Inject dagger knows you want an AuthController. So far so good. Now dagger will look for some means to provide the controller, looking for it within the component, the components dependencies, and the components modules. It will also look whether the class can be supplied on its own, because it knows about its constructor.
How does dagger know about the objects constructor if you don't include it in any module?
#Inject
public AuthController(Context context) { /**/ }
By annotating the constructor with inject you also told dagger that there is a class called AuthController and you need a context for it to be instantiated. It is basically the same as adding it to your module.
A module #Provides method should be used if you don't have the source code to just add the #Inject annotation to the constructor, or if the object needs further initialization. Or in your case...
[...]the Module files could be used as a "documentation" of my dependencies tree [...]
Yes, of course you could do that. But as your project grows you will have to maintain a lot of unnecessary code, since the same could have been done with a simple annotation on the constructor.
Is there any best practices for when using #Inject annotations in constructors or when to add the #Provides method in Modules files?
If you want to provide different versions for a different context (e.g. implementing an interface in 2 different ways) there is also the #Binds annotation that tells dagger which class you wish to provide as implementation.
Other than that I believe you should always use constructor injection when possible. If something changes you don't have to touch any other parts of your code, and it is just less code that you write, and hence less places where you could include a bug.
Also Dagger can and does optimize a lot by knowing more, and if you implement unnecessary code it will have to work with the overhead you introduced
Of course in the end it is all up to what you think is best. After all it is you that has to work with your code ;)
We have a set of interfaces e.g BookingInterface, InvoiceInterface,PaymentInterface that are implemented by different business processes
e.g
Business1BookingInterface implements BookingInterface {
}
Business1InvoiceInterface implements InvoiceInterface {
}
Business2BookingInterface implements BookingInterface {
}
Business2InvoiceInterface implements InvoiceInterface {
}
We are looking at making each business process a Plugin that implements the set of interfaces exposed.
In our rest API we would like a particular plugin interface injected into our service
e.g
#Inject
public BillingService(Configuration configuration,
EventDispatcher eventDispatcher,
Map<String,PluginInterface> theCorrectInterfaceImplementation) {
}
I am looking up MapBindings, AssistedInjection and FactoryModuleBuilder but not sure as to how do i get the right Guice setup to inject the required plugin interface at runtime.
MapBinder (as one of the Multibindings features) is the right call for a plugin-style interface. FactoryModuleBuilder is an implementation detail of Assisted Injection, which is just a way to mix explicit constructor parameters with Guice-provided constructor parameters. If you don't need to do that, then you don't need assisted injection.
You'll still need to set up those bindings in a module:
public Business1Module extends AbstractModule {
#Override public void configure() {
MapBinder<String, BookingInterface> bookingBinder =
MapBinder.newMapBinder(binder(), String.class, BookingInterface.class);
bookingBinder.addBinding("business1").to(Business1BookingInterface.class);
MapBinder<String, InvoiceInterface> invoiceBinder =
MapBinder.newMapBinder(binder(), String.class, InvoiceInterface.class);
invoiceBinder.addBinding("business1").to(Business1InvoiceInterface.class);
}
}
...and then install that Module in your injector.
Injector yourInjector = Guice.createInjector(/*...*/,
new Business1Module(), new Business2Module());
The upshot is that you don't need to aggregate those dependencies yourself, and that Guice won't complain about multiple conflicting bindings to Map<String, BookingInterface> or Map<String, InvoiceInterface> (etc)...they will be automatically combined into one big map each.
Other notes:
Multibindings is in a separate JAR, so don't forget to install that on your classpath.
This might be an excellent reason to use Modules with constructor parameters:
Injector yourInjector = Guice.createInjector(/*...*/,
new BusinessModule("business1",
Business1BookingInterface.class, Business1InvoiceInterface.class),
new BusinessModule("business2",
Business2BookingInterface.class, Business2InvoiceInterface.class));
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.
I gave to Google Guice the responsibility of wiring my objects. But, how can I test if the bindings are working well?
For example, suppose we have a class A which has a dependence B. How can I test that B is injected correctly?
class A {
private B b;
public A() {}
#Inject
public void setB(B b) {
this.b = b
}
}
Notice that A hasn't got a getB() method and I want to assert that A.b isn't null.
For any complex Guice project, you should add tests to make sure that the modules can be used to create your classes. In your example, if B were a type that Guice couldn't figure out how to create, then Guice won't be able to create A. If A wasn't needed to start the server but was needed when your server was handling a request, that would cause problems.
In my projects, I write tests for non-trivial modules. For each module, I use requireBinding() to declare what bindings the module requires but doesn't define. In my tests, I create a Guice injector using the module under test and another module that provides the required bindings. Here's an example using JUnit4 and JMock:
/** Module that provides LoginService */
public class LoginServiceModule extends AbstractModule {
#Override
protected void configure() {
requireBinding(UserDao.class);
}
#Provides
LoginService provideLoginService(UserDao dao) {
...
}
}
#RunWith(JMock.class)
public class LoginServiceModuleTest {
private final Mockery context = new Mockery();
#Test
public void testModule() {
Injector injector = Guice.createInjector(
new LoginServiceModule(), new ModuleDeps());
// next line will throw an exception if dependencies missing
injector.getProvider(LoginService.class);
}
private class ModuleDeps extends AbstractModule {
private final UserDao fakeUserDao;
public ModuleDeps() {
fakeUserDao = context.mock(UserDao.class);
}
#Override
protected void configure() {}
#Provides
Server provideUserDao() {
return fakeUserDao;
}
}
}
Notice how the test only asks for a provider. That's sufficient to determine that Guice could resolve the bindings. If LoginService was created by a provider method, this test wouldn't test the code in the provider method.
This test also doesn't test that you binded the right thing to UserDao, or that UserDao was scoped correctly. Some would argue that those types of things are rarely worth checking; if there's a problem, it happens once. You should "test until fear turns to boredom."
I find Module tests useful because I often add new injection points, and it's easy to forget to add a binding.
The requireBinding() calls can help Guice catch missing bindings before it returns your injector! In the above example, the test would still work if the requireBinding() calls were not there, but I like having them because they serve as documentation.
For more complicated modules (like my root module) I might use Modules.override() to override bindings that I don't want at test time (for instance, if I want to verify that my root object to be created, I probably don't want it to create an object that will connect to the database). For simple projects, you might only test the top-level module.
Note that Guice will not inject nulls unless the field as annotated with #Nullable so you very rarely need to verify that the injected objects are non-null in your tests. In fact, when I annotate constructors with #Inject I do not bother to check if the parameters are null (in fact, my tests often inject null into the constructor to keep the tests simple).
Another way to test your configuration is by having a test suite that tests your app end-to-end. Although end-to-end tests nominally test use cases they indirectly check that your app is configured correctly, (that all the dependencies are wired, etc etc). Unit tests on the other hand should focus exclusively on the domain, and not on the context in which your code is deployed.
I also agree with NamshubWriter's answer. I'm am not against tests that check configuration as long as they are grouped in a separate test suite to your unit tests.
IMHO, you should not be testing that. The Google Guice guys have the unit tests to assert that the injections work as expected - after all, that's what Guice is designed to do. You should only be writing tests for your own code (A and B).
I don't think you should test private members being set. Better to test against the public interface of your class. If member "b" wouldn't be injected, you'll probably get a NullPointerException executing your tests, which should be plenty of warning.