[Java]ClassLoader et Driver JDBC

Sujet assez pointu mais je pose quand même la question : Je cherche à charger en live des drivers JDBC avec un système de plugin (mon mysql.jar n’est donc pas à l’origine dans le classpath).

Voici mon code :

[code] public static void main(String… args) throws Exception {
JarFileLoader jarFileLoader = new JarFileLoader();
jarFileLoader.addFile("/usr/share/java/mysql.jar");
Driver driver = (Driver)Class.forName(“com.mysql.jdbc.Driver”, true, jarFileLoader).newInstance();
DriverManager.registerDriver(driver);

	// Affichage des drivers chargés
	for (Driver myDriver : Collections.list(DriverManager.getDrivers())) {
		logger.debug(myDriver.getClass().getName());
	}

	Properties props = new Properties();
	props.setProperty("user", "achievo");
	props.setProperty("password", "achievo");
	props.setProperty("autoReconnect", "true");
	Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/achievo", props);
	Statement statement = connection.createStatement();
	ResultSet result = statement.executeQuery("SELECT 1");
	
	if (result.next()) {
		logger.debug("Result : " + result.getInt(1));
	}
}
}[/code]

et le résultat :

21:08:38.979 [main] DEBUG org.hibiscus.analysesi.db.DbManager - sun.jdbc.odbc.JdbcOdbcDriver Exception in thread "main" java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost/achievo at java.sql.DriverManager.getConnection(DriverManager.java:602) at java.sql.DriverManager.getConnection(DriverManager.java:154) at org.hibiscus.analysesi.db.DefaultDbManager.main(DefaultDbManager.java:286)

Comme vous le voyez, il ne me trouve pas mon Driver même si j’arrive à instancier la classe “com.mysql.jdbc.Driver”, par contre si j’ajoute mon fichier jar mysql.jar dans le classpath, ça passe bien.

J’essaye de fouiller dans tout ce qui touche au Driver JDBC et au ClassLoader mais je ne trouve pas beaucoup de documentation sur la marche à suivre. Y a-t-il quelqu’un qui ai déjà du travailler avec plusieurs ClassLoader et qui connait les pièges à éviter ?

Alors déjà, qui est ce JarFileLoader ? Je suppose que c’est un java.net.URLClassLoader, ou qque chose dans le genre… Disons en tout cas que c’est un CL qui arrive à charger ta classe, qui n’était pas dans le classpath au départ - i.e. qui n’est pas chargée par le CL de ta classe courante (celle qui a un main).

Pour mieux comprendre ton problème, ajoute cette ligne au début de ton main :

[codebox] // Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();

    // Walk through the loaded drivers.
    for (int i = 0; i < drivers.size(); i++) {
        DriverInfo di = (DriverInfo)drivers.elementAt(i);
    // If the caller does not have permission to load the driver then 
    // skip it.
        if ( [b]getCallerClass(callerCL, di.driverClassName ) != di.driverClass [/b]) {[b]   // impossible si ton driver n'est pas chargeable par le callerCL[/b]
            println("    skipping: " + di);
            continue;
        }
        result.addElement(di.driver);
    }

[/codebox]

Impossible donc, tant que le le CL n’a pas le driver dès le départ dans son classpath :confused:

La méthode de DriverManager permettant de trouver ce fameux callerCL étant statique privée et faisant appel à une méthode native (très discutable indeed… :crying: ), impossible de contourner par des moyens usuels (dits « propres ») comme un simple overriding.
En vérité je ne vois pas bien comment workarounder ce problème… vais essayer d’y réfléchir.

HTH quand même :slight_smile:

Mon JarFileLoader et en effet un java.net.URLClassLoader.

J’ai regardé les sources du DriverManager et tout s’explique ce qui ne m’arrange pas du tout. Le plus simple pour moi serait de faire un script de lancement pour la JVM qui prennent en charge les drivers JDBC dans le ClassPath mais c’est chiant, il faut faire ça en fonction du système d’exploitation.

Merci de ton aide et surtout bienvenu sur la Geekzone !