Example code in JDK8 requiring change for modular function
David Holmes
david.holmes at oracle.com
Sun May 6 05:36:09 PDT 2012
Hi Paul,
On 5/05/2012 12:57 AM, Paul Sandoz wrote:
> Hi,
>
> Looking into java.nio.Files (by chance for other reasons) one comes across:
>
> Files.probeContentType
> http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType(java.nio.file.Path)
>
> which states:
>
> "A given invocation of the Java virtual machine maintains a system-wide list of file type detectors. Installed file type detectors are loaded using the service-provider loading facility defined by the ServiceLoader class. Installed file type detectors are loaded using the system class loader. If the system class loader cannot be found then the extension class loader is used; If the extension class loader cannot be found then the bootstrap class loader is used. File type detectors are typically installed by placing them in a JAR file on the application class path or in the extension directory, the JAR file contains a provider-configuration file named java.nio.file.spi.FileTypeDetector in the resource directory META-INF/services, and the file lists one or more fully-qualified names of concrete subclass of FileTypeDetector that have a zero argument constructor. If the process of locating or instantiating the installed file type detectors fails then an unspecified error is thr!
own. The
ordering that installed providers are located is implementation specific."
>
> And the relevant code in Files.java is:
>
> private static class FileTypeDetectors{
> static final FileTypeDetector defaultFileTypeDetector =
> sun.nio.fs.DefaultFileTypeDetector.create();
> static final List<FileTypeDetector> installeDetectors =
> loadInstalledDetectors();
>
> // loads all installed file type detectors
> private static List<FileTypeDetector> loadInstalledDetectors() {
> return AccessController
> .doPrivileged(new PrivilegedAction<List<FileTypeDetector>>() {
> @Override public List<FileTypeDetector> run() {
> List<FileTypeDetector> list = new ArrayList<>();
> ServiceLoader<FileTypeDetector> loader = ServiceLoader
> .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader());
> for (FileTypeDetector detector: loader) {
> list.add(detector);
> }
> return list;
> }});
> }
> }
>
> When running in "modular mode" the system class loader is the class loader of the entry module, where as what we really want to use is the class loader of the callee (the class loader used to load Files).
The system class loader needed not be the classloader of the callee. So
if we expect this to use the loader of the callee then the code is
broken regardless of module-mode.
David
-----
> While ServiceLoader in Jigsaw has been hacked to detect use of the system class loader and switch to the class loader of the callee it would be best to change the call from ServiceLoader.load to ServiceLoader.loadInstalled, which has the same class loading behavior in "classpath mode" and will do the right thing in "modular mode". i.e. where possible remove explicit referral to the system class loader.
>
> The javadoc also requires updating to reflect what happens in "modular mode".
>
> Further more, this code is caching the services. This is likely to be problematic with containers at runtime, that are started/stopped dynamically, where such a container has a module that provides a service implementations for FileTypeDetector.
>
> Paul.
More information about the jigsaw-dev
mailing list