140

Some time ago, I came across a piece of code, that used some piece of standard Java functionality to locate the classes that implemented a given interface. I know the functions were hidden in some non-logical place, but they could be used for other classes as the package name implied. Back then I did not need it, so I forgot about it, but now I do, and I can't seem to find the functions again. Where can these functions be found?

Edit: I'm not looking for any IDE functions or anything, but rather something that can be executed within the Java application.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Linor
  • 1,850
  • 2
  • 17
  • 17

9 Answers9

67

Awhile ago, I put together a package for doing what you want, and more. (I needed it for a utility I was writing). It uses the ASM library. You can use reflection, but ASM turned out to perform better.

I put my package in an open source library I have on my web site. The library is here: http://software.clapper.org/javautil/. You want to start with the with ClassFinder class.

The utility I wrote it for is an RSS reader that I still use every day, so the code does tend to get exercised. I use ClassFinder to support a plug-in API in the RSS reader; on startup, it looks in a couple directory trees for jars and class files containing classes that implement a certain interface. It's a lot faster than you might expect.

The library is BSD-licensed, so you can safely bundle it with your code. Source is available.

If that's useful to you, help yourself.

Update: If you're using Scala, you might find this library to be more Scala-friendly.

oliverpool
  • 1,624
  • 13
  • 30
Brian Clapper
  • 25,705
  • 7
  • 65
  • 65
  • Brian, does this work with Interface Inheritance as well? In my project I have an interface which acts as a template for all plugins, and then several interfaces extend that one to provide specialized plugin types. Would I be able to load all plugins using the parent type, or would I have to loop through all of the child types to get all of my plugins? – Brendon Dugan Mar 25 '13 at 13:44
  • 2
    It should. If it doesn't, I need to fix it... – Brian Clapper Mar 25 '13 at 13:57
  • 1
    Brian, it is very helpful. Does it support directory parameter so that I can find classes in the lib. – Jacky Jul 05 '13 at 08:40
  • Yes. You add the directory to the finder. It'll also search jars. – Brian Clapper Jul 12 '13 at 02:27
  • @Brian Does the fact you're using ASM mean that the classes do not actually get loaded but only the files them selves get scanned? As loading everything from the classpath to memory in order to scan it would be a huuuge overhead. – kaqqao Jun 15 '16 at 00:13
  • That's precisely why I used ASM. The library uses ASM to do its work by scanning the byte code directly, bypassing both the classloader and reflection. – Brian Clapper Jun 16 '16 at 12:09
  • @BrianClapper on the site for javautil, it says that it's found in the jcenter maven repo, but I can't find it there (though I find a bunch of other org.clapper artifacts). http://jcenter.bintray.com/org/clapper/ – Scott Nov 22 '16 at 18:39
  • I need to update it. Sorry. I tend to use the Scala more these days. – Brian Clapper Nov 29 '16 at 00:42
  • @BrianClapper is there a way to instantiate found class? Because as far as I understand I can found all classes in jar - get its name and then I need to process jar again in order to load classes by found names. – lapots Feb 21 '17 at 21:07
  • No longer available! :( Nor Maven central nor in http://software.clapper.org – user482745 Mar 22 '17 at 09:20
  • I'm working on fixing that. In the meantime, it's available here: https://dl.bintray.com/bmc/maven (or will be shortly). – Brian Clapper Mar 22 '17 at 23:25
  • Version 3.2.0 should be in JCenter soon. It's in dl.bintray.com/bmc/maven now. Once it's in JCenter, I'll sync it to Maven. – Brian Clapper Mar 23 '17 at 02:11
  • @BrianClapper please help me here: https://stackoverflow.com/questions/68078584/is-there-way-that-we-can-get-the-id-of-partition-which-the-current-row-processed , thanks very much. – Shawn.X Jun 23 '21 at 14:13
64

Spring can do this for you...

BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);

TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class);
s.addIncludeFilter(tf);
s.scan("package.you.want1", "package.you.want2");       
String[] beans = bdr.getBeanDefinitionNames();

