MyBatis multiple data sources using single mapper - java

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

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 use the Multibinder within Guice to construct dynamic sets based on application configuration?

I have an application which relies on Properties configuration to determine whether to mix in various components or not.
For example, the configuration has boolean flags like "componentX.enabled" etc which determine whether these components should be active or not.
Currently I am using these flags in my provider methods like so:
#Provides
#Singleton
#Nullable
public ComponentX provideComponentX(Properties props) {
if (props.isComponentXEnabled()) {
return new ComponentX();
} else {
return null;
}
}
#Provides
#Singleton
public Set<Component> provideComponentSet(
#Nullable ComponentX compX,
ComponentY compY,
ComponentZ compZ
) {
Set<Component> comps = new HashSet<>();
if (compX != null) {
comps.add(compX);
}
comps.add(compY);
comps.add(compZ);
return comps;
}
This approach seems a little clunky (it relies on possible injecting null)- but is there a better way?
The only other way I can think of doing it is by using a parent injector to obtain the application Properties into my module, and then using the set Multibinder.
Then use the create child injector with the new module to complete the bootstrap process.
public class Module extends AbstractModule {
Properties props;
public Module(Properties props) {
this.props = props;
}
public void configure() {
Multibinder<Component> compBinder = Multibinder.newSetBinder(binder(), Component.class);
if (props.isComponentXEnabled()) {
compBinder.addBinding().to(ComponentX.class);
}
compBinder.addBinding().to(ComponentY.class);
compBinder.addBinding().to(ComponentZ.class);
}
}
This also seems a little clunky because it requires the use of a child injector etc.
Again, is there a better way?
Maybe I could use Netflix's Governator (https://github.com/Netflix/governator/wiki/Configuration-Mapping) to inject Configuration values into my module (not sure if that is possible or not)?
How do other people approach this problem?
The applications I've been working with recently have a properties file (or other configuration) that is used to decide which parts of the application are relevant. Our typical approach is parse those properties immediately (just to a Properties object) and construct the application module(s) from that, and they will then conditionally include other modules based on the values specified.
In a couple of places, this has grown into an "init parameters" set, with an enumeration of possible parameters:
enum InitParam {
PricesQueue("prices.queue")
}
Each enum instance is related to a property key and there is a method to get a basic string value for each parameter from Properties:
boolean presentIn(Properties props) { return props.containsKey(propertyKey); }
String valueIn(Properties props) { return props.getProperty(propertyKey); }
So this can be used like so:
public AppModule extends AbstractModule {
private final Properties config;
protected void configure() {
if (InitParam.PricesQueue.presentIn(config)) {
install(new PricesQueueConsumerModule(config));
}
}
}
Additionally, there is a module to bind all the values in the config properties to String, Optional<String> etc, allowing:
#Inject
public PricesQueueConsumer(#FromInitParam(InitParam.PricesQueue) String queueName) {
}
This will trap the queue consumer being referenced when the configuration isn't available (the module won't bind a string if the value isn't present in the config file) while still allowing the behaviour for when the value isn't present to be deferred to later (by injecting Optional<String> instead)
So this is somewhat similar to your second approach, except that I'd not considered the using-Guice-to-inject-Guice-modules approach, which seems a bit convoluted. Although probably it's essentially the same. Maybe rather than a parent/child injector you could simply create a "bootstrapping" injector to build your top-level application module, and then use that to build a completely separate injector?

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

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