Attached patch with tests so first the bug for java11 can be fixed and
backported.
Would be nice if someone can guide me how to continue with this and/or
can reply on my previous questions.

Op di 5 mrt. 2019 om 07:11 schreef Donald Kwakkel <[email protected]>:
>
> > On 02/28/2019 01:06 PM, Alan Bateman wrote:
> > > On 28/02/2019 20:58, Jonathan Gibbons wrote:
> > >> Looking at the revised JAR specification, approved in [1], it is
> > >> disappointing that the spec contains text which is specific to
> > >> a JAR file being used in a classloader:
> > >>
> > >> |The resulting URLs are inserted into the search path of the class
> > >> loader opening the context JAR immediately following the path of the
> > >> context JAR. Any duplicated URLs are omitted.|
> > >>
> > >> That text would seem not to apply to javac and other tools that may wish
> > >> to process the class files in a JAR file.
> > > That should be fixed as it should apply at compile-time too.
> > >
> > > -Alan
> >
> > |Agreed it might be good to fix it if possible. All the preceding text
> > is good, and can be handled by javac. The only questionable bit is the
> > text "Any duplicated URLs are omitted" which could be moved up a bit in
> > the spec to a new paragraph, and maybe rephrased to use "ignored"
> > instead of "omitted". If that were done, all the stuff about class
> > loaders could be taken as non-normative text.
>
> So if I am correct the answer to Question 2 is: Yes, behavior must be the 
> same.
>
> What are the next steps to take for this? And can someone also answer my
> other questions?:
>
> Question 1: Where can I find the tests for these changes?
> Question 2: Where should the common code for this be located?
> Question 3: Is it an idea to first implement below patch and backport
> that, and in addition as new ticket implement the new behaviour also
> for javac?
> Question 4:Is this they way to do it, or is there a better way to
> provide debug information to users running javac?
diff -r d489081c5650 src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java	Sat Mar 02 18:09:18 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/FSInfo.java	Wed Mar 13 22:31:17 2019 +0100
@@ -26,7 +26,10 @@
 package com.sun.tools.javac.file;
 
 import java.io.IOException;
