Summary
-------
Stricter enforcement of the JAR Class-Path attribute requires changing the JAR spec.
Problem
-------
The JAR spec specifies that Class-Path entries must be relative URLs. However the JDK has also accepted absolute URLs for quite some time.
There is now code in the JDK to enforce this, but it is disabled by default, for compatibility. The JDK-8216401 fix improves compatibility of this code, so for JDK 13, we want to enable the enforcement code by default.
Solution
--------
Update the JAR spec to specify a valid Class-Path entry and reflect the new default behavior.
Some previously-working Class-Path entries could now be ignored. Such entries would need to be updated. To help isolate ignored Class-Path entries, setting the "jdk.net.URLClassPath.showIgnoredClassPathEntries" system property to "true" (or empty string) will print a warning message for Class-Path entries that are ignored.
Specification
-------------
JAR specification diff:
-and interpreted by the Java 2 Platform to configure applications, class
+and interpreted by the Java Platform to configure applications, class
...
The manifest for an application can specify one or more relative URLs
referring to the JAR files and directories for other libraries that it
needs. These relative URLs will be treated relative to the code base
-that the containing application was loaded from.
+that the containing application was loaded from (the "*context JAR*").
An application (or, more generally, JAR file) specifies the relative
...
At most one `Class-Path` header may be specified in a JAR file's
-manifest..
+manifest.
+
+A `Class-Path` entry is valid if the following conditions are true:
-Currently, the URLs must be *relative* to the code base of the JAR file
-for security reasons. Thus, remote optional packages will originate from
-the same code base as the application.
+- It can be used to create a [`URL`](../../api/java.base/java/net/URL.html#<init>(java.net.URL,java.lang.String)),
+ by resolving it against the context JAR���s URL.
+
+- It is relative, not [absolute](../../api/java.base/java/net/URI.html#isAbsolute()),
+ i.e. it does not contain a scheme component, except for the case when the
+ context JAR is loaded from the file system, in which case the `file` scheme
+ is permitted for compatibility reasons.
-Each relative URL is resolved against the code base that the containing
-application or library was loaded from. If the resulting URL is invalid
-or refers to a resource that cannot be found then it is ignored.
+- The location of the JAR file or directory represented by this entry
+ is contained within the containing directory of the context JAR.
+ Use of "`../`" to navigate to the parent directory is not permitted,
+ except for the case when the context JAR is loaded from the file system.
-The resulting URLs are used to extend the class path for the
-application, applet, or servlet by inserting the URLs in the class path
-immediately following the URL of the containing JAR file. Any duplicate
-URLs are omitted. For example, given the following class path:
+Invalid entries are ignored. Valid entries are resolved against the context JAR.
+If the resulting URL is invalid or refers to a resource that cannot be found,
+then it is ignored. Duplicate URLs are ignored.
+
+The resulting URLs are inserted into the class path,
+immediately following the path of the context JAR.
+For example, given the following class path:
...
-Class-Path: x.jar a.jar
+Class-Path: lib/x.jar a.jar
```
-Then the resulting application class path would be the following:
+Then the effective search path of such a `URLClassLoader` instance would be:
``` {style="MARGIN-LEFT: 40px"}
-a.jar b.jar x.jar
+a.jar b.jar lib/x.jar
```
Of course, if `x.jar` had dependencies of its own then these would be
Updated JAR specification:
Class-Path Attribute
--------------------
The manifest for an application can specify one or more relative URLs
referring to the JAR files and directories for other libraries that it
needs. These relative URLs will be treated relative to the code base
that the containing application was loaded from (the "context JAR").
An application (or, more generally, JAR file) specifies the relative
URLs of the libraries that it needs via the manifest attribute
`Class-Path`. This attribute lists the URLs to search for
implementations of other libraries if they cannot be found on the host
Java Virtual Machine. These relative URLs may include JAR files
and directories for any libraries or resources needed by the
application. Relative URLs not ending with '/' are assumed to refer to
JAR files. For example,
``` {style="MARGIN-LEFT: 40px"}
Class-Path: servlet.jar infobus.jar acme/beans.jar images/
```
At most one `Class-Path` header may be specified in a JAR file's
manifest.
A `Class-Path` entry is valid if the following conditions are true:
- It can be used to create a [`URL`](../../api/java.base/java/net/URL.html#<init>(java.net.URL,java.lang.String)),
by resolving it against the context JAR���s URL.
- It is relative, not [absolute](../../api/java.base/java/net/URI.html#isAbsolute()),
i.e. it does not contain a scheme component, except for the case when the
context JAR is loaded from the file system, in which case the `file` scheme
is permitted for compatibility reasons.
- The location of the JAR file or directory represented by this entry
is contained within the containing directory of the context JAR.
Use of "`../`" to navigate to the parent directory is not permitted,
except for the case when the context JAR is loaded from the file system.
Invalid entries are ignored. Valid entries are resolved against the context JAR.
If the resulting URL is invalid or refers to a resource that cannot be found,
then it is ignored. Duplicate URLs are ignored.
The resulting URLs are inserted into the class path,
immediately following the URL of the context JAR.
For example, given the following class path:
``` {style="MARGIN-LEFT: 40px"}
a.jar b.jar
```
If `b.jar` contained the following `Class-Path` manifest attribute:
``` {style="MARGIN-LEFT: 40px"}
Class-Path: lib/x.jar a.jar
```
Then the effective search path of such a `URLClassLoader` instance would be:
``` {style="MARGIN-LEFT: 40px"}
a.jar b.jar lib/x.jar
```
Of course, if `x.jar` had dependencies of its own then these would be
added according to the same rules and so on for each subsequent URL. In
the actual implementation, JAR file dependencies are processed lazily so
that the JAR files are not actually opened until needed.
A new JDK-specific system property:
Setting `-Djdk.net.URLClassPath.showIgnoredClassPathEntries` or `-Djdk.net.URLClassPath.showIgnoredClassPathEntries=true` will print a warning message for Class-Path entries that are ignored.