Guice: is it possible to inject modules? - java

I have a Module that requires some Depedency. Is there a way Modules themselves can be injected? I realize this is a bit of a chicken and egg situation...
Example:
public class MyModule implements Module {
private final Dependency d_;
#Inject public MyModule(Dependency d) {
d_ = d;
}
public void configure(Binder b) { }
#Provides Something provideSomething() {
// this requires d_
}
}
I suppose in this case the solution would be to turn the #Provides method into a full-fledged Provider<Something> class. This is clearly a simplified example; the code I'm dealing with has many such #Provides methods so cutting them each into individual Provider<...> classes and introducing a module to configure them adds a fair amount of clutter - and I thought Guice was all about reducing boilerplate clutter?
Perhaps it's a reflection of my relative noobyness to Guice but I've come across a fair few cases where I've been tempted to do the above. I must be missing something...

#Provides methods can take dependencies as parameters just like parameters to an #Inject annotated constructor or method:
#Provides Something provideSomething(Dependency d) {
return new Something(d); // or whatever
}
This is documented here, though perhaps it could be made to stand out more.

Using a provider or #Provides methods are great if you need a dependency to manually construct an object. However, what if you need something to help you decide how to configure the bindings themselves? It turns out you can use Guice to create (and configure) your module.
Here is a (contrived) example. First, the module we want to configure:
/**
* Creates a binding for a Set<String> which represents the food in a pantry.
*/
public class PantryModule extends AbstractModule {
private final boolean addCheese;
#Inject
public ConditionalModule(#Named("addCheese") boolean addCheese) {
this.addCheese = addCheese;
}
#Override
protected void configure() {
Multibinder<String> pantryBinder = Multibinder
.newSetBinder(binder(), String.class);
pantryBinder.addBinding().toInstance("milk");
if (addCheese) {
pantryBinder.addBinding().toInstance("cheese");
}
pantryBinder.addBinding().toInstance("bread");
}
}
The PantryModule expects a boolean value to be injected to decide whether or not it should include cheese in the pantry.
Next, we'll use Guice to configure the module:
// Here we use an anonymous class as the "configuring" module. In real life, you would
// probably use a standalone module.
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
// No cheese please!
bindConstant().annotatedWith(Names.named("addCheese")).to(false);
bind(PantryModule.class);
}
});
Module configuredConditionalModule = injector.getInstance(PantryModule.class);
Now that we have a configured module, we'll update our injector to use it...
//...continued from last snippet...
injector = injector.createChildInjector(configuredConditionalModule);
And finally we'll get the set of strings that represent our pantry:
//...continued from last snippet...
Set<String> pantry = injector.getInstance(new Key<Set<String>>() {});
for (String food : pantry) {
System.out.println(food);
}
If you put all the pieces together in a main method and run it, you'll get the following output:
milk
bread
If you change the binding to the "addCheese" boolean to true, you'll get:
milk
cheese
bread
This technique is cool, but probably only useful when you have control over the Injector instance and only when the module requires complex dependencies. Nonethless, I found a real need for this on a real project at work. If I did, then someone else might too.

