487 lines
21 KiB
Diff
487 lines
21 KiB
Diff
Subject: Backport JDK-8339460 CDS error when module is located in a directory with space in the name
|
|
|
|
---
|
|
src/hotspot/share/cds/classListParser.cpp | 6 +-
|
|
src/hotspot/share/cds/classListWriter.cpp | 4 +-
|
|
src/hotspot/share/cds/filemap.cpp | 4 +-
|
|
src/hotspot/share/classfile/classLoader.cpp | 50 +++++-
|
|
src/hotspot/share/classfile/classLoader.hpp | 4 +-
|
|
.../share/classfile/classLoaderExt.cpp | 12 +-
|
|
test/hotspot/jtreg/TEST.groups | 3 +-
|
|
.../cds/appcds/complexURI/ComplexURITest.java | 167 ++++++++++++++++++
|
|
.../appcds/complexURI/mypackage/Another.java | 27 +++
|
|
.../cds/appcds/complexURI/mypackage/Main.java | 37 ++++
|
|
10 files changed, 296 insertions(+), 18 deletions(-)
|
|
create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java
|
|
create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java
|
|
create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java
|
|
|
|
diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp
|
|
index a1e1a4131..0ba74ca4e 100644
|
|
--- a/src/hotspot/share/cds/classListParser.cpp
|
|
+++ b/src/hotspot/share/cds/classListParser.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2015, 2024, 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
|
|
@@ -472,7 +472,9 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
|
|
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
|
|
}
|
|
|
|
- InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL);
|
|
+ ResourceMark rm;
|
|
+ char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source));
|
|
+ InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL);
|
|
if (k->local_interfaces()->length() != _interfaces->length()) {
|
|
print_specified_interfaces();
|
|
print_actual_interfaces(k);
|
|
diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp
|
|
index 2a65ee51d..53637429a 100644
|
|
--- a/src/hotspot/share/cds/classListWriter.cpp
|
|
+++ b/src/hotspot/share/cds/classListWriter.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2021, 2024, 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
|
|
@@ -171,6 +171,8 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre
|
|
}
|
|
}
|
|
|
|
+ // NB: the string following "source: " is not really a proper file name, but rather
|
|
+ // a truncated URI referring to a file. It must be decoded after reading.
|
|
#ifdef _WINDOWS
|
|
// "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar"
|
|
stream->print(" source: %s", cfs->source() + 6);
|
|
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
|
|
index 023c0762a..f56920c64 100644
|
|
--- a/src/hotspot/share/cds/filemap.cpp
|
|
+++ b/src/hotspot/share/cds/filemap.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2003, 2024, 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
|
|
@@ -583,7 +583,7 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) {
|
|
|
|
// skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table()
|
|
ResourceMark rm;
|
|
- const char* file = ClassLoader::skip_uri_protocol(location->as_C_string());
|
|
+ const char* file = ClassLoader::uri_to_path(location->as_C_string());
|
|
for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) {
|
|
SharedClassPathEntry* ent = shared_path(i);
|
|
assert(ent->in_named_module(), "must be");
|
|
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
|
|
index 5e89673a5..74b9d9300 100644
|
|
--- a/src/hotspot/share/classfile/classLoader.cpp
|
|
+++ b/src/hotspot/share/classfile/classLoader.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 1997, 2024, 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
|
|
@@ -78,6 +78,9 @@
|
|
#include "utilities/macros.hpp"
|
|
#include "utilities/utf8.hpp"
|
|
|
|
+#include <stdlib.h>
|
|
+#include <ctype.h>
|
|
+
|
|
// Entry point in java.dll for path canonicalization
|
|
|
|
typedef int (*canonicalize_fn_t)(const char *orig, char *out, int len);
|
|
@@ -1223,7 +1226,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
|
}
|
|
|
|
#if INCLUDE_CDS
|
|
-char* ClassLoader::skip_uri_protocol(char* source) {
|
|
+static const char* skip_uri_protocol(const char* source) {
|
|
if (strncmp(source, "file:", 5) == 0) {
|
|
// file: protocol path could start with file:/ or file:///
|
|
// locate the char after all the forward slashes
|
|
@@ -1242,6 +1245,47 @@ char* ClassLoader::skip_uri_protocol(char* source) {
|
|
return source;
|
|
}
|
|
|
|
+static char decode_percent_encoded(const char *str, size_t& index) {
|
|
+ if (str[index] == '%'
|
|
+ && isxdigit(str[index + 1])
|
|
+ && isxdigit(str[index + 2])) {
|
|
+ char hex[3];
|
|
+ hex[0] = str[index + 1];
|
|
+ hex[1] = str[index + 2];
|
|
+ hex[2] = '\0';
|
|
+ index += 2;
|
|
+ return (char) strtol(hex, NULL, 16);
|
|
+ }
|
|
+ return str[index];
|
|
+}
|
|
+
|
|
+char* ClassLoader::uri_to_path(const char* uri) {
|
|
+ const size_t len = strlen(uri) + 1;
|
|
+ char* path = NEW_RESOURCE_ARRAY(char, len);
|
|
+
|
|
+ uri = skip_uri_protocol(uri);
|
|
+
|
|
+ if (strncmp(uri, "//", 2) == 0) {
|
|
+ // Skip the empty "authority" part
|
|
+ uri += 2;
|
|
+ }
|
|
+
|
|
+#ifdef _WINDOWS
|
|
+ if (uri[0] == '/') {
|
|
+ // Absolute path name on Windows does not begin with a slash
|
|
+ uri += 1;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ size_t path_index = 0;
|
|
+ for (size_t i = 0; i < strlen(uri); ++i) {
|
|
+ char decoded = decode_percent_encoded(uri, i);
|
|
+ path[path_index++] = decoded;
|
|
+ }
|
|
+ path[path_index] = '\0';
|
|
+ return path;
|
|
+}
|
|
+
|
|
// Record the shared classpath index and loader type for classes loaded
|
|
// by the builtin loaders at dump time.
|
|
void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
|
|
@@ -1275,7 +1319,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
|
|
// Save the path from the file: protocol or the module name from the jrt: protocol
|
|
// if no protocol prefix is found, path is the same as stream->source(). This path
|
|
// must be valid since the class has been successfully parsed.
|
|
- char* path = skip_uri_protocol(src);
|
|
+ const char* path = ClassLoader::uri_to_path(src);
|
|
assert(path != nullptr, "sanity");
|
|
for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) {
|
|
SharedClassPathEntry* ent = FileMapInfo::shared_path(i);
|
|
diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp
|
|
index 4cb196719..2f464063e 100644
|
|
--- a/src/hotspot/share/classfile/classLoader.hpp
|
|
+++ b/src/hotspot/share/classfile/classLoader.hpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 1997, 2024, 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
|
|
@@ -364,7 +364,7 @@ class ClassLoader: AllStatic {
|
|
// entries during shared classpath setup time.
|
|
static int num_module_path_entries();
|
|
static void exit_with_path_failure(const char* error, const char* message);
|
|
- static char* skip_uri_protocol(char* source);
|
|
+ static char* uri_to_path(const char* uri);
|
|
static void record_result(JavaThread* current, InstanceKlass* ik,
|
|
const ClassFileStream* stream, bool redefined);
|
|
#endif
|
|
diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp
|
|
index c9fd8173b..5334b118e 100644
|
|
--- a/src/hotspot/share/classfile/classLoaderExt.cpp
|
|
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2015, 2024, 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
|
|
@@ -98,12 +98,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable*
|
|
ModulePathsGatherer(JavaThread* current, GrowableArray<char*>* module_paths) :
|
|
_current(current), _module_paths(module_paths) {}
|
|
void do_module(ModuleEntry* m) {
|
|
- char* path = m->location()->as_C_string();
|
|
- if (strncmp(path, "file:", 5) == 0) {
|
|
- path = ClassLoader::skip_uri_protocol(path);
|
|
- char* path_copy = NEW_RESOURCE_ARRAY(char, strlen(path) + 1);
|
|
- strcpy(path_copy, path);
|
|
- _module_paths->append(path_copy);
|
|
+ char* uri = m->location()->as_C_string();
|
|
+ if (strncmp(uri, "file:", 5) == 0) {
|
|
+ char* path = ClassLoader::uri_to_path(uri);
|
|
+ _module_paths->append(path);
|
|
}
|
|
}
|
|
};
|
|
diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups
|
|
index 4923fbd5b..4c7352956 100644
|
|
--- a/test/hotspot/jtreg/TEST.groups
|
|
+++ b/test/hotspot/jtreg/TEST.groups
|
|
@@ -1,5 +1,5 @@
|
|
#
|
|
-# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved.
|
|
+# Copyright (c) 2013, 2024, 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
|
|
@@ -430,6 +430,7 @@ hotspot_cds_only = \
|
|
hotspot_appcds_dynamic = \
|
|
runtime/cds/appcds/ \
|
|
-runtime/cds/appcds/cacheObject \
|
|
+ -runtime/cds/appcds/complexURI \
|
|
-runtime/cds/appcds/customLoader \
|
|
-runtime/cds/appcds/dynamicArchive \
|
|
-runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \
|
|
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java
|
|
new file mode 100644
|
|
index 000000000..409e37e10
|
|
--- /dev/null
|
|
+++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java
|
|
@@ -0,0 +1,167 @@
|
|
+/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2024 JetBrains s.r.o.
|
|
+ * 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
|
|
+ * @summary Verifies that CDS works with jar located in directories
|
|
+ * with names that need escaping
|
|
+ * @bug 8339460
|
|
+ * @requires vm.cds
|
|
+ * @requires vm.cds.custom.loaders
|
|
+ * @requires vm.flagless
|
|
+ * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
|
|
+ * @compile mypackage/Main.java mypackage/Another.java
|
|
+ * @run main/othervm ComplexURITest
|
|
+ */
|
|
+
|
|
+import jdk.test.lib.process.OutputAnalyzer;
|
|
+import jdk.test.lib.process.ProcessTools;
|
|
+import jdk.test.lib.Platform;
|
|
+
|
|
+import java.io.File;
|
|
+import java.nio.file.Files;
|
|
+import java.nio.file.Path;
|
|
+
|
|
+public class ComplexURITest {
|
|
+ final static String moduleName = "mymodule";
|
|
+
|
|
+ public static void main(String[] args) throws Exception {
|
|
+ System.setProperty("test.noclasspath", "true");
|
|
+ String jarFile = JarBuilder.build(moduleName, "mypackage/Main", "mypackage/Another");
|
|
+
|
|
+ Path subDir = Path.of(".", "dir with space");
|
|
+ Files.createDirectory(subDir);
|
|
+ Path newJarFilePath = subDir.resolve(moduleName + ".jar");
|
|
+ Files.move(Path.of(jarFile), newJarFilePath);
|
|
+ jarFile = newJarFilePath.toString();
|
|
+
|
|
+ final String listFileName = "test-classlist.txt";
|
|
+ final String staticArchiveName = "test-static.jsa";
|
|
+ final String dynamicArchiveName = "test-dynamic.jsa";
|
|
+
|
|
+ // Verify static archive creation and use
|
|
+ File fileList = new File(listFileName);
|
|
+ delete(fileList.toPath());
|
|
+ File staticArchive = new File(staticArchiveName);
|
|
+ delete(staticArchive.toPath());
|
|
+
|
|
+ createClassList(jarFile, listFileName);
|
|
+ if (!fileList.exists()) {
|
|
+ throw new RuntimeException("No class list created at " + fileList);
|
|
+ }
|
|
+
|
|
+ createArchive(jarFile, listFileName, staticArchiveName);
|
|
+ if (!staticArchive.exists()) {
|
|
+ throw new RuntimeException("No shared classes archive created at " + staticArchive);
|
|
+ }
|
|
+
|
|
+ useArchive(jarFile, staticArchiveName);
|
|
+
|
|
+ // Verify dynamic archive creation and use
|
|
+ File dynamicArchive = new File(dynamicArchiveName);
|
|
+ delete(dynamicArchive.toPath());
|
|
+
|
|
+ createDynamicArchive(jarFile, dynamicArchiveName);
|
|
+ if (!dynamicArchive.exists()) {
|
|
+ throw new RuntimeException("No dynamic archive created at " + dynamicArchive);
|
|
+ }
|
|
+
|
|
+ testDynamicArchive(jarFile, dynamicArchiveName);
|
|
+ }
|
|
+
|
|
+ private static void delete(Path path) throws Exception {
|
|
+ if (Files.exists(path)) {
|
|
+ if (Platform.isWindows()) {
|
|
+ Files.setAttribute(path, "dos:readonly", false);
|
|
+ }
|
|
+ Files.delete(path);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void createClassList(String jarFile, String list) throws Exception {
|
|
+ String[] launchArgs = {
|
|
+ "-XX:DumpLoadedClassList=" + list,
|
|
+ "--module-path",
|
|
+ jarFile,
|
|
+ "--module",
|
|
+ moduleName + "/mypackage.Main"};
|
|
+ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
|
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, "create-list");
|
|
+ output.shouldHaveExitValue(0);
|
|
+ }
|
|
+
|
|
+ private static void createArchive(String jarFile, String list, String archive) throws Exception {
|
|
+ String[] launchArgs = {
|
|
+ "-Xshare:dump",
|
|
+ "-XX:SharedClassListFile=" + list,
|
|
+ "-XX:SharedArchiveFile=" + archive,
|
|
+ "--module-path",
|
|
+ jarFile,
|
|
+ "--module",
|
|
+ moduleName + "/mypackage.Main"};
|
|
+ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
|
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dump-archive");
|
|
+ output.shouldHaveExitValue(0);
|
|
+ }
|
|
+
|
|
+ private static void useArchive(String jarFile, String archive) throws Exception {
|
|
+ String[] launchArgs = {
|
|
+ "-Xshare:on",
|
|
+ "-XX:SharedArchiveFile=" + archive,
|
|
+ "--module-path",
|
|
+ jarFile,
|
|
+ "--module",
|
|
+ moduleName + "/mypackage.Main"};
|
|
+ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
|
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, "use-archive");
|
|
+ output.shouldHaveExitValue(0);
|
|
+ }
|
|
+
|
|
+ private static void createDynamicArchive(String jarFile, String archive) throws Exception {
|
|
+ String[] launchArgs = {
|
|
+ "-XX:ArchiveClassesAtExit=" + archive,
|
|
+ "--module-path",
|
|
+ jarFile,
|
|
+ "--module",
|
|
+ moduleName + "/mypackage.Main"};
|
|
+ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
|
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive");
|
|
+ output.shouldHaveExitValue(0);
|
|
+ }
|
|
+
|
|
+ private static void testDynamicArchive(String jarFile, String archive) throws Exception {
|
|
+ String[] launchArgs = {
|
|
+ "-XX:SharedArchiveFile=" + archive,
|
|
+ "-XX:+PrintSharedArchiveAndExit",
|
|
+ "--module-path",
|
|
+ jarFile,
|
|
+ "--module",
|
|
+ moduleName + "/mypackage.Main"};
|
|
+ ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs);
|
|
+ OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive");
|
|
+ output.shouldHaveExitValue(0);
|
|
+ output.shouldContain("archive is valid");
|
|
+ output.shouldContain(": mypackage.Main app_loader");
|
|
+ output.shouldContain(": mypackage.Another unregistered_loader");
|
|
+ }
|
|
+}
|
|
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java
|
|
new file mode 100644
|
|
index 000000000..106dfd490
|
|
--- /dev/null
|
|
+++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java
|
|
@@ -0,0 +1,27 @@
|
|
+/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2024 JetBrains s.r.o.
|
|
+ * 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 mypackage;
|
|
+
|
|
+public class Another {
|
|
+}
|
|
diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java
|
|
new file mode 100644
|
|
index 000000000..fdb79e895
|
|
--- /dev/null
|
|
+++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java
|
|
@@ -0,0 +1,37 @@
|
|
+/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 2024 JetBrains s.r.o.
|
|
+ * 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 mypackage;
|
|
+
|
|
+import java.net.URL;
|
|
+import java.net.URLClassLoader;
|
|
+
|
|
+public class Main {
|
|
+ public static void main(String[] args) throws Exception {
|
|
+ URL url1 = Main.class.getProtectionDomain().getCodeSource().getLocation();
|
|
+ System.out.println("Will load Another from " + url1);
|
|
+ ClassLoader cl = URLClassLoader.newInstance(new URL[] { url1 }, null);
|
|
+ var anotherClass = cl.loadClass("mypackage.Another");
|
|
+ System.out.println("Class " + anotherClass + " loaded successfully");
|
|
+ }
|
|
+}
|
|
--
|
|
2.33.0
|
|
|