-import java.nio.file.FileSystems;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.spi.FileSystemProvider;
@@ -90,7 +93,6 @@
     }
 
     public List<Path> getJarClassPath(Path file) throws IOException {
-        Path parent = file.getParent();
         try (JarFile jarFile = new JarFile(file.toFile())) {
             Manifest man = jarFile.getManifest();
             if (man == null)
@@ -100,22 +102,27 @@
             if (attr == null)
                 return Collections.emptyList();
 
-            String path = attr.getValue(Attributes.Name.CLASS_PATH);
-            if (path == null)
+            String classpath = attr.getValue(Attributes.Name.CLASS_PATH);
+            if (classpath == null)
                 return Collections.emptyList();
 
-            List<Path> list = new ArrayList<>();
+            // TODO: Must use the same code as jdk.internal.loader.URLClassPath.JarLoader.parseClassPath(base, path)
+            StringTokenizer st = new StringTokenizer(classpath);
+            List<Path> paths = new ArrayList<>(st.countTokens());
+            while (st.hasMoreTokens()) {
+                String path = st.nextToken();
+                try {
+                    // Use getCanonicalFile just as jdk.internal.loader.URLClassPath.toFileURL
+                    URL base = file.toFile().getCanonicalFile().toURI().toURL();
+                    URI uri = new URL(base, path).toURI();
 
-            for (StringTokenizer st = new StringTokenizer(path);
-                 st.hasMoreTokens(); ) {
-                String elt = st.nextToken();
-                Path f = FileSystems.getDefault().getPath(elt);
-                if (!f.isAbsolute() && parent != null)
-                    f = parent.resolve(f).toAbsolutePath();
-                list.add(f);
+                    // Should return uri, see comment on com.sun.tools.javac.file.Locations.SearchPath.addJarClassPath
+                    paths.add(Path.of(uri)); 
+                } catch (MalformedURLException | URISyntaxException e) {
+                    System.err.println("Class-Path entry: \"" + path + "\" ignored in JAR file \"" + file + "\": " + e.getMessage());
+                }
             }
-
-            return list;
+            return paths;
         }
     }
 
diff -r d489081c5650 test/langtools/tools/javac/8218268/ManifestClassPathTest.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/8218268/ManifestClassPathTest.java	Wed Mar 13 22:31:17 2019 +0100
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8821826
+ * @summary : Test javac handles Manifest Class-Path entries the same as java
+ * @library /tools/lib
+ * @modules jdk.compiler/com.sun.tools.javac.api
+ *          jdk.compiler/com.sun.tools.javac.main
+ *          jdk.compiler/com.sun.tools.javac.util
+ * @build toolbox.ToolBox toolbox.TestRunner toolbox.JavacTask toolbox.JavaTask toolbox.JarTask
+ * @run main ManifestClassPathTest
+ */
+
+import static java.io.File.pathSeparator;
+import static java.io.File.separator;
+import static java.nio.file.Files.createLink;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import toolbox.JarTask;
+import toolbox.JavaTask;
+import toolbox.JavacTask;
+import toolbox.Task;
+import toolbox.Task.Expect;
+import toolbox.TestRunner;
+import toolbox.ToolBox;
+
+public class ManifestClassPathTest extends TestRunner {
+	private static final String JAR_NAME = "j.jar";
+
+	private ToolBox tb;
+
+	public static void main(String... args) throws Exception {
+		new ManifestClassPathTest().runTests();
+	}
+
+	public ManifestClassPathTest() {
+		super(System.err);
+		tb = new ToolBox();
+	}
+
+	@Override
+	public void runTests() throws Exception {
+		runTests(m -> new Object[] { Paths.get(m.getName()) });
+	}
+
+	@Test
+	public void test(Path base) throws Exception {
+		String dirName = "x y";
+		String jarOutDirectory = "x%20y";
+
+		Path current = base.resolve("out");
+		Path jarPath = createJar(current, dirName);
+
+		Path src = current.resolve("src");
+		tb.writeJavaFiles(src, "public class A { public static void main(String[] args) { J.test(); }}");
+
+		// Test 1: Compile and run with jar on classpath
+		doTest(jarPath.toString(), src);
+
+		// Test 2: Compile and run with jar as relative path via classpath manifest
+		String jarRelativePath = jarOutDirectory + separator + JAR_NAME;
+		doTest(createManifestJar(current, jarRelativePath), src);
+
+		// Test 3: Compile and run with jar as absolute (url) path via classpath
+		// manifest
+		String path = current.toFile().getAbsolutePath() + separator + jarRelativePath;
+		doTest(createManifestJar(current, path), src);
+
+		// Test 4: Compile and run with jar as url via classpath manifest
+		String urlPath = path.replace(separator, "/");
+		doTest(createManifestJar(current, "file:" + urlPath), src);
+		doTest(createManifestJar(current, "file://" + urlPath), src);
+
+		// Test 5: garbage before, right jar must still be used
+		doTest(createManifestJar(current, "notexisting://garbage " + jarRelativePath), src);
+
+		// Test 6: linked jar
+		String linkJar = "l.jar";
+		createLink(current.resolve(linkJar), current.resolve(dirName + separator + JAR_NAME));
+		doTest(createManifestJar(current, linkJar), src);
+
+		// Test 7: wrong classpath
+		doTest(createManifestJar(current, "notexisting://garbage"), src, Task.Expect.FAIL);
+	}
+
+	private void doTest(String classpath, Path src) {
+		doTest(classpath, src, Task.Expect.SUCCESS);
+	}
+
+	private void doTest(String classpath, Path src, Expect expectedExit) {
+		String cp = classpath + pathSeparator + src;
+		System.err.println("javac -cp " + cp + src.resolve("A.java"));
+
+		new JavacTask(tb, Task.Mode.EXEC).classpath(cp).files(src.resolve("A.java")).run(expectedExit);
+		// Bug: jdk.net.URLClassPath.disableClassPathURLCheck meaning is inverted and
+		// should be default enabled according to spec
+		new JavaTask(tb).vmOptions("-Djdk.net.URLClassPath.disableClassPathURLCheck=false").classpath(cp).className("A")
+				.run(expectedExit);
+	}
+
+	private Path createJar(Path current, String jarOutDirectory) throws IOException {
+		Path jarSrc = current.resolve("jarSrc");
+		tb.writeJavaFiles(jarSrc, "public class J { public static void test() { System.out.println(\"OK\"); }}");
+		Path jarOut = current.resolve(jarOutDirectory);
+		tb.createDirectories(jarOut);
+		Path jarFile = jarOut.resolve(JAR_NAME);
+
+		new JarTask(tb, jarFile).baseDir(jarSrc).files("J.java").run().writeAll();
+		return jarFile;
+	}
+
+	private String createManifestJar(Path current, String classpath) throws IOException {
+		Path jarCpPath = current.resolve("jcp.jar");
+		new JarTask(tb, jarCpPath).manifest("Class-Path: " + classpath + "\n\n").run().writeAll();
+		return jarCpPath.toString();
+	}
+}
+

Reply via email to