I\'m writing a database validation tool in Java and have preference screens so the user can define their database connections. The tool should be able to cope with DB2, Orac
To the point, you need to scan the entire classpath (and subfolders) for classes implementing java.sql.Driver. This way you will also cover drivers which are not loaded manually by Class#forName() or automagically by META-INF/services.
Here's a basic example:
public static void main(String[] args) throws Exception {
List> drivers = findClassesImplementing(Driver.class);
System.out.println(drivers);
}
public static List> findClassesImplementing(Class cls) throws IOException {
List> classes = new ArrayList>();
for (URL root : Collections.list(Thread.currentThread().getContextClassLoader().getResources(""))) {
for (File file : findFiles(new File(root.getFile()), ".+\\.jar$")) {
JarFile jarFile = new JarFile(file);
for (JarEntry jarEntry : Collections.list(jarFile.entries())) {
String name = jarEntry.getName();
if (name.endsWith(".class")) try {
Class> found = Class.forName(name.replace("/", ".").replaceAll("\\.class$", ""));
if (cls.isAssignableFrom(found)) {
classes.add((Class) found);
}
} catch (Throwable ignore) {
// No real class file, or JAR not in classpath, or missing links.
}
}
}
}
return classes;
}
public static List findFiles(File directory, final String pattern) throws IOException {
File[] files = directory.listFiles(new FileFilter() {
public boolean accept(File file) {
return file.isDirectory() || file.getName().matches(pattern);
}
});
List found = new ArrayList(files.length);
for (File file : files) {
if (file.isDirectory()) {
found.addAll(findFiles(file, pattern));
} else {
found.add(file);
}
}
return found;
}
Instead you can also consider to use the Google Reflections API which does this all in a single line:
Set> drivers = reflections.getSubTypesOf(Driver.class);