How to #Inject into existing object hierarchy using Guice? - java

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);
}
}

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);
}
}

MyBatis multiple data sources using single mapper

I'm working on a system that uses guice to bind and inject MyBatis mappers used to remove entries from different DBs. The fact is that all DB are located in different hosts but have the same structure. Since there are a lot of them and the number and location of the hosts change quite often, I would like to install a MyBatis module with different data sources that are loaded dynamically using the same mapper.
I've been looking around but can't figure out how to solve the mapper ambiguity. I also took a look to MyBatis beans CDI plugin, that makes it easier to add named mappers with multiple data sources, but still can't get it working since I don't have a fixed list of data sources that i can name.
Am I missing an easy way to achieve this?
You need to bind your MyBatisModule privately and expose the mappings with a unique binding attribute. I've got an example below. I've verified that it works, too :)
DaoModule: This module is setup to bind a single mapper to a key with a specific data-source. Note that this class is extending a "PrivateModue" and it's exposing the key to the parent module. You'll be using this key to inject the mapping.
public class DaoModule<T> extends PrivateModule {
private static final String ENVIRONMENT_ID = "development";
private final Key<T> key;
private final Class<T> mapper;
private final Provider<DataSource> dataSourceProvider;
public DaoModule(Key<T> key, Class<T> mapper, Provider<DataSource> dataSourceProvider) {
this.key = key;
this.mapper = mapper;
this.dataSourceProvider = dataSourceProvider;
}
#Override
protected void configure() {
install(new InnerMyBatisModule());
expose(key);
}
private class InnerMyBatisModule extends MyBatisModule {
#Override
protected void initialize() {
bind(key).to(mapper);
addMapperClass(mapper);
environmentId(ENVIRONMENT_ID);
bindDataSourceProvider(dataSourceProvider);
bindTransactionFactoryType(JdbcTransactionFactory.class);
}
}
}
MyModule: This module installs two DaoModules with the same mapper type by two different keys and different data-sources.
public class MyModule extends AbstractModule {
#Override
protected void configure() {
Key<MapperDao> key1 = Key.get(MapperDao.class, Names.named("Mapper1"));
Provider<DataSource> datasource1 = null;
Key<MapperDao> key2 = Key.get(MapperDao.class, Names.named("Mapper2"));
Provider<DataSource> datasource2 = null;
install(new DaoModule<MapperDao>(key1, MapperDao.class, datasource1));
install(new DaoModule<MapperDao>(key2, MapperDao.class, datasource2));
}
}
Main: And the main acquires the two mappers of the same type but with different data-sources.
public class Main {
public static void main(String... args) {
Injector i = Guice.createInjector(new MyModule());
MapperDao mapper1 = i.getInstance(Key.get(MapperDao.class, Names.named("Mapper1")));
MapperDao mapper2 = i.getInstance(Key.get(MapperDao.class, Names.named("Mapper2")));
}
}
Example Injection Class: This shows how to use field injection to inject the mappers
public class MyExampleClass {
#Inject
#Named("Mapper1")
MapperDao mapper1;
#Inject
#Named("Mapper2")
MapperDao mapper2;
}
This answer is for slightly different scope than the question. For anyone who has fixed number of datasources and needs to share a mapper, there is also a solution without using #Named the way it is described in accepted answer.
You can simply use
interface SomeMapperForDbA extends SomeMapper {}
and add + expose SomeMapperForDbA in the corresponding PrivateModule.
Interface name here acts as a logical data source discriminator, while all the mapping queries stil stay intact in one place in SomeMapper. There are pros and cons to this approach vs named injects, but it works and might save the day for some.
Obviously, you need to inject SomeMapperForDbA to use the DbA data source. That said, it can neatly be done in constructor only, while the class member type used in the actual code can just be the SomeMapper to avoid confusion.
Alternatively, you could add some DbA-specific selects to SomeMapperForDbA, if databases have common and different parts etc. In this case I would suggest a better name, that reflects such logic.
I.e. don't be afraid to extend mapper interfaces when needed.
org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource is designed for this purpose.
https://www.baeldung.com/spring-abstract-routing-data-source

Guice method injection using annotations

