I am currently trying to add the entries of a map consisting of Map<? extends CustomModule, CustomModule> (from an additional, custom module system) as bindings within a guice module.
My code so far looks like this:
manager.getRegistry().forEach(new BiConsumer<Class<? extends CustomModule>, ModuleRegistry.Entry>() {
#Override
public void accept(Class<? extends CustomModule> moduleClass, ModuleRegistry.Entry entry) {
bind(moduleClass).to(entry.getModule()); // getModule() returns the instance which implements moduleClass
}
});
Guice sadly needs the direct class instead of a wildcard ("? extends").
Since I already got the "bindings", is there another way to add them to the injector?
Thanks in advance!
So after trying various other possible ways, I finally found one that works.
Since the original problem was that Guice required a "capture" of something (in this case "capture of ? extends Module instance", basically means something that is an instance of something that is a module) and failed, I had to cast my already known module class to its raw type, like this:
final Class moduleClass = (Class) aClass;
final Binding binding = injector.getExistingBinding(Key.get(moduleClass));
if (binding == null) {
bind(moduleClass).toInstance(entry.getModule());
}
I also had to add a null check in my case, but it also includes the way how to cast your unknown class to guice's "Key" helper.
Related
Can I do it with reflection or something like that?
I have been searching for a while and there seems to be different approaches, here is a summary:
reflections library is pretty popular if u don't mind adding the dependency. It would look like this:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader (as per erickson answer) and it would look like this:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
Note that for this to work you need to define Petas a ServiceProviderInterface (SPI) and declare its implementations. you do that by creating a file in resources/META-INF/services with the name examples.reflections.Pet and declare all implementations of Pet in it
examples.reflections.Dog
examples.reflections.Cat
package-level annotation. here is an example:
Package[] packages = Package.getPackages();
for (Package p : packages) {
MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
if (annotation != null) {
Class<?>[] implementations = annotation.implementationsOfPet();
for (Class<?> impl : implementations) {
System.out.println(impl.getSimpleName());
}
}
}
and the annotation definition:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PACKAGE)
public #interface MyPackageAnnotation {
Class<?>[] implementationsOfPet() default {};
}
and you must declare the package-level annotation in a file named package-info.java inside that package. here are sample contents:
#MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;
Note that only packages that are known to the ClassLoader at that time will be loaded by a call to Package.getPackages().
In addition, there are other approaches based on URLClassLoader that will always be limited to classes that have been already loaded, Unless you do a directory-based search.
What erickson said, but if you still want to do it then take a look at Reflections. From their page:
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
In general, it's expensive to do this. To use reflection, the class has to be loaded. If you want to load every class available on the classpath, that will take time and memory, and isn't recommended.
If you want to avoid this, you'd need to implement your own class file parser that operated more efficiently, instead of reflection. A byte code engineering library may help with this approach.
The Service Provider mechanism is the conventional means to enumerate implementations of a pluggable service, and has become more established with the introduction of Project Jigsaw (modules) in Java 9. Use the ServiceLoader in Java 6, or implement your own in earlier versions. I provided an example in another answer.
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired
private List<ITask> tasks;
}
The most robust mechanism for listing all classes that implement a given interface is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)
try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
.enableClassInfo().scan()) {
for (ClassInfo ci : scanResult.getClassesImplementing("x.y.z.SomeInterface")) {
foundImplementingClass(ci); // Do something with the ClassInfo object
}
}
With ClassGraph it's pretty simple:
Groovy code to find implementations of my.package.MyInterface:
#Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().withCloseable { scanResult ->
scanResult.getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.name
}
What erikson said is best. Here's a related question and answer thread - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
The Apache BCEL library allows you to read classes without loading them. I believe it will be faster because you should be able to skip the verification step. The other problem with loading all classes using the classloader is that you will suffer a huge memory impact as well as inadvertently run any static code blocks which you probably do not want to do.
The Apache BCEL library link - http://jakarta.apache.org/bcel/
Yes, the first step is to identify "all" the classes that you cared about. If you already have this information, you can enumerate through each of them and use instanceof to validate the relationship. A related article is here: https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html
Also, if you are writing an IDE plugin (where what you are trying to do is relatively common), then the IDE typically offers you more efficient ways to access the class hierarchy of the current state of the user code.
I ran into the same issue. My solution was to use reflection to examine all of the methods in an ObjectFactory class, eliminating those that were not createXXX() methods returning an instance of one of my bound POJOs. Each class so discovered is added to a Class[] array, which was then passed to the JAXBContext instantiation call. This performs well, needing only to load the ObjectFactory class, which was about to be needed anyway. I only need to maintain the ObjectFactory class, a task either performed by hand (in my case, because I started with POJOs and used schemagen), or can be generated as needed by xjc. Either way, it is performant, simple, and effective.
A new version of #kaybee99's answer, but now returning what the user asks: the implementations...
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
default ITask getImplementation() {
return this;
}
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired(required = false)
private List<ITask> tasks;
if ( tasks != null)
for (ITask<?> taskImpl: tasks) {
taskImpl.doStuff();
}
}
I'm using generics to get my code reusable and to utilize dependency injection.
I have two Interfaces: DataParserImplementation and ObjectImplementation. I have classes that implement each: SalesRepbyId implements DataParserImpl (it parses the data into objects and puts those objects into collections). SalesRep implements Objectimpl (It is the object for a specific dataset).
I'm trying to get it so that I can select which kind of Objectimpl I use in my SalesRepbyId class so I can remove the coupling.
I know there is something called reflection that I've been told is the method I need to use. I also have heard about a "Factory Pattern" and a "Properties file" that allows me to do what I want to do. A lot of this is very confusing so please explain it like I'm five.
Here is the code with where it stops working:
EDIT: Revisions based on comments: I want to specify the type of DataObject (D) my class uses by passing it through the constructor via a common interface and using generic types. When I try and use it instead of a concrete implementing class, I get the error. I can't find anything about this error.
public class SalesRepbyId<D extends ObjectImplementation> implements DataParserImplementation<Map<String,D>> {
private FileParserImplementation<ArrayList<String[]>> FileParser;
private D dataObject;
public SalesRepbyId(FileParserImplementation<ArrayList<String[]>> FileParser,D d){
this.FileParser = FileParser;
this.dataObject = d;
}
#Override
public Map<String, D> Parse() {
try{
//reads the file and returns an array of string arrays
ArrayList<String[]> Salesrep_contactlist = FileParser.ReadFile;
//here it still says "Unknown Class." that's the problem
Map<String, dataObject> SalesrepByIdMap = new HashMap<>();
//I want to be able to put in any class that implements
//dataObject into this class and have it run the same way.
Summary of what I did
I Implemented the Factory Design pattern and created a properties file which allowed me to reflect in the class I wanted instead of trying to use a generic DataObject (or D) type.
Details of Solution
Reflecting the class using the properties file "config.properties" and then casting it to type Objectimplementation allowed me to use any class that implemented that interface (and was implemented in the Factory and set in the properties file). I then refactored all instances of D to type ObjectImplementation since the parent interface is the layer of abstraction needed here rather than a generic concrete class.
Why it didn't work the way I tried it in the question
the reason the generic D type doesn't work with reflection is because reflection uses a concrete classtype determined at runtime and the generic D type is specified before runtime. Thus I was trying to reflect in the classtype and its methods/instances without properly using reflection and the code was telling me that the classtype was unknown at the time I needed it.
Code example to compare to the Question code
Example of the working code:
public class SalesRepbyId implements
DataParserImplementation<Map<String,ObjectImplementation>> {
private FileParserImplementation<ArrayList<String[]>> FileParser;
//the Factory class that creates instances of the reflected class I wanted
private ObjectFactory Factory = new ObjectFactory();
public Map<String, ObjectImplementation> Parse() {
//the proeprties object which then loads properties from a file and reflects the classtype I want
Properties prop = new Properties();
//loading in the classtype and casting it to the subclass of ObjectImplementation that it actually is
prop.load(SalesRepbyId.class.getResourceAsStream("config.properties"));
Class<? extends ObjectImplementation> Classtouse = Class.forName(prop.getProperty("ObjectImplementation")).asSubclass(ObjectImplementation.class);
//construct instances of 'Classtouse' and parse the data into these dynamically typed objects
//return the map that holds these objects
}
I have some classes which require a specific object to be injected (lets name it ToInject).
The problem is that I cannot provide ToInject from separate modules:
#Module(injects={OneActivity.class})
public class OneActivityModule {
#Provides
public ToInject provideToInject(){
return new ToInject(...)
}
}
#Module(injects={TwoActivity.class})
public class TwoActivityModule {
#Provides
public ToInject provideToInject(){
return new ToInject(...)
}
}
I get this exception when creating the ObjectGraph:
Caused by: java.lang.IllegalArgumentException: TwoActivityModule: Duplicate:
com.example.test.OneActivityModule$$ModuleAdapter$ProvideToInjectProvidesAdapter[key=com.example.test.ToInject method=com.example.test.OneActivityModule.provideToInject()]
com.example.test.TwoActivityModule$$ModuleAdapter$ProvideToInjectProvidesAdapter[key=com.example.test.ToInject method=com.example.test.TwoActivityModule.provideToInject()]
at dagger.ObjectGraph$DaggerObjectGraph.makeGraph(ObjectGraph.java:187)
at dagger.ObjectGraph$DaggerObjectGraph.access$000(ObjectGraph.java:138)
at dagger.ObjectGraph.create(ObjectGraph.java:129)
I know that I could move ToInject providers to a single module, and use qualifiers to make then unique, but why can't I do it this way? injects is specified for each Module, ain't that makes those providers unique also?
Any suggestions?
UPDATE:
I thought about it, and the real problem is that I want to configure the ToInject object based on which Activity gets it. ToInject is actiually an abstract class (and the code snippet above uses a "not abstract" class just for the example).
My conclusion is that I should use only one provider for ToInject, so I can change the implementation with the change of a single line of code. But I would still need to configure the ToInject object based on which Activity get it.
So the main question became that whether this is possible with Dagger, or do I have to pass the configuration to every Activity, and manually set it?
The configuration in this case is an ID (String), and the object to configure (ToInject in this example) is a fragment that displays an advert banner. I want to separate it from the Activity as much as possible, so I can reuse it in other projects.
I found the sufficient solution.
This is a library responsible for providing the implementation of the abstract ToInject.
#Module(library=true)
public class ProviderModule {
#Provides
public ToInject provideToInject(){
return new ToInjectConcrete1();
}
}
And I can create Activity specific modules the way below. As you can see this ToInject provider method has a ToInject argument, that is actually provided by the library above. After I got it, I can do my further configuration that is specific to my Activity.
#Module(injects = OneActivity.class, includes = ProviderModule.class)
public class OneActivityModule {
#Provides
#Named("one")
public ToInject provideToInject(ToInject toInject) {
toInject.text = "overridden by one";
return toInject;
}
}
The key was the usage of qualifiers (in this case the #Named qualifier).
Note:
The origin of my problem was that I assumed provider methods in separate modules (with injects defined) are unique. Now I know that injects is for compile time verification, and has nothing to do with the uniquness of the providers. Providers with same return type can be made unique with qualifiers (for example #Named) just as how I did in this solution.
I'm trying to use Picocontainer Web (picocontainer-web-core-2.5.1.jar).
I have configured everything and I checked out that everything works just fine, until trying to retrieve anything from container... :p
I though I should use static method getRequestComponentForThread(Class type) from PicoServletContainerFilter class, which looks like this:
public static Object getRequestComponentForThread(Class type) {
MutablePicoContainer requestContainer = ServletFilter.currentRequestContainer.get();
MutablePicoContainer container = new DefaultPicoContainer(requestContainer);
container.addComponent(type);
return container.getComponent(type);
}
But as you can see, in that method, new instance of DefaultPicoContainer is created and type which I'm trying to retrieve is being registered.
if type is a Class - new instance is created and returned, instead of cached one from parent container...
if type is a Interface - runtime exception ("'ExampleInterface' is not instantiable") is being thrown, at 3rd line (addComponent).
And my question is: How to use this library? I was pretty sure that I understand it, but implementation of this one method blows my mind...
Actually you should not use getComponent unless there's a special case.
App/Session/Request containers are created for you when you add pico context listener to the web.xml.
Just configure components for each scope and picocontainer will inject stuff automatically and instantiate components when needed. Also use Startable lifecycle interface.
I figured out one acceptable solution - writing own version of org.picocontainer.web.PicoServletContainerFilter.ServletFilter - and adding one method:
public class MyComponentContainer extends PicoServletContainerFilter {
/*
code from original class PicoServletContainerFilter.ServletFilter
[...]
*/
public static <T> T getComponent(Class<T> clazz) {
return (T) currentRequestContainer.get().getComponent(clazz);
}
}
I'm not sure if it's the best to do, but it work's fine for me. However, if you know better solution I'd be grateful for information :)
I'm reviewing Guice. Let's say I've got the following setup:
public interface IsEmailer {...}
public interface IsSpellChecker {...}
public class Emailer implements IsEmailer {
#Inject
public class Emailer(final IsSpellChecker spellChecker)....
}
public class FrenchSpellChecker implements IsSpellChecker {....}
public class EnglishSpellChecker implements IsSpellChecker {....}
#BindingAnnotation public #interface English {}
#BindingAnnotation public #interface French {}
Then in my module I've bound the interfaces to their respective implementations, and annotated the spell checkers with the respective binding-annotation.
Now, let's say based on a runtime variable I need to construct an emailer that either uses the English or the French spell checker.
I thought of using a named providers in my module:
#Provides
#English
IsEmailer provideEnglishEmailer() {
return new Emailer(new EnglishSpellChecker());
}
#Provides
#French
IsEmailer provideFrenchEmailer() {
return new Emailer(new FrenchSpellChecker());
}
This works like this:
IsEmailer emailer = myModule.getInstance(Key.get(IsEmailer.class,
French.class));
Is this the cleanest way to do something like this? After all, I'm forced to construct the object by hand (in the providers).
Thanks
First some notes:
Generally you want to avoid using getInstance as much as possible, except for your "root" element (e.g. YourApplication). Within anything that Guice provides, your best bet is to ask for an injection of Provider<IsEmailer>, or perhaps #English Provider<IsEmailer> and #French Provider<IsEmailer>. Guice will not actually create the elements until you call get on the Provider, so the overhead of creating the Provider is very very light.
You don't have to bind to a provider to get a provider. Guice will resolve any binding of X, Provider<X>, or #Provides X to any injection of X or Provider<X> automatically and transparently.
Provider implementations can take injected parameters, as can #Provides methods.
If you want to bind a lot of things to #English or #French, you may also investigate private modules, since this sounds like the "robot legs" problem to me.
The easiest way is simply to go with the first bullet and inject a Provider of each, especially if you're only doing this once.
You can also bind it in a Module, if your runtime variable is accessible via Guice. Put this in your module along with the #Provides annotations above. (As noted, you may want to rewrite them to accept an EnglishSpellChecker and FrenchSpellChecker as parameters respectively, to enable the spell checkers to inject their own dependencies.)
#Provides IsEmailer provideEmailer(Settings settings,
#English Provider<IsEmailer> englishEmailer,
#French Provider<IsEmailer> frenchEmailer) {
if (settings.isEnglish()) {
return englishEmailer.get();
} else {
return frenchEmailer.get();
}
}
You could use a MapBinder. That would allow you to inject a Map<Language, IsSpellChecker>, and then retrieve the appropriate spell checker at runtime.