[9] RFR(S): 8178726: Can't load classes from classpath if it is a UNC share

Volker Simonis volker.simonis at gmail.com
Thu Apr 13 18:50:32 UTC 2017


Hi,

can you please review the following change which fixes a problem with
UNC paths on the Windows class path:

http://cr.openjdk.java.net/~simonis/webrevs/2017/8178726/
https://bugs.openjdk.java.net/browse/JDK-8178726

I would appreciate if somebody could run this trough JPRT for me. I
won't be available until Tuesday after Easter so there's some time for
testing :)

Here comes the detailed problem description (also included in the bug report):

If we set the classpath to a UNC share (e.g. '-cp \\foo\bar\classes')
java won't be able to find classes there. This is also true if we set
the classpath to a drive letter which maps to a network drive (e.g.
'-cp Z:\classes' where 'Z:' is a short-cut for '\\foo\bar').

This error is clearly a regression and should be fixed before Java 9 GA.

The problem is caused by the refactoring of the application class loader:

Before Java 9 the application class loader was a URLClassLoader
(actually sun.misc.Launcher$AppClassLoader which extends
URLClassLoader). It took the classpath from the "java.class.path"
property and transformed it into a File[] by calling
Launcher.getClassPath(). This File[] was then converted into a URL[]
by calling Launcher.pathToURLs() which in turn called
Launcher.getFileURL() which finally called
sun.net.www.ParseUtil.fileToEncodedURL() to convert a File into an
URL. This last function explicitly creates URLs with protocol 'file'
and empty authority (i.e. if the File contained an authority part like
"\\foo" in "\\foo\bar\classs"), this was saved in the path part of the
URL (i.e. 'return new URL("file", "", path)');

Later, these URLs were used to access classes on the classpath. This
was done by creating new File objects from the path components of the
corresponding URLs and because these path components already contained
the full UNC path, everything worked fine.

In JDK 9 now, the legacy class path is constructed in
jdk.internal.loader.ClassLoaders. It also takes the "java.class.path"
property as a starting point but calls addClassPathToUCP() which in
turn calls toFileURL() which finally uses
'Paths.get(s).toRealPath().toUri().toURL()' to transform a string 's'
into an URL. This conversion creates URLs where the authority part
contains the hostname and the path component contains the remaining
path from the UNC paths in the classpath.

The problem is now that during class loading, the new application
class loader jdk.internal.loader.ClassLoaders$AppClassLoader calls
jdk.internal.loader.BuiltinClassLoader.loadClass() which calls
loadClassOrNull() which calls findClassOnClassPathOrNull() which calls
jdk.internal.loader.URLClassPath.getResource(). The class URLClassPath
has a list of all the previously created URLs for each entry of the
classpath. For each of these URLs it creates a
jdk.internal.loader.URLClassPath$Loader by calling getLoader(). If the
corresponding URL represents a file, it will create a
jdk.internal.loader.URLClassPath$FileLoader (which derives from
URLClassPath$Loader). The FileLoader class uses the file component of
the URL to construct a File object for accessing the underlying
ressources. But unlike the jdk8 case, the file part of the URL now
only contains the path component WITHOUT the authority (i.e. 'host')
part. This will be interpreted as a relative path realtively to the
current drive and obviously fail.

Thanks,
Volker


More information about the core-libs-dev mailing list