Yang Zhou
Yang Zhou

Reputation: 54

Why cannot load java.sql.Driver with URLClassloader(name, null) in Java 11

In Java 8, we can load MySQL Driver like this:

URLClassLoader mysql5ClassLoader = new URLClassLoader(new URL[]{new File(mysql5path).toURI().toURL()}, null);
Class<?> mysql5Class = mysql5ClassLoader.loadClass("com.mysql.jdbc.Driver");
Driver mysql5Driver = (Driver) mysql5Class.getDeclaredConstructor().newInstance();

But in Java 11 (in fact, 9 or later), we must using

URLClassLoader mysql5ClassLoader = new URLClassLoader(new URL[]{new File(mysql5path).toURI().toURL()}, ClassLoader.getPlatformClassLoader());

I check the oracle doc found https://docs.oracle.com/en/java/javase/11/migrate/index.html#JSMIG-GUID-A868D0B9-026F-4D46-B979-901834343F9E

The changes that were implemented in JDK 9 may impact code that creates class loaders with null (that is, the bootstrap class loader) as the parent class loader and assumes that all platform classes are visible to the parent. Such code may need to be changed to use the platform class loader as the parent (see ClassLoader.getPlatformClassLoader).

Then I debug with null parent and ClassLoader.getPlatformClassLoader() parent found both above using ClassLoader.findClass(name), one get java.lang.NoClassDefFoundError: java/sql/Driver, one can load MySQL Driver successfully.

Why and How get the different result

Upvotes: 1

Views: 1163

Answers (1)

Stephen C
Stephen C

Reputation: 719289

If you use null as the parent classloader, you are telling this classloader to resolve platform classes in the bootstrap classloader.

That (typically) worked prior to Java 9 because all Java platform classes were loaded via the bootstrap classloader.

It (typically) doesn't work from Java 9 onwards, because in Java 9 they introduced modules and changed what classloaders loaded what platform classes. Most platform classes are now loaded by a different classloader. (Specifically by the classloader returned by getPlatformClassLoader().)

So ... in Java 9 ... if you create a classloader with a null parent, then class loading a JDBC driver is liable to fail ... because the bootstrap classloader doesn't know about the platform classes that the driver depends on.

Note: this is simply an elaboration of what the text you quoted in your question actually says.


Q: Why did they change it?

A: Because it was necessary to support modules and to fix the problem of the SE libraries being monolithic.

Q: Can you avoid fixing your code?

A: Not if you want to create the classloader dynamically like that. But you wouldn't have this problem if you simply included the driver in the launch-time classpath; e.g. using -cp ....

Upvotes: 2

Related Questions