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.
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
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.