The question is already well answered, but I just wanted to add a variation to Colin's example:
class MyModule extends AbstractModule {
public void configure() {
bind(Something.class).toProvider(new Provider<Something>() {
#Inject Dependency d;
Something get() { return d.buildSomething(); }
}
}
}
The #Provides method approach is clearer than what I have above for this simple case, but I've found that instantiating an actual Provider can be useful in some situations too. Something I stole from the mailing list; wouldn't have occurred to me on my own ;)

What is the problem with initializing the module just by calling new MyModule(d) or by creating a Provider<Something> that has an injected Injector? Those would appear to be the standard ways of handling this sort of problem. As has been mentioned, you can also use #Provides methods with arguments.
If the dependency is optional then you can create the module and then call a setter to initialize the value if needed (e.g., com.google.inject.persist.jpa.JpaPersistModule does this with properties, while using new JpaPersistModule(String) to load the correct configuration).
Otherwise I suppose it might be possible to do so (and then call createChildInjector(Modules... modules)), but I'd almost always prefer one of the other approaches to that one.

Related

How to configure providers with custom parameters?

My class depends on some services which needs to take few parameters and then make network call, currently I am passing those parameters and then creating those services via a factory injected into my class. I need to inject those services as a dependency instead, I know that I can create providers for them but in most of the examples I see that the providers are often bound to the fixed values like serveraddres etc. but I need to give then values during run time.
Below is my example code:
public SomeClass {
private final SomeFactory someFactory;
#Inject
SomeClass(SomeFactory factory) {
someFactory = factory;
}
public Foo getFoo(String fooId) {
FooService fooService = someFactory.getFooService(fooId);
return fooService.getFoo();
}
}
What I need to do is:
public SomeClass {
private final FooService fooService;
#Inject
SomeClass(FooService fooService) {
this.fooService = fooService;
}
public Foo getFoo(String fooId) {
return fooService.getFoo();
}
}
Update 1
Making the use case more clear:
#Provides
#RequestScoped
public SomeService provideSomeService(Dep1 dep1, String code) throws IOException {
return new SomeService.Builder()
.withApplicationName("Foo")
.setCode(code)
.build();
}
Here, code can be null by default and when needed I can give some value in it.
Can I somehow pass arguments to the provider before its created?
If you have a binding for your value (here, code is a String without a binding annotation), then your Update 1 is exactly what the code would look like.
In practice, there are a few differences:
Constants like int and String values are generally annotated with a binding annotation, either #Named or a custom annotation.
If you need to inject a value into an object graph after Guice initialization, but have a deep enough object graph that dependency injection is still a good idea, you can create a child injector. This way you can make a #Named("code") String accessible within one action or object, but not across your entire Guice application.
If your value for code is dynamic enough that it can't be provided through Guice as a key of its own, then you'll have to pass it in using a factory of some sort. For a Builder-based object, I'd say that your SomeFactory implementation is the best that I would come up with in your case.
If you don't need to use a Builder, and can let Guice create the object based on your fields or constructor parameters, you can code-generate a Factory.
Guice can generate a factory for you through FactoryModuleBuilder, in a feature known as "assisted injection".
Google's other tool, AutoFactory, will code-generate a factory implementation that works in both Guice and Dagger. (It's bundled as "Auto", which includes a model object generator called AutoValue that also generates annotation implementations.)
I put a small demonstration of a child injector and assisted injection in my other SO answer here.
The best approach here is to parameterize the module and pass the parameter through to a provider that you create at runtime:
public class MyModule extends AbstractModule {
private final String code;
public MyModule(String code) {
this.code = code;
}
#Override public void configure() {
Provider<Dep1> depProvider = getProvider(Dep1.class);
bind(SomeService.class)
.toProvider(() -> new SomeService.Builder()
.withApplicationName("Foo")
.withDep(depProvider.get())
.setCode(code)
.build())
.in(RequestScoped.class);
}
}

Guice: One "Provider<T>" for multiple implementations

I have an interface that has 20 or so annotated implementations. I can inject the correct one if I know which I need at compile time, but I now need to dynamically inject one based on runtime parameters.
As I understood the documentation, I would have to use 20 or so Provider<T> injections and then use the one I need, which seems rather excessive to me. Is there a way to have something like an inst(Provider<T>).get(MyAnnotation.class) to bind a specific implementation, and then have only that Provider injected into my class?
Inject a MapBinder.
In your module, load the bindings into the MapBinder, then make your runtime parameters injectable as well. This example is based on the one in the documentation:
public class SnacksModule extends AbstractModule {
protected void configure() {
MapBinder<String, Snack> mapbinder
= MapBinder.newMapBinder(binder(), String.class, Snack.class);
mapbinder.addBinding("twix").to(Twix.class);
mapbinder.addBinding("snickers").to(Snickers.class);
mapbinder.addBinding("skittles").to(Skittles.class);
}
}
Then, in your object, inject the Map and the parameter. For this example I will assume you've bound a java.util.Properties for your runtime parameters:
#Inject
public MyObject(Map<String, Provider<Snack>> snackProviderMap, Properties properties) {
String snackType = (String) properties.get("snackType");
Provider<Snack> = snackProviderMap.get(property);
// etc.
}
Note, with the same MapBinder you can inject either a simple Map<String, Snack> or a Map<String, Provider<Snack>>; Guice binds both.
If all you want is to get an instance programmatically, you can inject an Injector. It's rarely a good idea--injecting a Provider<T> is a much better idea where you can, especially for the sake of testing--but to get a binding reflectively it's the only way to go.
class YourClass {
final YourDep yourDep; // this is the dep to get at runtime
#Inject YourClass(Injector injector) {
YourAnnotation annotation = deriveYourAnnotation();
// getProvider would work here too.
yourDep = injector.getInstance(Key.get(YourDep.class, annotation));
}
}
If you're trying write a Provider that takes a parameter, the best way to express this is to write a small Factory.
class YourDepFactory {
#Inject #A Provider<YourDep> aProvider;
#Inject #B Provider<YourDep> bProvider;
// and so forth
Provider<YourDep> getProvider(YourParameter parameter) {
if (parameter.correspondsToA()) {
return aProvider;
} else if (parameter.correspondsToB()) {
return bProvider;
}
}
YourDep get(YourParameter parameter) {
return getProvider(parameter);
}
}