N.B. The TypeFilter is important if you want the correct results! You can also use exclusion filters here instead.

The Scanner can be found in the spring-context jar, the registry in spring-beans, the type filter is in spring-core.

Nick Robson
  • 671
  • 5
  • 2
  • 9
    You might want to add `s.setIncludeAnnotationConfig(false);` to filter Spring own classes out. – Alain Pannetier Nov 10 '13 at 12:40
  • 1
    but how can `String[]` be useful?? what we need here is a list of `CLASS_YOU_WANT`classes, – azerafati Oct 26 '14 at 12:03
  • 1
    you can get the `BeanDefinition` from the `BeanDefinitionRegistry` instance using the bean name. – André Jan 06 '15 at 10:56
  • 4
    `s.resetFilters(false);` will remove the default Spring filters that would include all classes with @Component, @Service, and some other annotations into the result set. – averasko Jun 01 '15 at 13:32
  • 2
    You can use `ClassPathScanningCandidateComponentProvider` to get the `BeanDefinition` directly. The constructor takes a boolean which allows you to disable the default filters that pick up `@Component`, `@Service`, etc. The `TypeFilter` can be included using `addIncludeFilter` and the definitions retrieved via `findCandidateComponents("com.my.package")` – Max Feb 07 '16 at 18:08
  • It's looking for classes, but the question aims for classes that implements certain interface. – NaN Dec 14 '18 at 13:54
  • This code seems to hard-code package names at design-time. We need it to search all packages in the project (mainly because people who implement the interface can have their implementations in whatever packages they like - and i won't know any of their names. CLR and .NET can do it; so Java must be able to. – Ian Boyd Jul 22 '22 at 04:13
40

I really like the reflections library for doing this.

It provides a lot of different types of scanners (getTypesAnnotatedWith, getSubTypesOf, etc), and it is dead simple to write or extend your own.

Manius
  • 3,594
  • 3
  • 34
  • 44
robertvoliva
  • 902
  • 6
  • 6
  • 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. – Javaru Jun 21 '23 at 21:14
29

The code you are talking about sounds like ServiceLoader, which was introduced in Java 6 to support a feature that has been defined since Java 1.3 or earlier. For performance reasons, this is the recommended approach to find interface implementations at runtime; if you need support for this in an older version of Java, I hope that you'll find my implementation helpful.

There are a couple of implementations of this in earlier versions of Java, but in the Sun packages, not in the core API (I think there are some classes internal to ImageIO that do this). As the code is simple, I'd recommend providing your own implementation rather than relying on non-standard Sun code which is subject to change.

Community
  • 1
  • 1
erickson
  • 265,237
  • 58
  • 395
  • 493
  • 7
    AFAI understand it, the poster does want to have this for arbitrary interfaces, so ServiceLoader probably doesn't help. – Kutzi May 05 '11 at 15:00
  • @Kutzi How do you arrive at that conclusion? The poster explicitly says he wants to "locate the classes that implemented a given interface", and the tool he is looking for is "some piece of standard Java." – erickson Apr 12 '12 at 15:33
  • 2
    If you want auto-generation of the META-INF services stuff check out Kohsuke's MetaInfServices http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html – Adam Gent Jun 24 '12 at 13:09
  • 1
    ServiceLoader doesn't seem to be able to find implementors of an arbitrary interface. – Cajunluke Sep 25 '12 at 23:03
  • @CajunLuke No, it can't. However that's not what the question was asking. – erickson Sep 26 '12 at 03:59
  • 1
    I like this answer 1) its a standard java tool, 2) I'm defining a piece of an extendable framework, so this is perfect. Different strokes for different folks, this just happened to be my stroke! – Ring Nov 17 '14 at 22:28
  • 1
    Caution - ServiceLoader will not provide a list of *classes* - it will provide a list of *instances*. Most often, this distinction is not important, but in certain cases - classes without a no-arg constructor, enums - it may be relevant. – drew Aug 31 '17 at 15:42
  • 3
    @drew this has changed with Java 9. It now offers a way to iterate over all providers without instantiating them, so you can query the `Class` first. Further, for Java code using modules, it is now possible to provide services via static factory methods, [this answer](https://stackoverflow.com/a/59617524/2711488) provides an example for integrating an `enum` type. – Holger Apr 17 '20 at 21:53
14

Package Level Annotations

I know this question has already been answered a long time ago but another solution to this problem is to use Package Level Annotations.

While its pretty hard to go find all the classes in the JVM its actually pretty easy to browse the package hierarchy.

Package[] ps = Package.getPackages();
for (Package p : ps) {
  MyAno a = p.getAnnotation(MyAno.class)
  // Recursively descend
}

Then just make your annotation have an argument of an array of Class. Then in your package-info.java for a particular package put the MyAno.

I'll add more details (code) if people are interested but most probably get the idea.

MetaInf Service Loader

To add to @erickson answer you can also use the service loader approach. Kohsuke has an awesome way of generating the the required META-INF stuff you need for the service loader approach:

http://weblogs.java.net/blog/kohsuke/archive/2009/03/my_project_of_t.html

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • 3
    Beware: not all packages are available at run time. See [here](http://stackoverflow.com/questions/1816730/is-there-a-way-to-force-a-classloader-to-load-a-package-even-if-none-of-its-clas) for more insight. – clafonta Mar 14 '12 at 11:40
  • 2
    Please add more code to show annotation example as well . Already given +1 . – Shahzeb Mar 14 '12 at 23:46
  • @clafonta I believe by using package-info.java and annotations in that class the package will be loaded very early (eager). There are others that use this technique (JAX-RS and JAXB) of package-info annotations (http://stackoverflow.com/questions/8735737/what-package-info-do-i-annotate-with-xmljavatypeadapters). Basically you need to rely on something else being loaded first in those packages. – Adam Gent Mar 18 '12 at 13:47
9

You could also use the Extensible Component Scanner (extcos: http://sf.net/projects/extcos) and search all classes implementing an interface like so:

Set<Class<? extends MyInterface>> classes = new HashSet<Class<? extends MyInterface>>();

ComponentScanner scanner = new ComponentScanner();
scanner.getClasses(new ComponentQuery() {
    @Override
    protected void query() {
        select().
        from("my.package1", "my.package2").
        andStore(thoseImplementing(MyInterface.class).into(classes)).
        returning(none());
    }
});

This works for classes on the file system, within jars and even for those on the JBoss virtual file system. It's further designed to work within standalone applications as well as within any web or application container.

Matthias Rothe
  • 101
  • 1
  • 6
  • 1
    This is by far the simplest way to collect implementing classes. – Sven May 03 '12 at 10:59
  • 1
    This seems to be limited to searching in specific packages though, no? – Brad Mace May 28 '13 at 20:37
  • This is the only solution I could find that would handle all implementing classes of sub-interfaces as well. And it was easy to integrate and use. – Kevin Pauli Nov 16 '16 at 16:32
  • Looks like this may not be compatible with modern versions of Java (threw exceptions for me for Java 8) – Richard Tingle Aug 15 '19 at 10:42
  • Well, it's still working with Java 8, even though exceptions are thrown and logged if you have a logger installed. With Java 9 and up I haven't tried but would be very surprised if it still worked, because of the implications of project Jigsaw. – Matthias Rothe Feb 05 '20 at 17:30
8

In full generality, this functionality is impossible. The Java ClassLoader mechanism guarantees only the ability to ask for a class with a specific name (including package), and the ClassLoader can supply a class, or it can state that it does not know that class.

Classes can be (and frequently are) loaded from remote servers, and they can even be constructed on the fly; it is not difficult at all to write a ClassLoader that returns a valid class that implements a given interface for any name you ask from it; a List of the classes that implement that interface would then be infinite in length.

In practice, the most common case is an URLClassLoader that looks for classes in a list of filesystem directories and JAR files. So what you need is to get the URLClassLoader, then iterate through those directories and archives, and for each class file you find in them, request the corresponding Class object and look through the return of its getInterfaces() method.

Frankie
  • 24,627
  • 10
  • 79
  • 121
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • Sorry for the downvote, but this answer doesn't look correct. Something like this: `ServiceLoader providers = ServiceLoader.load(Provider.class); for (Provider p : providers) { ... }` would list all implementations, no? – Frankie Dec 28 '22 at 05:40
  • @Frankie No. The ServiceLoader/ServiceProvider thing is an additional mechanism on top of Classloaders which requires additional work to make the specific provider classes known to the JVM (via a provider-configuration file, or a provides directive in the module declaration), *and* those provider classes have to fulfull some additional criteria. It will not return anything for most interfaces. – Michael Borgwardt Dec 31 '22 at 10:04
  • Ah! Now, I understand where you're coming from with the "impossible" statement. Agreed. I wasn't considering the full scope, where OP simply does not control part of the codebase. Nonetheless, wouldn't you be able to use reflections for that? I wrote a post precisely about this a couple of weeks ago, didn't put it here as OP has already found its answer, but would be happy if you could give it a look and correct me if I'm wrong: https://wasteofserver.com/java-how-to-get-all-implementations-of-an-interface/ many thanks! – Frankie Jan 02 '23 at 10:20
  • 1
    @Frankie: The Ronmano Reflections library that you mention basically does what I describe in the third paragraph of my answer, see https://github.com/ronmamo/reflections/blob/master/src/main/java/org/reflections/util/ClasspathHelper.java - and it has the restrictions I describe in the second paragraph. Admittedly, those restrictions are pretty irrelevant in practice because probably less than 1% of all Java applications use custom classloaders. Interestingly, it also relies on classloaders returning class files as resources for a directory, which I'm not sure is a standardized feature. – Michael Borgwardt Jan 02 '23 at 15:34
  • Much appreciated for your time. Definitely helped me get a much clearer view on the subject. Thanks! – Frankie Jan 02 '23 at 17:00
5

Obviously, Class.isAssignableFrom() tells you whether an individual class implements the given interface. So then the problem is getting the list of classes to test.

As far as I'm aware, there's no direct way from Java to ask the class loader for "the list of classes that you could potentially load". So you'll have to do this yourself by iterating through the visible jars, calling Class.forName() to load the class, then testing it.

However, it's a little easier if you just want to know classes implementing the given interface from those that have actually been loaded:

  • via the Java Instrumentation framework, you can call Instrumentation.getAllLoadedClasses()
  • via reflection, you can query the ClassLoader.classes field of a given ClassLoader.

If you use the instrumentation technique, then (as explained in the link) what happens is that your "agent" class is called essentially when the JVM starts up, and passed an Instrumentation object. At that point, you probably want to "save it for later" in a static field, and then have your main application code call it later on to get the list of loaded classes.

Neil Coffey
  • 21,615
  • 7
  • 62
  • 83
  • Instrumentation.getAllLoadedClasses() : Cannot make a static reference to the non-static method getAllLoadedClasses() from the type Instrumentation ................. Java 8 – JRichardsz Dec 13 '18 at 15:56
  • The Instrumentation instance is pass to the premain method: public static void premain( String agentArgs, Instrumentation instrumentation ) – Aldo Canepa Oct 13 '20 at 20:16
0

If you were asking from the perspective of working this out with a running program then you need to look to the java.lang.* package. If you get a Class object, you can use the isAssignableFrom method to check if it is an interface of another Class.

There isn't a simple built in way of searching for these, tools like Eclipse build an index of this information.

If you don't have a specific list of Class objects to test you can look to the ClassLoader object, use the getPackages() method and build your own package hierarchy iterator.

Just a warning though that these methods and classes can be quite slow.

Matt Large
  • 399
  • 1
  • 4
  • 9