How do I discover classes at runtime in the classpath which implements a defined interface?
ServiceLoader suits well (I think, I haven't used it), but I need do it in Java 1.5.
How do I discover classes at runtime in the classpath which implements a defined interface?
ServiceLoader suits well (I think, I haven't used it), but I need do it in Java 1.5.
There's nothing built into Java 1.5 for this. I implemented it myself; it's not too complicated. However, when we upgrade to Java 6, I will have to replace calls to my implementation with calls to ServiceLoader
. I could have defined a little bridge between the app and the loader, but I only use it in a few places, and the wrapper itself would be a good candidate for a ServiceLoader.
This is the core idea:
public <S> Iterable<S> load(Class<S> ifc) throws Exception {
ClassLoader ldr = Thread.currentThread().getContextClassLoader();
Enumeration<URL> e = ldr.getResources("META-INF/services/" + ifc.getName());
Collection<S> services = new ArrayList<S>();
while (e.hasMoreElements()) {
URL url = e.nextElement();
InputStream is = url.openStream();
try {
BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while (true) {
String line = r.readLine();
if (line == null)
break;
int comment = line.indexOf('#');
if (comment >= 0)
line = line.substring(0, comment);
String name = line.trim();
if (name.length() == 0)
continue;
Class<?> clz = Class.forName(name, true, ldr);
Class<? extends S> impl = clz.asSubclass(ifc);
Constructor<? extends S> ctor = impl.getConstructor();
S svc = ctor.newInstance();
services.add(svc);
}
}
finally {
is.close();
}
}
return services;
}
Better exception handling is left as an exercise for the reader. Also, the method could be parameterized to accept a ClassLoader of the caller's choosing.
javax.imageio.spi.ServiceRegistry
is the equivalent with prior Java versions. It's available since Java 1.4.
It does not look like a general utility class, but it is. It's even a bit more powerful than ServiceLoader
, as it allows some control over the order of the returned providers and direct access to the registry.
See http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
ServiceLoader is quite basic, and has been in use (informally) within the JDK since 1.3. ServiceLoader just finally made it a first class citizen. It simply looks for a resource file named for your interface, which is basically bundled in the META-INF directory of a library jar.
That file contains the name of the class to load.
So, you'd have a file named:
META-INF/services/com.example.your.interface
and inside it is a single line: com.you.your.interfaceImpl.
In lieu of ServiceLoader, I like Netbeans Lookup. It works with 1.5 (and maybe 1.4).
Out of the box, it does the exact same thing as ServiceLoader, and it's trivial to use. But it offers a lot more flexibility.
Here's a link: http://openide.netbeans.org/lookup/
Here's a article about ServiceLoader, but it mentions Netbeans Lookup at the bottom: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
Unfortunately,
There's nothing built into Java 1.5 for this ...
is only a part of truth.
There is non-standard sun.misc.Service
around.
http://www.docjar.com/docs/api/sun/misc/Service.html
Beware, it is not a part of standard J2SE API!
It is non-standard part of Sun JDK.
So you can not rely on it if you use, say, JRockit
.
This is an old question but the other option is to use Package Level Annotations. See my answer for: Find Java classes implementing an interface
Package level annotations are annotations that are in package-info.java classes.
JAXB uses this instead of Service Loaders. I also think its more flexible than the service loader.
There is no reliable way to know what classes are in the classpath. According to its documentation, ServiceLoader relies on external files to tell it what classes to load; you might want to do the same. The basic idea is to have a file with the name of the class(es) to load, and then use reflection to instantiate it/them.