Is it possible to bind dependencies to interceptor in TestNG?

public class AbstractTest implements ITestListener {
#Inject
protected MobConfiguration mob;
#Override
public void onStart(ITestContext context) {
// TODO Auto-generated method stub
}
}
When I tried to inject dependencies in the listener class, it always returns null.
Is there any possible ways to handle DI in listener or interceptor implementer classes?
I have successfully tried this approach (using a factory, code example at the end of this answer). There is one addition to care for, if you use groups annotations, the thereby discrimination (as in line 126 in code for TestDIFactory.java - there again) seems to work reliable only if you use a testng.xml file.
Otherwise with annotation parameters only the default case (l. 130, TestDIFactory.java) seems to get active. One can easily check that by adding if(context.getIncludedGroups().length == 0) throw new NullPointerException("no groups found"); after l. 122, TestDIFactory.java
If you need the implements ITestListener explicitly it should be easy to modify the public void onStart(ITestContext context) method accordingly.
#Guice(moduleFactory = TestDIFactory.class)
public class YourTestClass {
#Inject protected MobConfiguration mob;
#Test(groups = {"unit"})
public void yourtest() {}
}
EDIT:
I have proven the factory approach problematic in one case:
If the modules provided by the factory share bindings meaning one object bound in module A is also bound in another module B but you request a combined module which installs / calls configure on A and B and then is returned by the factory. You run into a high change to get InstantiationExceptions. So rule of thumb for me: factories only when only one module per test is needed. In other cases I use i. e. #Guice(modules = {TestDIFactory.A.class, TestDIFactory.B.class}) assumed given A and B public access though.
While it will be possible in version 7.5.0, in the 7.4.0 you can just:
#Override
public void onStart(ITestContext context) {
final Injector parentInjector = context.getSuite().getParentInjector();
final YourGuiceModule module = parentInjector.getInstance(YourGuiceModule.class);
final MobConfiguration mob = parentInjector.createChildInjector(module).getInstance(MobConfiguration.class);
mob.useIt();
}
This is valid if you bind the module on the test, if you bind it on the parent module you can just do a:
context.getSuite().getParentInjector().getInstance(MobConfiguration.class);

Does Guice support a way of method injection (non setter injection)?

