Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which exact classes are loaded by Platform ClassLoader?

Let's assume, we're using OpenJDK 20. The official documentation says:

The platform class loader is responsible for loading the platform classes. Platform classes include Java SE platform APIs, their implementation classes, and JDK-specific run-time classes that are defined by the platform class loader or its ancestors. The platform class loader can be used as the parent of a ClassLoader instance.

At the same time, I understood from the Oracle specification that Bootstrap ClassLoader loads the core runtime classes required to start the JVM. I also understood that Platform ClassLoader does not load anything into an empty program:

jshell> ClassLoader.getPlatformClassLoader().getDefinedPackages();
$1 ==> Package[0] { }

But it loads some packages from Java SE, like java.sql:

jshell> java.sql.Connection.class.getClassLoader()
$2 ==> jdk.internal.loader.ClassLoaders$PlatformClassLoader@27fa135a

jshell> ClassLoader.getPlatformClassLoader().getDefinedPackages()
$3 ==> Package[1] { package java.sql }

And some not (like java.util.logging, as the same child of java-se module):

jshell> java.util.logging.ConsoleHandler.class.getClassLoader();
$4 ==> null

Am I correct in stating that Platform ClassLoader loads the public types of system modules that a developer might need? If so, which specific packages (or better ask, modules?) fall under this "might"?

Thanks in advance.

like image 247
Yahor Barkouski Avatar asked Jan 29 '26 10:01

Yahor Barkouski


1 Answers

The decision is made per module. You can use the following code to group the modules per class loader:

ModuleLayer.boot().modules().stream()
  .collect(Collectors.groupingBy(
    m -> Optional.ofNullable(m.getClassLoader())
                 .map(ClassLoader::getName).orElse("boot"),
    Collectors.mapping(Module::getName,
                       Collectors.toCollection(() -> new TreeSet<>()))))
  .entrySet().stream()
  .sorted(Comparator.comparingInt(
                     e -> List.of("boot", "platform", "app").indexOf(e.getKey())))
  .map(e -> e.getKey() + "\n\t" + String.join("\n\t", e.getValue()))
  .forEach(System.out::println);

which will print something alike:

boot
    java.base
    java.datatransfer
    java.desktop
    java.instrument
    java.logging
    java.management
    java.management.rmi
    java.naming
    java.prefs
    java.rmi
    java.security.sasl
    java.xml
    jdk.jfr
    jdk.management
    jdk.management.agent
    jdk.management.jfr
    jdk.naming.rmi
    jdk.net
    jdk.sctp
    jdk.unsupported
platform
    java.compiler
    java.net.http
    java.scripting
    java.security.jgss
    java.smartcardio
    java.sql
    java.sql.rowset
    java.transaction.xa
    java.xml.crypto
    jdk.accessibility
    jdk.charsets
    jdk.crypto.cryptoki
    jdk.crypto.ec
    jdk.dynalink
    jdk.httpserver
    jdk.jsobject
    jdk.localedata
    jdk.naming.dns
    jdk.scripting.nashorn
    jdk.security.auth
    jdk.security.jgss
    jdk.xml.dom
    jdk.zipfs
app
    jdk.attach
    jdk.compiler
    jdk.editpad
    jdk.internal.ed
    jdk.internal.jvmstat
    jdk.internal.le
    jdk.internal.opt
    jdk.jartool
    jdk.javadoc
    jdk.jconsole
    jdk.jdeps
    jdk.jdi
    jdk.jdwp.agent
    jdk.jlink
    jdk.jshell
    jdk.jstatd
    jdk.unsupported.desktop

Demonstration on tio.run

Note that the classes loaded by the bootstrap class loader are not strictly necessary to run the JVM. Only a few classes within the java.base module are really required by the JVM. You can use the jlink command to create an environment containing only the modules required by your application and in the most extreme example, that could be an environment only containing java.base (and your application module, to be useful).

You may recognize a pattern in the decision about the module to class loader mapping, but as with any decision made by humans, there can be outliers.

It’s not really important anyway; when you ask a module-capable class loader to load a class belonging to a named module (and all JDK classes belong to a named module) within the same module layer, it will delegate to the module’s class loader anyway.

For example, the following code

Class<?> c = Class.forName("com.sun.source.doctree.VersionTree",
    false, ClassLoader.getPlatformClassLoader());
System.out.println(c + "\n\t" + c.getClassLoader() + "\n\t" + c.getModule());

prints

interface com.sun.source.doctree.VersionTree
    jdk.internal.loader.ClassLoaders$AppClassLoader@5bc2b487
    module jdk.compiler

demonstrating that asking the platform class loader for a class belonging to a module associated with the application class loader will succeed.

Demonstration on tio.run

like image 170
Holger Avatar answered Jan 31 '26 23:01

Holger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!