2009-12-03 26 views
7

Sto scrivendo uno strumento di convalida del database in Java e sono schermate delle preferenze in modo che l'utente possa definire le connessioni del database. Lo strumento dovrebbe essere in grado di gestire DB2, Oracle, Postgresql e Mysql come minimo.Trovare i driver JDBC installati

Quello che mi piacerebbe davvero è poter presentare all'utente un elenco dei driver jdbc installati come parte di questo processo.

Qualcuno può fornire uno snippet di codice per scoprire i driver JDBC installati?

risposta

9

Al punto, è necessario eseguire la scansione dell'intero classpath (e sottocartelle) per le classi che implementano java.sql.Driver. In questo modo coprirai anche i driver che sono non caricati manualmente da Class#forName() o automaticamente da META-INF/services.

Ecco un esempio di base:

public static void main(String[] args) throws Exception { 
    List<Class<Driver>> drivers = findClassesImplementing(Driver.class); 
    System.out.println(drivers); 
}   

public static <T extends Object> List<Class<T>> findClassesImplementing(Class<T> cls) throws IOException { 
    List<Class<T>> classes = new ArrayList<Class<T>>(); 

    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<T>) found); 
        } 
       } catch (Throwable ignore) { 
        // No real class file, or JAR not in classpath, or missing links. 
       } 
      } 
     } 
    } 

    return classes; 
} 

public static List<File> 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<File> found = new ArrayList<File>(files.length); 

    for (File file : files) { 
     if (file.isDirectory()) { 
      found.addAll(findFiles(file, pattern)); 
     } else { 
      found.add(file); 
     } 
    } 

    return found; 
} 

Invece si può anche prendere in considerazione di utilizzare la Google Reflections API che fa tutto questo in una sola riga:

Set<Class<? extends Driver>> drivers = reflections.getSubTypesOf(Driver.class); 
+0

In questa soluzione, non stai eseguendo blocchi statici sulle classi che stai testando? –

+0

Sì, sarebbero stati eseguiti. Non puoi andare in giro. – BalusC

+1

Thx bigtime, BalusC –

3

Questo dovrebbe aiutare:

java.sql.DriverManager.getDrivers() 
+6

Poiché questo è IMHO erroneamente accettato, vorrei solo enfatizza di più: funziona * solo * se i driver sono ** effettivamente ** caricati; manualmente con 'Class # forName()' o automagicamente da 'META-INF/services'. Questo NON rileva i driver che * sono * in classpath, ma che * non * sono caricati. – BalusC

3
java.sql.DriverManager.getDrivers() 

non è tutto.

Come il doc dice

recupera un Enumeration con tutti i driver JDBC attualmente caricati al cui il chiamante corrente ha accesso.

Ciò significa che i driver caricati (con Class.forName()), non sono installati (diciamo disponibile tramite JAR).

Normalmente si consegnerebbe il software con tutti i jar del driver JDBC che il programma può funzionare. A seconda di cosa l'utente si connetterà (oracle, access, db2) il programma deve caricare il driver appropriato.

+1

Ho avuto l'impressione che la distribuzione di driver di terze parti nei miei barattoli violerebbe il copyright, o comunque qualcosa di legale –

+1

In realtà includerà i driver indicati tramite la proprietà di sistema 'jdbc.drivers' e quelli resi disponibili tramite il fornitore di servizi ('META-INF/services') meccanismo. –

Problemi correlati