I have been looking over the net for an explanation about the injector heirarchy and how/when to use createChildInjector(), but I cannot find a clear and concise explanation.
Here is my use case:
I have a base application module which I use to inject certain context items. This module should be included in every injector instance.
I have a search module which searches a database
I have a search module which searches ElasticSearch. Some of the bindings in this class should override the bindings that are provided in the database search module.
For example, say the database search module contains:
bind(PlaceSearch.class).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(HibernatePersonSearch.class);
And the ElasticSearch module contains:
bind(PersonSearch.class).to(PersonElasticSearch.class);
Is there a way to create an injector that includes the PlaceSearch binding from the database search module and the PersonSearch binding from the ElasticSearch module without creating a separate module that contains
bind(PlaceSearch.class).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(PersonElasticSearch.class);
? Is this a case for Modules.override()? A case for createChildInjector? Thanks ahead of time!
The Modules.override() is not working in Stage.PRODUCTION. You should use PrivateModule where the binding is valid/visible only inside private module, so you can bind different implementation classes to the same interface. Then you can install the Private module to the parent Module, but you have to explicitly expose() all binding you want to make visible for other modules.
Guice - Private Modules
Lets say:
DatabaseSearchModule.java (extends PrivateModule)
bind(PlaceSearch.class).annotatedWith(Names.named("dbSearch")).to(HibernatePlaceSearch.class);
bind(PersonSearch.class).to(HibernatePersonSearch.class);
expose(PlaceSearch.class).annotatedWith(Names.named("dbSearch"));
EleasticSearchModule.java (extends PrivateModule)
bind(PersonSearch.class).annotatedWith(Names.named("elastic")).to(PersonElasticSearch.class);
expose(PersonSearch.class).annotatedWith(Names.named("elastic"));
Well then you can install it in some Parent abstract or servlet module
MainModule.java
install(new DatabaseSearchModule());
install(new EleasticSearchModule());
bind(OtherClass.class);
OtherClass.java
#Inject #Named("elastic")
private PlaceSearch elasticSearch;
#Inject #Named("dbSearch")
private PlaceSearch dbSearch;
You can use Named annotation or you can create very elegant own binding Annotation.
This is a perfect case for Modules.override().
Most applications shouldn't use child injectors. They add a lot of configuration complexity and have some surprising behavior for corner cases.
Related
I have a piece of code with a couple of Modules from different libraries:
install(new AModule())
install(new BModule())
I am getting an error:-
A binding to com.path.to.Class was already configured at com.AModule.provideClass.
at com.BModule...
I need both the modules but they cannot be used together because both have bindings to a particular class. I do not own the 2 libraries so cannot make changes there. How can I solve this issue?
Use Modules.override
If you require the binding present in AModule, use:
install(Modules.override(new BModule()).with(new AModule()));
On the other hand, if you require the binding present in BModule, use:
install(Modules.override(new AModule()).with(new BModule()));
I have three maven projects:
demo-api: Contains POJOs for function APIs i.e. OutputPojo.class, InputPojo.class
demo-packaged-function: Defines a single function public OutputPojo apply(InputPojo) {...} that depends on the 'demo-api' project.
demo-deployer: Uses spring-cloud-function-deployer to run the packaged function, also depends on the 'demo-api' project.
If I use simple types for the function signature (i.e. refactor to String apply(String input) {...} then everything works fine. However, with the setup described above I get the following exception:
Exception in thread "main" java.lang.ClassCastException: class org.example.function.api.InputPojo cannot be cast to class org.example.function.api.InputPojo (org.example.function.api.InputPojo is in unnamed module of loader 'app'; org.example.function.api.InputPojo is in unnamed module of loader org.springframework.cloud.function.deployer.FunctionArchiveDeployer$1 #7fedfe27)
Which makes sense becaues the class InputPojo is loaded by both class loaders. If I don't package the function as a fat jar, i get ClassNotFoundException when trying to deploy the jar, and I can't remove the dependency on demo-api from the deployer project as otherwise I cannot use the POJO classes when calling the function. How is this meant to work without simple argument types for the functions?
The documentation doesn't cover this, and while there are examples of packaged functions using POJOs, i cannot find any examples of them actually being called by the deployer - other than one is the unit tests which demos type conversion and converts the POJO to Message.
I would like to use service ServiceLoader between diferrent modules in a maven Project. I have a parent module called iMage. In the parent module there is a module with a name jmjrst.main and it has a public abstract class called JmjrstPlugin.
Then there is another module called prizm-plugin with the following class:
public class HelloWorldPlugin extends JmjrstPlugin{ ... }
I added jmjrst.main as a dependency to prizm-plugin and vica-versa as well.
In order to use ServiceLoader I wanted to use META-INF/services generator.
I added the following line to the pom.xml of prizm-plugin:
<dependency>
<groupId>org.kohsuke.metainf-services</groupId>
<artifactId>metainf-services</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
And the class HelloWorldPlugin starts like that:
#MetaInfServices(JmjrstPlugin.class)
public class HelloWorldPlugin extends JmjrstPlugin{ ... }
On the website on META-INF/services generator goes: "When you use javac in JavaSE6, META-INF/services/* files are generated automatically. No additional compiler switches are necessary. This library handles incremental compilation correctly, too."
At my case nothing is generated. Can somebody help me with that?
From the code snippet of your class HelloWorldPlugin it is not clear which interface is 'the contract'. And in the link that you gave:
If you have multiple interfaces and/or base type, the library cannot infer the contract type. In such a case, specify the contract type explicitly by giving it to #MetaInfServices ..
So first of all you have to be sure which contract you wish to fulfill and if the parent class(es) implement several then you'll need to explicitly state which one in the #MetaInfServices annotation.
That's the first thing to check I think.
I want to load dynamic library where classes inherit from an interface/abstract class on my core project, so I can load my classes at runtime and use it. How can i do that ?
Example:
Core: ITrigger (interface)
Library: {MyTriggerOne extends ITrigger} {MyTriggerTwo extends ITrigger}
If you want to load a class/library dynamically use Class.forName('class name') method to load.
I had the same requirement and I used the library Reflections.
Very simple code snippet:
public Set<Class<? extends ITrigger>> getITriggerClasses() {
final Reflections reflections = new Reflections("package.where.to.find.implementations");
return reflections.getSubTypesOf(ITrigger.class);
}
Then you can use the method Class::newInstance to create the ITrigger(s).
This is a very simple example, there are several options to initialize the Reflections class (not only with one package name).
Java's SPI(Service Provider Interface) libraries allow you to load classes dynamically based on the interfaces they implement, that can be done with the help of META-INF/services.
You can create a interface like
package com.test.dynamic;
public interface ITrigger {
String getData();
String setData();
}
you can use the ServiceLoader class to load the interface like below code
ServiceLoader<ITrigger> loader = ServiceLoader.load(ITrigger.class);
then you can perform all the operation on it.
If you have some other implementing classes on your classpath, they register themselves in META-INF/services.
you need to create a file in META-INF/services in your classpath with the following properties
The name of the file is the fully qualified class name of the
interface, in this case, it's com.test.dynamic.ITrigger
The file contains a newline-separated list of implementations, so
for the example implementation, it would contain one line:
com.test.dynamic.impl.SomeITriggerImplementation class.
In my grails application I have Java classes (src/java). And I want to have access to my domain classes and use GORM features(like get(), findBy..., save(), delete() and etc.) directly from my Java classes. I know, I can do this by Spring IoC: for example, I can add grails service to my Java class:
public class SimpleJavaClass{
//...
#Autowired
private ExampleService exampleService;
//...
}
And wireup each instance of this class by Spring:
//...
GrailsApplication grailsApplication
//...
def simpleAction(){
def instance = new SimpleJavaClass()
grailsApplication.mainContext.autowireCapableBeanFactory.autowireBean(instance)
}
But may be there is more appropriate way to do same?
Using Grails 2.0, the only current way is to package your domain classes into a binary plugin (see http://grails.org/doc/2.0.x/guide/single.html#binaryPlugins)
You then can depend on this binary plugin and because it is precompiled the Java code will see many of the GORM methods which are wired into the byte code