106

Can I do it with reflection or something like that?

user2427
  • 7,842
  • 19
  • 61
  • 71

11 Answers11

74

I have been searching for a while and there seems to be different approaches, here is a summary:

  1. 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);
    
  2. 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
    
  3. 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.

lakshayg
  • 2,053
  • 2
  • 20
  • 34
Ahmad Abdelghany
  • 11,983
  • 5
  • 41
  • 36
  • Which of the three approaches is more efficient and quickest? – carlspring May 29 '16 at 11:34
  • @carlspring I can not make an absolute statement about their relative efficiency but the first alternative (reflections library) worked pretty well for me. – Ahmad Abdelghany May 30 '16 at 19:45
  • How does DriverManager of JDBC work? Isn't it doing the similar thing (searching all implementations of Driver interface in classpath)? – Alex Semeniuk Feb 16 '19 at 22:00
  • 1
    @AlexSemeniuk I think they now support the Service Loader/Provider mechanism (approach #2 above) according to their docs "The DriverManager methods getConnection and getDrivers have been enhanced to support the Java Standard Edition Service Provider mechanism." See https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html – Ahmad Abdelghany Feb 18 '19 at 15:13
  • 2
    It’s worth noting that the service provider mechanism has been integrated into the module system with Java 9, which makes it even more convenient than package level annotations, i.e. you don’t need to create your own annotation type, can declare the implementations in the module-info you’ll create anyway when writing modular software and get compile-time feedback regarding the validity of the implementation. – Holger Mar 04 '20 at 10:52
  • As of Oct 2021, the *Reflections Library* is no longer maintained. [Classgraph](https://github.com/classgraph/classgraph) is a viable alternative. For this use case, see [this example](https://github.com/classgraph/classgraph/wiki/Code-examples#find-the-names-of-classes-that-implement-interface-comxyzwidget) in wiki docs, and/or Luke Hutchison's [answer](https://stackoverflow.com/a/51625212/1348743). – Javaru Jun 21 '23 at 21:16
29

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.

erickson
  • 265,237
  • 58
  • 395
  • 493
  • 6
    Unfortunately, the Service Provider mechanism requires you to list the classes that might be in the list of interest in a separate file which is often unfeasible. – averasko May 31 '15 at 15:41
  • 5
    It's feasible to write source code implementing an interface, compile it, and deploy it, but infeasible to include a text file with the implementation's FQN? That's seldom, if ever, the case. Hardly "often." – erickson Mar 12 '17 at 16:45
  • How does DriverManager of JDBC work? Isn't it doing the similar thing (searching all implementations of Driver interface in classpath)? – Alex Semeniuk Feb 16 '19 at 22:01
  • 1
    @AlexSemeniuk No. it uses the Service Loader mechanism I describe above; A JDBC 4.0+ driver must list its name in `META-INF/services/java.sql.Driver` – erickson Feb 16 '19 at 22:06
  • Making a developer edit an unrelated file is a non-starter. It has to work as good as .NET/CLR reflection: where we can find all implementations and it just works. – Ian Boyd Jul 22 '22 at 04:19
28

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
Aldo
  • 536
  • 5
  • 23
Peter Severin
  • 2,455
  • 21
  • 13
  • 14
    more specific: `new Reflections("my.package").getSubTypesOf(MyInterface.class)` – zapp Mar 16 '13 at 13:12
  • @zapp What do you pass to `Reflections()` when you a) don't know the name of any package, and b) need it to scan **all** packages? (i don't know what packages the developers may have chosen to place any and all implementations in). – Ian Boyd Jul 22 '22 at 04:50
20

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;
}
NaN
  • 8,596
  • 20
  • 79
  • 153
kaybee99
  • 4,566
  • 2
  • 32
  • 42
10

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
    }
}
Luke Hutchison
  • 8,186
  • 2
  • 45
  • 40
6

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
}
Luke Hutchison
  • 8,186
  • 2
  • 45
  • 40
verglor
  • 616
  • 7
  • 21
  • You need to call `scan().withCloseable { ... }` in Groovy, or use try-with-resources in Java: https://github.com/classgraph/classgraph/wiki/API:-ScanResult#scanresult-lifecycle Also, the last part should be `.name`, not `.className`, since `.getName()` is the right method to get the name of a class from a `ClassInfo` object. – Luke Hutchison Oct 05 '19 at 11:03
4

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

Gorjan Mishevski
  • 182
  • 3
  • 10
Zhichao
  • 599
  • 5
  • 14
4

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/

1

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.

Uri
  • 88,451
  • 51
  • 221
  • 321
1

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.

NDK
  • 41
  • 5
1

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();
    }   
}
NaN
  • 8,596
  • 20
  • 79
  • 153