Search code examples
javaeclipseclassloader

Java: find classes with certain base type on program startup


I have a Java program (an Eclipse plug-in to be specific), which is using several JAR files (which I can control). One of the core JAR files defines an abstract class called Strategy. When the user starts the program, the program needs to know all sub classes of Strategy, that are on the program ClassPath.

As I described in this StackOverflow question, I tried to use static initializer blocks on the sub classes, so that they auto-register themselves in a registry. This approach is not working since the static initalizers are not executed before I explicitly use the class.

Is there any other way to find all classes with a certain base type that are on the current ClassPath?

I can think of the following solutions:

  • traverse all JARs in a specific directory and check the classes they contain
  • create a file which is loaded on program start-up and read the class names from that

I can implement both of them myself (so I do not ask for any code samples here). I merely want to know if there is another option I am missing. Any in-class solution (like the one I tried with static initializers) would be greatly appreciated.


Solution

  • If you're open to using a third-party library, Reflections seems to be the best fit here. It's a Java runtime metadata analysis library and is like geared to do this. From their website:

    Using Reflections you can query your metadata such as:

    • get all subtypes of some type
    • get all types/constructos/methods/fields annotated with some annotation, optionally with annotation parameters matching
    • get all resources matching matching a regular expression
    • get all methods with specific signature including parameters, parameter annotations and return type

    All you need is to create a configured instance of Reflections in your StrategyRegistrar class as

    Reflections reflections = new Reflections(
                new ConfigurationBuilder()
               .setUrls(ClasspathHelper.forPackage("com.your.app.strategies.pkg"))
               .setScanners(new SubTypesScanner())
           );
    

    And, then simply fire a query like

    Set<Class<? extends Strategy>> strategies =
        reflections.getSubTypesOf(com.your.app.strategies.pkg.Strategy.class);