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));
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 have a project that provides an interface, let's call it IImplementMe, which i want to inject into my project. This interface will be implemented by various producers, so I need to inject all implementations. I am trying to use TypeLiteral for this.
Here is the code of the producer :
#Singleton
public class SomeImplementation implements IImplementMe {
private final String value;
#Inject
public SomeImplementation(final SomeOtherConfig configuration) {
this.value= configuration.getValue();
}
#Override
public String getValue() {
return value;
}
}
And in my registry class I have register(IImplementMe.class).to(SomeImplementation.class);
Then, in my project I inject it like this :
#Inject
public SomeEndpoint(final List<IImplementMe> implementations){
///
}
and i bind it like
private static class MarketDataSetTypeLiteral extends TypeLiteral<List<IImplementMe>> {
}
bind(new MarketDataSetTypeLiteral()).toRegistry();
I made sure my SomeIMplementation constructor gets called, but in my endpoint the List is empty, so no implementation is provided. I'm using guice for injection. Any ideas ?
LE: It turns out that the provided implementation is created after my endpoint class is created (at creation time it injects a reference of an empty list). Later in the lifecycle the reference is updated with the implementation, so I actually have access to it after guice does it's stuff.
I'm guessing it's due to the maven dependencies, and how guice handles the instantiations. Since the producer must have a dependency on my project, I guess it makes sense it gets instantiated last, thus causing my initial problem.
You are looking for multibindings -> https://github.com/google/guice/wiki/Multibindings
public class IImplementMeModule extends AbstractModule {
public void configure() {
Multibinder< IImplementMe > uriBinder = Multibinder.newSetBinder(binder(), IImplementMe.class);
uriBinder.addBinding().to(SomeImplementationOfIImplementMe.class);
uriBinder.addBinding().to(AnotherImplementationOfIImplementMe.class);
... // bind plugin dependencies, such as our Flickr API key
}
}
Then you can inject the set of IImplemetnMe as following
#Inject TweetPrettifier(Set<IImplemetnMe> implementations)
I would suggest you to have a look at MapBindings which allows you provide keys for each implementation and then you will be able to inject your bindings as a Map
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.
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.
I have this class:
public class House {
private final Door door;
private final Window window;
private final Roof roof;
#Inject
public House(Door door, Window window, Roof roof) {
this.door = door;
this.window = window;
this.roof = roof;
}
}
Where Door, Window and Roof are concrete classes. Now if I want to implement a Module for this scenario, I would do it like this:
public class HouseModule extends AbstractModule {
#Override
protected void configure() {
bind(Door.class).to(Door.class);
bind(Window.class).to(Window.class);
bind(Roof.class).to(Roof.class);
}
}
But I wonder if this is the right way to bind concrete classes, or if there are easier ways. I feel there is an easier way to this.
This is the way to go:
protected void configure() {
bind(Door.class);
bind(Window.class);
bind(Roof.class);
}
Since they are concrete classes, as Guice says, you can't bind them to themselves :-)
Check out the Binder docs, it notes:
bind(ServiceImpl.class);
This statement does essentially nothing; it "binds the ServiceImpl class to itself" and does not change Guice's default behavior. You may still want to use this if you prefer your Module class to serve as an explicit manifest for the services it provides. Also, in rare cases, Guice may be unable to validate a binding at injector creation time unless it is given explicitly.
Concrete classes with constructor marked as #Inject are automatically available for injection. But it helps the developer (you) know what is configured in the module.
Guice's Just-In-Time binding does exactly what you want. Given your Door, Window and Roof meet following requirements (quoted from the Guice documentation):
either a public, no-arguments constructor, or a constructor with the #Inject annotation
an empty Module implementation will be sufficient:
public class HouseModule extends AbstractModule {
#Override
protected void configure() {
}
}
Binding is needed to link Interface and Implementation class (to change to other implementation in test env for example). But since you have concrete classes, no need for binding to, just bind classes