I am building a program that utilizes a quite big amount of modules (around 150 at the moment). Every module is just a simple class that implements the same interface. All of those modules (classes) are placed in the same package.
The program must create instance of every class from the modules package, and then execute a method from every instance (the method is present in the interface).
The logic of what I want to achieve could look as following:
1. Obtain all classes from the package com.example.modules
2. Create instances of all the gathered classes, and put them in a list (or any other iterable container)
3. Iterate the list, executing method X from every instance (the method is present in the interface)
I would want to kindly ask for suggestions how I can achieve this. I am a Java beginner, therefore any source code and/or links to the docs would be extremely helpful.
Hmm...that just sounds...interesting...what is the use case for such a thing? Why do you have 150 classes implementing the same interface? Are you sure that this wouldn't make sense done some other simpler way? Are the 150 different implementations really 150 different bits of logic?
I have done something similar to this to build a simple container to execute classes packaged in jar files. These are the steps:
Get a list of all classes in the specified package: - get the context ClassLoader
- use the ClassLoader to get a list of resources for the package name (there will only be one resource)
- iterate through the resources (or just work with the first element) and:
- check the protocol associated with the resource URL (jar'ed and non-jar'ed are handled differently)
- for non-jar'ed, get the file directory for the package from the URL
- iterate through all the filenames in the directory looking for files ending with class (all the files should be class files)
- form a fully qualified class name (package name + filename (without the .class suffix))
- get a class object using the class name (use Class.forName())
- add the class object to a list of Class<?>
Iterate through the list of class objects and: - verify that the class implements the needed interface
- create an instance of the class
- call the specific method
Scott Shipp wrote:Hmm...that just sounds...interesting...what is the use case for such a thing? Why do you have 150 classes implementing the same interface? Are you sure that this wouldn't make sense done some other simpler way? Are the 150 different implementations really 150 different bits of logic?
I forgot to mention that there are abstract classes that stand between the "module" classes and the interface. Most of those "module" classes are just configuring the settings used by the abstract class they extend.
In more detail:
Those 150 "module" classes represent websites with which my program must interact.
About 100 of those websites are running on a small set of software (around 10 scripts). For this reason, I have created abstract classes that implement interaction logic with those scripts.
Most of those websites aren't using the scripts in their default config - they often use custom code, plugins, and various configurations on software and server side. For this reason, the script implementations are abstract classes that are extended by the "module" classes - any changes in the default behavior of the script are either configured or implemented in the "module" classes. In example, basic configuration is done by calling the abstract class constructor and/or other configuration related methods. Custom code or server specific modifications are handled by overriding methods (like login method).
This organization allows me to easily handle all of the 150 websites. When one gets updated, I can easily navigate to the class that represents given website and change what is needed. So far this system proved to be working nicely.
Ron, thank you very much for the detailed description of the process, and Rob for the idea with ServiceLoader. Your posts gave me a new idea how I can temporarily handle this situation (due to an incoming deadline). For now, I will store the class names in the database. When the classes are needed, I will simply query the database and create new instances using the class names.
Nevertheless, I will have to implement "scanning" of the classes in the package anyway. It will be needed to implement ofter features that are planned for the next iteration on the beginning of 2016. I will come here back with details how I implemented it. Suggestions of Ron and Rob will be definitely very helpful in implementing that. Thank you again for your responses, I really appreciate that.