I have two Runnable classes, and I want to inject a dependency between them, so that the SecondProcedure runs using the Table created by the FirstProcedure.
class FirstProcedure implements Runnable {
private Table composers = new Table();
public void run() {
// populates the composers table
}
public Table getComposers() {
return composers;
}
}
class SecondProcedure implements Runnable {
private Table composers;
public void run() {
// writes the name of each composer to the console
}
public Table setComposers(final Table composers) {
this.composers = composers;
}
}
The idea is that in my main class I can instantiate both of the procedures, inject the relevant table (which should reference correctly even though it won't be populated by this point), work out the dependencies between the two procedures, and then run them in the right order. i.e. there will be a unique instance of each of these two procedures (but I'm intentionally avoiding the Singleton (anti)pattern so that I can have proper unit tests).
How can I go about this using Guice?
Can I annotate the setComposers method with something like:
#InjectTable(procedure=FirstProcedure.class, name="composers")
public Table setComposers(final Table composers) {
this.composers = composers;
}
and have a Guice module which will bind the Table in the SecondProcedure based on the class and name of the provided field?
I don't see anything which quite fits this paradigm in the bind() methods of AbstractModule.
(Aside from this, I'm not too keen on the design for this annotation itself, with the name of the field being in a string, instead of referring to the method explicitly somehow.)
I think you might be over-complicating the problem.
It looks like SecondProcedure has a simple dependency on Table:
class SecondProcedure {
#Inject
SecondProcedure(Table table) {
this.table = table;
}
}
And FirstProcedure is a Provider of Table:
class FirstProcedure implements Provider<Table> {
public Table get() {
return buildTheTable();
}
}
Your module then just needs to bind the provider:
class SomeModule extends AbstractModule {
protected void configure() {
bind(Table.class).toProvider(FirstProcedure.class);
}
}
A JIT binding of the #Inject annotated constructor will provide SecondProcedure, so you don't need to bind it explicitly.
Once you've done this, you might consider changing the name of FirstProcedure to TableProvider.
To use the FirstProcedure, you then just inject it, or get it from the injector:
injector.getInstance(FirstProcedure.class).run();
As an aside, the Guice singleton pattern (#Singleton scope) is not an anti-pattern as it's confined to the injector. There are plenty of cases where it's appropriate, and the Guice singleton implementation doesn't get in the way of testing.
Perhaps the thing you should be concerned about is static state. Guice itself provides a good explanation of why it is bad: http://code.google.com/p/google-guice/wiki/AvoidStaticState

Correct design of classes built for testability using constructor injection

Say I have these 3 layers of my code:
1. Database layer (ORM)
2. BusinessLogic
3. Application
Now, I write my code as follows:
Database layer:
This mainly has CURD operations over database.
class MyDatabaseLayer {
public int findValue(int k) {
// find v
}
public void insertValue(int k, int v) {
// Insert v
}
}
BusinessLogic:
This holds the actual logic to call database layer and do stuff.
class MyBusinessLogic {
private MyDatabaseLayer dbLayer;
public MyBusinessLogic(MyDatabaseLayer dbLayer) {
this.dbLayer = dbLayer;
}
public int manipulateValue(int k) {
dbLayer.findValue(k);
//do stuff with value
}
}
Application layer:
This calls the business logic and displays the data
MyBusinessLogic logic = new MyBusinessLogic(new MyDatabaseLayer ()); //The problem
logic.manipulateValue(5);
Now if you see in the application layer, it knows about the database layer, which is wrong. It knows too much.
Misko Hevery says: Constructor injection is good. But if I follow that, how will I achieve abstraction? And how can Google Guice help me here?
Note that for the testability Misko refers to, you ideally want to make interfaces for MyDatabaseLayer, MyBusinessLogic, etc. and have the constructors take those interfaces rather than concrete classes so that in testing you can easily pass in fake implementations that don't actually use the database, etc.
With Guice, you would bind the interfaces to concrete classes in a Module or Modules. You would then create an Injector using those Modules and get some root object (for example, your application object) from the Injector.
Injector injector = Guice.createInjector(new AbstractModule() {
#Override protected void configure() {
bind(MyDatabaseLayer.class).to(MyDatabaseLayerImplementation.class);
// etc.
});
MyApplicationLayer applicationLayer = injector.getInstance(MyApplicationLayer.class);
In MyApplicationLayer, you'd inject the business logic:
#Inject
public MyApplicationLayer(MyBusinessLogic logic) {
this.logic = logic;
}
This is of course a very simple example and there are much more complex things you can do. In a web application, for example, you can use constructor injection on servlets using Guice Servlet rather than getting an object directly out of the Injector after creating it.
The part you are missing with inversion-of-control is that the application layer does not call the constructor directly.. It uses a factory (the IoC container) to populate the constructor parameter.
Whatever tool you use, guice / spring / picocontainer / singleton-factories, your application code should look something like:
#Controller
class MyController {
#Resource // Some container knows about this annotation and wires you in
MyBusinessLogic myBusinessLogic;
#RequestMethod("/foo/bar.*")
public MyWebResponse doService(Response resp, long id, String val) {
boolean worked = myBusinessLogic.manipulatevalue(id, val);
return new MyWebResponse(worked);
}
}
Note, the myBusinessLogic could be registered in several ways - java's #Resource, MyBusinessLogicFactory.getMyBusinessLogic(), guice.get(MyBusinessLogic.class), etc.
A poor-mans solution would be:
package foo;
class MyBusinessLogicFactory {
static volatile MyBusinessLogic instance; // package-scoped so unit tests can override
public static MyBusinessLogic getInstance() {
if (instance == null) {
synchronized(MyBusinessLogicFactory.class) {
instance = new MyBusinessLogic(MyDatabaseLayerFactory.getInstance());
}
}
return instance;
}
}
// repeat with MyDatabaseLayerFactory
Note the above singleton model is highly discouraged, since it has no scope. You COULD wrap the above inside a context - soething like
class Context {
Map<Class,Object> class2Instance = new ConcurrentHashMap<>();
public <T> T getInstance(Class<T> clazz) {
Object o = class2Instance.get(clazz);
if (o == null) {
synchronized(this) {
o = class2Instance.get(clazz);
if (o != null) return (T)o;
o = transitivelyLoadInstance(clazz); // details not shown
for (Class c : loadClassTree(clazz)) { // details not shown
class2Instance.put(c, o);
}
}
}
return (T)o;
}
...
}
But at that point, picocontainer, guice and spring can solve the complexities of the above SOOO much better.
Further, things like spring that honor the java 6 annotations mean you can do things other than constructor injection, which is VERY useful if you have multiple configuration items of the same base data-type (e.g. strings).

Guice: is it possible to inject modules?

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.

Categories

Resources