--- old/src/java.base/share/classes/java/lang/ClassLoader.java 2016-10-26 14:59:24.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/ClassLoader.java 2016-10-26 14:59:24.000000000 -0700 @@ -1681,6 +1681,15 @@ * this method during startup should take care not to cache the return * value until the system is fully initialized. * + *

The class path used by the built-in system class loader is determined + * by the system property "{@code java.class.path}" during early + * initialization of the VM. If the system property is not defined, + * or its value is an empty string, then there is no class path + * when the initial module is a module on the application module path, + * i.e. a named module. If the initial module is not on + * the application module path then the class path defaults to + * the current working directory. + * * @return The system ClassLoader for delegation * * @throws SecurityException --- old/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java 2016-10-26 14:59:25.000000000 -0700 +++ new/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java 2016-10-26 14:59:24.000000000 -0700 @@ -69,16 +69,17 @@ bcp = toURLClassPath(s); // we have a class path if -cp is specified or -m is not specified. - // If neither is specified then default to -cp . + // If neither is specified then default to -cp + // If -cp is not specified and -m is specified, the value of + // java.class.path is an empty string if defined, then no class path. URLClassPath ucp = null; String mainMid = System.getProperty("jdk.module.main"); String cp = System.getProperty("java.class.path"); - if (mainMid == null && cp == null) + if (cp == null) cp = ""; - if (cp != null) + if (mainMid == null || cp.length() > 0) ucp = toURLClassPath(cp); - // create the class loaders BOOT_LOADER = new BootClassLoader(bcp); PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER); --- old/src/java.base/share/native/launcher/defines.h 2016-10-26 14:59:25.000000000 -0700 +++ new/src/java.base/share/native/launcher/defines.h 2016-10-26 14:59:25.000000000 -0700 @@ -51,16 +51,6 @@ static char* const_progname = NULL; #endif static const char* const_jargs[] = JAVA_ARGS; -/* - * ApplicationHome is prepended to each of these entries; the resulting - * strings are concatenated (separated by PATH_SEPARATOR) and used as the - * value of -cp option to the launcher. - */ -#ifndef APP_CLASSPATH -static const char* const_appclasspath[] = { NULL }; -#else -static const char* const_appclasspath[] = APP_CLASSPATH; -#endif /* APP_CLASSPATH */ #else /* !JAVA_ARGS */ #define HAS_JAVA_ARGS JNI_FALSE static const char* const_progname = "java"; --- old/src/java.base/share/native/launcher/main.c 2016-10-26 14:59:26.000000000 -0700 +++ new/src/java.base/share/native/launcher/main.c 2016-10-26 14:59:26.000000000 -0700 @@ -83,7 +83,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) { - int margc, appclassc; + int margc; char** margv; const jboolean const_javaw = JNI_TRUE; @@ -93,7 +93,7 @@ int main(int argc, char **argv) { - int margc, appclassc; + int margc; char** margv; const jboolean const_javaw = JNI_FALSE; #endif /* JAVAW */ @@ -148,14 +148,9 @@ margv = args->elements; } #endif /* WIN32 */ - if (const_appclasspath[0] == NULL) { - appclassc = 0; - } else { - appclassc = sizeof(const_appclasspath) / sizeof(char *); - } return JLI_Launch(margc, margv, sizeof(const_jargs) / sizeof(char *), const_jargs, - appclassc, const_appclasspath, + 0, NULL, VERSION_STRING, DOT_VERSION, (const_progname != NULL) ? const_progname : *margv, --- old/src/java.base/share/native/libjli/java.c 2016-10-26 14:59:27.000000000 -0700 +++ new/src/java.base/share/native/libjli/java.c 2016-10-26 14:59:27.000000000 -0700 @@ -1664,19 +1664,21 @@ AddOption(apphome, NULL); /* How big is the application's classpath? */ - size = 40; /* 40: "-Djava.class.path=" */ - for (i = 0; i < cpathc; i++) { - size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */ - } - appcp = (char *)JLI_MemAlloc(size + 1); - JLI_StrCpy(appcp, "-Djava.class.path="); - for (i = 0; i < cpathc; i++) { - JLI_StrCat(appcp, home); /* c:\program files\myapp */ - JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */ - JLI_StrCat(appcp, separator); /* ; */ + if (cpathc > 0) { + size = 40; /* 40: "-Djava.class.path=" */ + for (i = 0; i < cpathc; i++) { + size += (int)JLI_StrLen(home) + (int)JLI_StrLen(cpathv[i]) + 1; /* 1: separator */ + } + appcp = (char *)JLI_MemAlloc(size + 1); + JLI_StrCpy(appcp, "-Djava.class.path="); + for (i = 0; i < cpathc; i++) { + JLI_StrCat(appcp, home); /* c:\program files\myapp */ + JLI_StrCat(appcp, cpathv[i]); /* \lib\myapp.jar */ + JLI_StrCat(appcp, separator); /* ; */ + } + appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */ + AddOption(appcp, NULL); } - appcp[JLI_StrLen(appcp)-1] = '\0'; /* remove trailing path separator */ - AddOption(appcp, NULL); return JNI_TRUE; } --- /dev/null 2016-10-26 14:59:28.000000000 -0700 +++ new/test/tools/launcher/modules/classpath/JavaClassPathTest.java 2016-10-26 14:59:28.000000000 -0700 @@ -0,0 +1,138 @@ +/* + * 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. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import jdk.testlibrary.JDKToolFinder; +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +/** + * @test + * @bug 8168205 + * @summary Test the default class path if -Djava.class.path is set + * @library /lib/testlibrary + * @modules jdk.compiler + * @build CompilerUtils jdk.testlibrary.* + * @run testng JavaClassPathTest + */ + +public class JavaClassPathTest { + private static String JAVA_TOOL = JDKToolFinder.getJDKTool("java"); + + private static final Path SRC_DIR = Paths.get(System.getProperty("test.src"), + "src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final String TEST_MODULE = "m"; + private static final String TEST_MAIN = "jdk.test.Main"; + + @BeforeTest + public void setup() throws Exception { + boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE)); + assertTrue(compiled, "module " + TEST_MODULE + " did not compile"); + + // add the class and a resource to the current working directory + Path file = Paths.get("jdk/test/Main.class"); + Files.createDirectories(file.getParent()); + Files.copy(MODS_DIR.resolve(TEST_MODULE).resolve(file), file); + + Path res = Paths.get("jdk/test/res.properties"); + Files.createFile(res); + } + + @DataProvider(name = "classpath") + public Object[][] classpath() { + return new Object[][]{ + // true indicates that class path default to current working directory + { "", true }, + { "-Djava.class.path", true }, + { "-Djava.class.path=", true }, + { "-Djava.class.path=.", true }, + }; + } + + @Test(dataProvider = "classpath") + public void testUnnamedModule(String option, boolean expected) throws Throwable { + + List cmds = new ArrayList<>(); + cmds.add(JAVA_TOOL); + if (!option.isEmpty()) { + cmds.add(option); + } + cmds.add(TEST_MAIN); + cmds.add(Boolean.toString(expected)); + + assertTrue(execute(cmds).getExitValue() == 0); + } + + @DataProvider(name = "moduleAndClassPath") + public Object[][] moduleAndClassPath() { + return new Object[][]{ + // true indicates that class path default to current working directory + { "", false }, + { "-Djava.class.path", false }, + { "-Djava.class.path=", false }, + { "-Djava.class.path=.", true }, + }; + } + + @Test(dataProvider = "moduleAndClassPath") + public void testNamedModule(String option, boolean expected) throws Throwable { + String javapath = JDKToolFinder.getJDKTool("java"); + + List cmds = new ArrayList<>(); + cmds.add(javapath); + if (!option.isEmpty()) { + cmds.add(option); + } + cmds.add("--module-path"); + cmds.add(MODS_DIR.toString()); + cmds.add("-m"); + cmds.add(TEST_MODULE + "/" + TEST_MAIN); + cmds.add(Boolean.toString(expected)); + + assertTrue(execute(cmds).getExitValue() == 0); + } + + private OutputAnalyzer execute(List cmds) throws Throwable { + ProcessBuilder pb = new ProcessBuilder(cmds); + Map env = pb.environment(); + // remove CLASSPATH environment variable + String value = env.remove("CLASSPATH"); + return ProcessTools.executeCommand(pb) + .outputTo(System.out) + .errorTo(System.out); + } + +} --- /dev/null 2016-10-26 14:59:29.000000000 -0700 +++ new/test/tools/launcher/modules/classpath/src/m/jdk/test/Main.java 2016-10-26 14:59:29.000000000 -0700 @@ -0,0 +1,45 @@ +/** + * 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. + */ + +package jdk.test; + +import java.net.URL; + +public class Main { + static final String JAVA_CLASS_PATH = "java.class.path"; + + public static void main(String[] args) throws Exception { + String value = System.getProperty(JAVA_CLASS_PATH); + if (value == null) { + throw new RuntimeException(JAVA_CLASS_PATH + " is expected non-null" + + " for compatibility"); + } + + boolean expected = args[0].equals("true"); + ClassLoader loader = ClassLoader.getSystemClassLoader(); + URL url = loader.getResource("jdk/test/res.properties"); + if ((expected && url == null) || (!expected && url != null)) { + throw new RuntimeException("URL: " + url + " expected non-null: " + expected); + } + } +} --- /dev/null 2016-10-26 14:59:30.000000000 -0700 +++ new/test/tools/launcher/modules/classpath/src/m/module-info.java 2016-10-26 14:59:29.000000000 -0700 @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m { +} +