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
Related
I have an application class "Application", one abstract class "AbstractClass" extended by "Impl1" and "Impl2".
The application class gets the impl1 or impl2 to perform some task based on the input it receives.
Currently I am injecting both the classes into the application class as shown below.
Then based on input, I either ask impl1 OR impl2 to perform the task.
public class Application {
private static final Data data1 = DATA_CONFIG.data_1;
private final AbstractClass impl1;
private final AbstractClass impl2;
#Inject
Application(final AbstractClass impl1, final AbstractClass impl2){
this.impl1 = impl1;
this.impl2 = impl2;
}
public void mainTask(final Data data){
if(data == data1){
impl1.performTask();
}else{
impl2.performTask();
}
}
}
But, is there any way I could use assisted inject or a similar concept to inject only the dependency required, so for example input is data1, I only inject impl1 and not impl2.??
So, what you want is to select injected object depending to some context of injection point - value of Data object in particular. I didn't do such things and can't guarantee success, but you can try custom injections.
Also you can do something like factory. But IMHO, this approach is not much better than original, cause it will just move selection between impl1 and impl2 to a factory class you have to create first.
Sketch:
#Inject
Application(IAbstractClassFactory factory){
this.factory = factory
}
void mainTask(final Data data){
impl = factory.create(data)
}
I am working on a REST API where I have an interface that defines a list of methods which are implemented by 4 different classes, with the possibility of adding many more in the future.
When I receive an HTTP request from the client there is some information included in the URL which will determine which implementation needs to be used.
Within my controller, I would like to have the end-point method contain a switch statement that checks the URL path variable and then uses the appropriate implementation.
I know that I can define and inject the concrete implementations into the controller and then insert which one I would like to use in each particular case in the switch statement, but this doesn't seem very elegant or scalable for 2 reasons:
I now have to instantiate all of the services, even though I only need to use one.
The code seems like it could be much leaner since I am literally calling the same method that is defined in the interface with the same parameters and while in the example it is not really an issue, but in the case that the list of implementations grows ... so does the number of cases and redundant code.
Is there a better solution to solve this type of situation? I am using SpringBoot 2 and JDK 10, ideally, I'd like to implement the most modern solution.
My Current Approach
#RequestMapping(Requests.MY_BASE_API_URL)
public class MyController {
//== FIELDS ==
private final ConcreteServiceImpl1 concreteService1;
private final ConcreteServiceImpl2 concreteService2;
private final ConcreteServiceImpl3 concreteService3;
//== CONSTRUCTORS ==
#Autowired
public MyController(ConcreteServiceImpl1 concreteService1, ConcreteServiceImpl2 concreteService2,
ConcreteServiceImpl3 concreteService3){
this.concreteService1 = concreteService1;
this.concreteService2 = concreteService2;
this.concreteService3 = concreteService3;
}
//== REQUEST MAPPINGS ==
#GetMapping(Requests.SPECIFIC_REQUEST)
public ResponseEntity<?> handleSpecificRequest(#PathVariable String source,
#RequestParam String start,
#RequestParam String end){
source = source.toLowerCase();
if(MyConstants.SOURCES.contains(source)){
switch(source){
case("value1"):
concreteService1.doSomething(start, end);
break;
case("value2"):
concreteService2.doSomething(start, end);
break;
case("value3"):
concreteService3.doSomething(start, end);
break;
}
}else{
//An invalid source path variable was recieved
}
//Return something after additional processing
return null;
}
}
In Spring you can get all implementations of an interface (say T) by injecting a List<T> or a Map<String, T> field. In the second case the names of the beans will become the keys of the map. You could consider this if there are a lot of possible implementations or if they change often. Thanks to it you could add or remove an implementation without changing the controller.
Both injecting a List or a Map have some benefits and drawbacks in this case. If you inject a List you would probably need to add some method to map the name and the implementation. Something like :
interface MyInterface() {
(...)
String name()
}
This way you could transform it to a Map<String, MyInterface>, for example using Streams API. While this would be more explicit, it would polute your interface a bit (why should it be aware that there are multiple implementations?).
When using the Map you should probably name the beans explicitly or even introduce an annotation to follow the principle of least astonishment. If you are naming the beans by using the class name or the method name of the configuration class you could break the app by renaming those (and in effect changing the url), which is usually a safe operation to do.
A simplistic implementation in Spring Boot could look like this:
#SpringBootApplication
public class DynamicDependencyInjectionForMultipleImplementationsApplication {
public static void main(String[] args) {
SpringApplication.run(DynamicDependencyInjectionForMultipleImplementationsApplication.class, args);
}
interface MyInterface {
Object getStuff();
}
class Implementation1 implements MyInterface {
#Override public Object getStuff() {
return "foo";
}
}
class Implementation2 implements MyInterface {
#Override public Object getStuff() {
return "bar";
}
}
#Configuration
class Config {
#Bean("getFoo")
Implementation1 implementation1() {
return new Implementation1();
}
#Bean("getBar")
Implementation2 implementation2() {
return new Implementation2();
}
}
#RestController
class Controller {
private final Map<String, MyInterface> implementations;
Controller(Map<String, MyInterface> implementations) {
this.implementations = implementations;
}
#GetMapping("/run/{beanName}")
Object runSelectedImplementation(#PathVariable String beanName) {
return Optional.ofNullable(implementations.get(beanName))
.orElseThrow(UnknownImplementation::new)
.getStuff();
}
#ResponseStatus(BAD_REQUEST)
class UnknownImplementation extends RuntimeException {
}
}
}
It passes the following tests:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class DynamicDependencyInjectionForMultipleImplementationsApplicationTests {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldCallImplementation1() throws Exception {
mockMvc.perform(get("/run/getFoo"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("foo")));
}
#Test
public void shouldCallImplementation2() throws Exception {
mockMvc.perform(get("/run/getBar"))
.andExpect(status().isOk())
.andExpect(content().string(containsString("bar")));
}
#Test
public void shouldRejectUnknownImplementations() throws Exception {
mockMvc.perform(get("/run/getSomethingElse"))
.andExpect(status().isBadRequest());
}
}
Regarding two of your doubts :
1. Instantiating the service object should not be an issue as this is one time job and controller gonna need them to serve all type of request.
2. You can use the exact Path mapping to get rid of switch case. For e.g. :
#GetMapping("/specificRequest/value1")
#GetMapping("/specificRequest/value2")
#GetMapping("/specificRequest/value3")
All of the above mapping will be on separate method which would deal with specific source value and invoke respective service method.
Hope this will help to make code more cleaner and elegant.
There is one more option of separating this on service layer and having only one endpoint to serve all types of source but as you said there is different implementation for each source value then it says that source is nothing but a resource for your application and having separate URI/separate method makes the perfect sense here. Few advantages that I see here with this are :
Makes it easy to write the test cases.
Scaling the same without impacting any other source/service.
Your code dealing the each source as separate entity from other sources.
The above approach should be fine when you have limited source values. If you have no control over source value then we need further redesign here by making source value differentiate by one more value like sourceType etc. and then having separate controller for each group type of source.
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);
}
}
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
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);
}
}