JDBC DriverManager never updated for system classloader?
Alan Bateman
alan.bateman at oracle.com
Sun Nov 2 09:07:55 UTC 2025
On 27/10/2025 20:06, Charles Oliver Nutter wrote:
> Hello!
>
> I've been looking for a concrete explanation for why the JDBC
> DriverManager can't find drivers under the following circumstances:
>
> * Driver jar loaded into child classloader of app classloader
> * Child classloader set for current thread's context classloader
>
> My long explanation of the issue is here:
>
> https://github.com/jruby/jruby/issues/8910#issuecomment-3453029437
>
> The short explanation is that when the DriverManager goes to check for
> "allowed" drivers, it ends up using the wrong classloader.
>
> https://github.com/openjdk/jdk/blob/8151251fa683459e57430abf8e3583c444315746/src/java.sql/share/classes/java/sql/DriverManager.java#L157
>
> * Caller's class is acquired with Reflection.getCallerClass
> * Caller's classloader is acquired
> * If that classloader is null, as it would have been for classes
> loaded on the root classpath in Java 8, it instead uses the thread
> context classloader.
> * If that classloader is not null (Java 9+) and not the platform
> classloader, it is used for verification; in this case it is the
> system classloader (a "ClassLoader#AppClassLoader" instance) so the
> child classloader's driver is disallowed.
>
> My confusion is why this code was never patched for the change to the
> system classloader (from null to an AppClassLoader). The logic in
> DriverManager will never use the ThreadContext classloader now, since
> there's almost no cases where "getClassLoader" will return null.
>
> Is there a good explanation for why this code still checks for a null
> classloader?
>
The java.sql module is mapped to the platform class loader so you are
correct that none of the classes in that module will be visible to the
boot class loader. None of the core modules `requires java.sql` so
wouldn't compile anyway.
The edge case of a JNI attached thread calling DriverManager methods
with no java frames on the stack should be the only case now where the
caller is null. The java.sql.rowset (requires java.sql) is also mapped
to the platform class loader. I don't know if it uses DriverManager but
if it did, then the caller would be a class defined by the platform
class loader.
I don't think it's possible to engage on the question as to why
DriverManager does a visibility check. The discovery and and driver
registration in this API date back to early JDK releases and have been
very problematic to secure. I think (need Lance to confirm) that the
hope was that the eco system would move to DataSource but it seems there
is still a lot of usage of DriverManager.
-Alan
More information about the core-libs-dev
mailing list