From what I understand Guice supports injection for: Constructors, Setters (which they call method injection for some reason), fields.
Can it also inject method parameters? For example:
void foo(InterfaceA a, InterfaceA a1){
...
}
interface InterfaceA{
...
}
class A implements InterfaceA{
....
}
class B implements InterfaceA{
....
}
I want to be able to bind a in foo to type A and a1 to B (will probably need annotation but lets ignore that for a second).
I want this to be done on invocation.
This seems different from the normal use cases (c'tor, fields, setters) in the sense that the dependency injection will happen on invocation rather than on object creation.
So is this possible?
Vladimir's answer is correct, but rather than injecting the injector, you can use field injection and Providers to do the same more concisely and to check that dependencies are satisfied at injector creation time. This code is the same as his, but modified to use Providers:
Injector injector = Guice.createInjector(b -> {
b.bind(InterfaceA.class).annotatedWith(Names.named("a")).to(A.class);
b.bind(InterfaceA.class).annotatedWith(Names.named("a1")).to(B.class);
b.bind(Invoke.class);
});
public class Invoke {
// Constructor injection works too, of course. These fields could also be
// made private, but this could make things difficult to test.
#Inject #Named("a") Provider<InterfaceA> aProvider;
#Inject #Named("a1") Provider<InterfaceA> a1Provider;
public void invoke() {
this.foo(aProvider.get(), a1Provider.get());
}
void foo(InterfaceA a, InterfaceA a1){
...
}
}
Well, you can do this:
Injector injector = Guice.createInjector(b -> {
b.bind(InterfaceA.class).annotatedWith(Names.named("a")).to(A.class);
b.bind(InterfaceA.class).annotatedWith(Names.named("a1")).to(B.class);
b.bind(Invoke.class);
});
public class Invoke {
private final Injector injector;
#Inject
Invoke(Injector injector) {
this.injector = injector;
}
public void invoke() {
this.foo(
injector.getInstance(Key.get(InterfaceA.class, Names.named("a"))),
injector.getInstance(Key.get(InterfaceA.class, Names.named("a1")))
);
}
void foo(InterfaceA a, InterfaceA a1){
...
}
}
But nothing more. Guice is a dependency injection framework and it usually means "construct objects with all their dependencies". While method parameters are dependencies formally (since the class is supposed to use them - this is the definition of dependency), they are not usually regarded as those by DI frameworks. It is understandable - this would make these frameworks much more complex for little to no gain, and also Java is not expressive enough language for such things not to look obscenely ugly.

How to #Inject into existing object hierarchy using Guice?

I have an existing object hierarchy where some objects have fields that need to be injected. Also there are some other objects that are constructed using Google Guice and need to be injected with references to some objects from previously described object hierarchy. How do I do such kind of injection with Guice?
The problem is that objects from existing hierarchy were not constructed using Guice, and therefore are not subject to inject process by default. There is, of course injector.injectMembers() method that is able to inject into existing object instance, but it does not work on object hierarchies.
For those wondering why I can't build mentioned object hierarchy using Guice. This hierarchy represents GUI objects and is built by a GUI framework (Apache Pivot) from a declarative GUI description (in fact this process can be described as object deserialization). That way interface construction is rather simple, and I only want to inject certain service references into interface objects and vice versa (for callbacks).
Approach I am currently about to take is described below.
For injecting into preexisting object hierarchy just let all objects that are interested in injection implement certain interface, like:
public interface Injectable {
void injectAll(Injector injector);
}
Those objects would then implement this interface like so:
public void injectAll(Injector injector) {
injector.injectMembers(this);
for (Injectable child : children)
child.injectAll(injector);
}
Then I'd just call mainWindow.injectAll(injector) for root object in hierarchy and all objects of interest are injected.
Not very nice solution, but gets the work done on one side. On the other side, I need to inject objects from this hierarchy. I guess it can be done via implementing custom provider for such objects.
Is there a better solution to my problem? Maybe there is also something wrong with my approach?
This solution will work, but I'd like to propose a slightly different one to you.
Specifically, since you're going to traverse a deep object structure, this really looks like a job for the Visitor pattern. Also, what you're describing seems to call out for a two-stage injector: a "bootstrap" stage that can inject stuff needed by the pivot-created hierarchy (but can't inject any pivot-created elements) and a second stage that is the real injector used by your app (that can inject anything).
What I would suggest is this basic pattern: make a visitor that traverses the hierarchy and, as it goes, it does injection on those things that need it and records those things that need to be injected elsewhere. Then, when it is done visitng everything, it uses Injector.createChildInjector to make a new Injector that can inject stuff from the original Injector and stuff from the pivot-created hierarchy.
First define a visitor that can hit everything in this hierarchy:
public interface InjectionVisitor {
void needsInjection(Object obj);
<T> void makeInjectable(Key<T> key, T instance);
}
Then define an interface for all your pivot-created elements:
public interface InjectionVisitable {
void acceptInjectionVisitor(InjectionVisitor visitor);
}
You'd implement this interface in your pivot-created classes as (assuming this code in the FooContainer class):
public void acceptInjectionVisitor(InjectionVisitor visitor) {
visitor.needsInjection(this);
visitor.makeInjectable(Key.get(FooContainer.class), this);
for (InjectionVisitable child : children) {
child.acceptInjectionVisitor(visitor);
}
}
Note that the first two statements are optional - it may be that some objects in the pivot hierarchy don't need injection and it could also be that some of them you wouldn't want to have injectable later. Also, notice the use of Key - this means that if you want some class to be injectable with a particular annotation you can do something like:
visitor.makeInjectable(Key.get(Foo.class, Names.named(this.getName())), this);
Now, how do you implement InjectionVisitor? Here's how:
public class InjectionVisitorImpl implements InjectionVisitor {
private static class BindRecord<T> {
Key<T> key;
T value;
}
private final List<BindRecord<?>> bindings = new ArrayList<BindRecord<?>>();
private final Injector injector;
public InjectionVisitorImpl(Injector injector) {
this.injector = injector;
}
public void needsInjection(Object obj) {
injector.injectMemebers(obj);
}
public <T> void makeInjectable(Key<T> key, T instance) {
BindRecord<T> record = new BindRecord<T>();
record.key = key;
record.value = instance;
bindings.add(record);
}
public Injector createFullInjector(final Module otherModules...) {
return injector.createChildInjector(new AbstractModule() {
protected void configure() {
for (Module m : otherModules) { install(m); }
for (BindRecord<?> record : bindings) { handleBinding(record); }
}
private <T> handleBinding(BindRecord<T> record) {
bind(record.key).toInstance(record.value);
}
});
}
}
You then use this in your main method as:
PivotHierarchyTopElement top = ...; // whatever you need to do to make that
Injector firstStageInjector = Guice.createInjector(
// here put all the modules needed to define bindings for stuff injected into the
// pivot hierarchy. However, don't put anything for stuff that needs pivot
// created things injected into it.
);
InjectionVisitorImpl visitor = new InjectionVisitorImpl(firstStageInjector);
top.acceptInjectionVisitor(visitor);
Injector fullInjector = visitor.createFullInjector(
// here put all your other modules, including stuff that needs pivot-created things
// injected into it.
);
RealMainClass realMain = fullInjector.getInstance(RealMainClass.class);
realMain.doWhatever();
Note that the way createChildInjector works ensures that if you have any #Singleton things bound in the stuff injected into the pivot hierarchy, you'll get the same instances injected by your real injector - the fullInjector will delegate injectoion to the firstStageInjector so long as the firstStageInjector is able to handle the injection.
Edited to add: An interesting extension of this (if you want to delve into deep Guice magic) is to modify InjectionImpl so that it records the place in your source code that called makeInjectable. This then lets you get better error messages out of Guice when your code accidentally tells the visitor about two different things bound to the same key. To do this, you'd want to add a StackTraceElement to BindRecord, record the result of new RuntimeException().getStackTrace()[1] inside the method makeInjectable, and then change handleBinding to:
private <T> handleBinding(BindRecord<T> record) {
binder().withSource(record.stackTraceElem).bind(record.key).toInstance(record.value);
}
You could inject MembersInjectors to inject nested fields. For example, this will deeply inject an existing Car instance:
public class Car {
Radio radio;
List<Seat> seats;
Engine engine;
public Car(...) {...}
#Inject void inject(RadioStation radioStation,
MembersInjector<Seat> seatInjector,
MembersInjector<Engine> engineInjector) {
this.radio.setStation(radioStation);
for (Seat seat : seats) {
seatInjector.injectMembers(seat);
}
engineInjector.injectMembers(engine);
}
}
public class Engine {
SparkPlug sparkPlug;
Turbo turbo
public Engine(...) {...}
#Inject void inject(SparkPlug sparkplug,
MembersInjector<Turbo> turboInjector) {
this.sparkPlug = sparkPlug;
turboInjector.injectMembers(turbo);
}
}

Categories

Resources