JDK-8174151 : URLClassLoader no longer uses custom URLStreamHandler for jar URLs
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2017-02-06
  • Updated: 2022-01-07
  • Resolved: 2017-02-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 10 JDK 9
10Fixed 9 b158Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "9-ea"
Java(TM) SE Runtime Environment (build 9-ea+155)
Java HotSpot(TM) 64-Bit Server VM (build 9-ea+155, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Darwin aw-rmbp.home 14.5.0 Darwin Kernel Version 14.5.0: Sun Sep 25 22:07:15 PDT 2016; root:xnu-2782.50.9~1/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
I am a developer on Spring Boot where we use the java.protocol.handler.pkgs system property to install a custom URLStreamHandler for jar URLs. The custom handler enables Spring Boot's support for nested jars with a single, executable "fat" jar. This works fine on Java 6, 7, and 8

Running on Java 9, our custom URLStreamHandler is no longer used for URLs with which a URLClassLoader has been configured. This breaks our executable jar support. I believe this is due to this change in OpenJDK: http://hg.openjdk.java.net/jdk9/jdk9/jdk/diff/c49b0409a802/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java

REGRESSION.  Last worked in version 8u121

ADDITIONAL REGRESSION INFORMATION: 
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please see https://github.com/wilkinsona/jar-handler-regression

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The output should be:

URLs handled by custom handler: 1
ACTUAL -
The output is:

URLs handled by custom handler: 0

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Please see https://github.com/wilkinsona/jar-handler-regression
---------- END SOURCE ----------


Comments
URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/1c101c68279d User: lana Date: 2017-02-22 18:30:12 +0000
22-02-2017

URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/1c101c68279d User: psandoz Date: 2017-02-14 23:44:53 +0000
14-02-2017

Webrev: http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8174151-url-class-path-loader/webrev/index.html
13-02-2017

One solution: 1) retain the new behaviour for the default jar handler; and 2) preserve the previous behaviour for a non-default jar URL handler. The downside to this approach is the non-default jar URL handler will need to be multi-release aware if such jars are to be supported. Whereas with the current behaviour a non-default jar handler does not require modification for manage such resources (see previous comment).
10-02-2017

It is arguably an implementation detail that ClassLoader.getResource might when finding a resource operate on the resource URL before it is returned (in fact optimizations for accessing a nested file-based URL to a Jar file will bypass the file: URL handler). A work around is to explicitly open the returned resource URL, such as calling openConnection(). When accessing resources in multi-release JARs files it is necessary to ensure the Jar file is constructed to enable multi-release processing. For URLs the "#runtime" fragment signals this, but for resources we want to avoid exposing that in any URLs so the URL classpath implement bypasses the Jar URL handler operations directly via the internal JarLoader. For multi-release Jars a versioned resource will return a URL to a versioned area, such as for loader.findResource("resource.txt"): jar:file:/x/y/z/mr.jar!/META-INF/versions/9/resource.txt and not: jar:file:/x/y/z/mr.jar!/resource.txt#runtime
10-02-2017

To reproduce the issue, build the project and run it. Following are the test results : JDK 8u121 - Pass JDK 9-ea + 153 - Fail Following is the output on JDK 9-ea +153 : URLs handled by custom handler: 0 Following is the output on JDK 8u121: URLs handled by custom handler: 1
08-02-2017