1 /*
2 * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test
26 * @bug 8142968 8300228
27 * @library /test/lib
28 * @modules java.base/jdk.internal.module
29 * jdk.compiler
30 * jdk.jlink
31 * @build ModuleReaderTest
32 * jdk.test.lib.compiler.CompilerUtils
33 * jdk.test.lib.util.JarUtils
34 * @run junit ModuleReaderTest
35 * @summary Basic tests for java.lang.module.ModuleReader
36 */
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.lang.module.ModuleFinder;
42 import java.lang.module.ModuleReader;
43 import java.lang.module.ModuleReference;
44 import java.net.URI;
45 import java.net.URL;
46 import java.net.URLConnection;
47 import java.nio.ByteBuffer;
48 import java.nio.file.Files;
49 import java.nio.file.Path;
50 import java.nio.file.Paths;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Optional;
54 import java.util.Set;
55 import java.util.spi.ToolProvider;
56 import java.util.stream.Stream;
57
58 import jdk.internal.module.ModulePath;
59 import jdk.test.lib.compiler.CompilerUtils;
60 import jdk.test.lib.util.JarUtils;
61 import org.junit.jupiter.api.BeforeAll;
62 import org.junit.jupiter.api.Test;
63
64 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
65 import static org.junit.jupiter.api.Assertions.assertEquals;
66 import static org.junit.jupiter.api.Assertions.assertFalse;
67 import static org.junit.jupiter.api.Assertions.assertThrows;
68 import static org.junit.jupiter.api.Assertions.assertTrue;
69
70 public class ModuleReaderTest {
71 private static final String TEST_SRC = System.getProperty("test.src");
72
73 private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
74 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
75 private static final Path MODS_DIR = Paths.get("mods");
76
77 // the module name of the base module
78 private static final String BASE_MODULE = "java.base";
79
80 // the module name of the test module
81 private static final String TEST_MODULE = "m";
82
83 // resources in the base module
84 private static final String[] BASE_RESOURCES = {
85 "java/lang/Object.class"
86 };
87
88 // (directory) resources that may be in the base module
89 private static final String[] MAYBE_BASE_RESOURCES = {
90 "java",
91 "java/",
92 "java/lang",
93 "java/lang/",
94 };
95
102 "//java/lang",
103 "java//lang",
104 "/java/lang/Object.class",
105 "//java/lang/Object.class",
106 "java/lang/Object.class/",
107 "java//lang//Object.class",
108 "./java/lang/Object.class",
109 "java/./lang/Object.class",
110 "java/lang/./Object.class",
111 "../java/lang/Object.class",
112 "java/../lang/Object.class",
113 "java/lang/../Object.class",
114
115 // junk resource names
116 "java\u0000",
117 "C:java",
118 "C:\\java",
119 "java\\lang\\Object.class"
120 };
121
122 // resources in test module (can't use module-info.class as a test
123 // resource as it will be modified by the jmod tool)
124 private static final String[] TEST_RESOURCES = {
125 "p/Main.class"
126 };
127
128 // (directory) resources that may be in the test module
129 private static final String[] MAYBE_TEST_RESOURCES = {
130 "p",
131 "p/"
132 };
133
134 // resource names that should not be found in the test module
135 private static final String[] NOT_TEST_RESOURCES = {
136 "NotFound",
137 "/p",
138 "//p",
139 "/p/Main.class",
140 "//p/Main.class",
141 "p/Main.class/",
142 "p//Main.class",
143 "./p/Main.class",
144 "p/./Main.class",
145 "../p/Main.class",
146 "p/../p/Main.class",
147
148 // junk resource names
149 "p\u0000",
150 "C:p",
151 "C:\\p",
152 "p\\Main.class"
153 };
154
155 @BeforeAll
156 public static void compileTestModule() throws Exception {
157 // javac -d mods/$TESTMODULE src/$TESTMODULE/**
158 boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
159 MODS_DIR.resolve(TEST_MODULE));
160 assertTrue(compiled, "test module did not compile");
161 }
162
163 /**
164 * Test ModuleReader with module in runtime image.
165 */
166 @Test
167 public void testImage() throws IOException {
168 ModuleFinder finder = ModuleFinder.ofSystem();
169 ModuleReference mref = finder.find(BASE_MODULE).get();
170 ModuleReader reader = mref.open();
171
172 try (reader) {
173
174 for (String name : BASE_RESOURCES) {
175 byte[] expectedBytes;
176 Module baseModule = Object.class.getModule();
177 try (InputStream in = baseModule.getResourceAsStream(name)) {
178 expectedBytes = in.readAllBytes();
179 }
180
205 assertThrows(NullPointerException.class, () -> reader.find(null));
206 assertThrows(NullPointerException.class, () -> reader.open(null));
207 assertThrows(NullPointerException.class, () -> reader.read(null));
208 assertThrows(NullPointerException.class, () -> reader.release(null));
209 }
210
211 // test closed ModuleReader
212 assertThrows(IOException.class, () -> reader.open(BASE_RESOURCES[0]));
213 assertThrows(IOException.class, () -> reader.read(BASE_RESOURCES[0]));
214 assertThrows(IOException.class, reader::list);
215 }
216
217 /**
218 * Test ModuleReader with exploded module.
219 */
220 @Test
221 public void testExplodedModule() throws IOException {
222 test(MODS_DIR);
223 }
224
225 /**
226 * Test ModuleReader with module in modular JAR.
227 */
228 @Test
229 public void testModularJar() throws IOException {
230 Path dir = Files.createTempDirectory(USER_DIR, "mlib");
231
232 // jar cf mlib/${TESTMODULE}.jar -C mods .
233 JarUtils.createJarFile(dir.resolve("m.jar"),
234 MODS_DIR.resolve(TEST_MODULE));
235
236 test(dir);
237 }
238
239 /**
240 * Test ModuleReader with module in a JMOD file.
241 */
242 @Test
243 public void testJMod() throws IOException {
244 Path dir = Files.createTempDirectory(USER_DIR, "mlib");
245
246 // jmod create --class-path mods/${TESTMODULE} mlib/${TESTMODULE}.jmod
247 String cp = MODS_DIR.resolve(TEST_MODULE).toString();
248 String jmod = dir.resolve("m.jmod").toString();
249 String[] args = { "create", "--class-path", cp, jmod };
250 ToolProvider jmodTool = ToolProvider.findFirst("jmod")
251 .orElseThrow(() ->
252 new RuntimeException("jmod tool not found")
253 );
254 assertEquals(0, jmodTool.run(System.out, System.out, args), "jmod tool failed");
255
256 test(dir);
257 }
258
259 /**
260 * The test module is found on the given module path. Open a ModuleReader
261 * to the test module and test the reader.
262 */
263 void test(Path mp) throws IOException {
264 ModuleFinder finder = ModulePath.of(Runtime.version(), true, mp);
265 ModuleReference mref = finder.find(TEST_MODULE).get();
266 ModuleReader reader = mref.open();
267
268 try (reader) {
269
|
1 /*
2 * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @bug 8142968 8300228
27 * @library /test/lib
28 * @modules java.base/jdk.internal.module
29 * jdk.compiler
30 * jdk.jlink
31 * @build ModuleReaderTest
32 * jdk.test.lib.compiler.CompilerUtils
33 * jdk.test.lib.util.JarUtils
34 * @run junit ModuleReaderTest
35 * @summary Basic tests for java.lang.module.ModuleReader
36 */
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.lang.module.ModuleFinder;
42 import java.lang.module.ModuleReader;
43 import java.lang.module.ModuleReference;
44 import java.net.URI;
45 import java.net.URL;
46 import java.net.URLConnection;
47 import java.nio.ByteBuffer;
48 import java.nio.charset.StandardCharsets;
49 import java.nio.file.Files;
50 import java.nio.file.Path;
51 import java.nio.file.Paths;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Optional;
55 import java.util.Set;
56 import java.util.spi.ToolProvider;
57 import java.util.stream.Stream;
58
59 import jdk.internal.module.ModulePath;
60 import jdk.test.lib.Utils;
61 import jdk.test.lib.compiler.CompilerUtils;
62 import jdk.test.lib.util.JarUtils;
63 import org.junit.jupiter.api.BeforeAll;
64 import org.junit.jupiter.api.Test;
65
66 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
67 import static org.junit.jupiter.api.Assertions.assertEquals;
68 import static org.junit.jupiter.api.Assertions.assertFalse;
69 import static org.junit.jupiter.api.Assertions.assertThrows;
70 import static org.junit.jupiter.api.Assertions.assertTrue;
71
72 public class ModuleReaderTest {
73 private static final Path MODS_DIR = Paths.get("mods");
74
75 // the module name of the base module
76 private static final String BASE_MODULE = "java.base";
77
78 // the module name of the test module
79 private static final String TEST_MODULE = "m";
80
81 // resources in the base module
82 private static final String[] BASE_RESOURCES = {
83 "java/lang/Object.class"
84 };
85
86 // (directory) resources that may be in the base module
87 private static final String[] MAYBE_BASE_RESOURCES = {
88 "java",
89 "java/",
90 "java/lang",
91 "java/lang/",
92 };
93
100 "//java/lang",
101 "java//lang",
102 "/java/lang/Object.class",
103 "//java/lang/Object.class",
104 "java/lang/Object.class/",
105 "java//lang//Object.class",
106 "./java/lang/Object.class",
107 "java/./lang/Object.class",
108 "java/lang/./Object.class",
109 "../java/lang/Object.class",
110 "java/../lang/Object.class",
111 "java/lang/../Object.class",
112
113 // junk resource names
114 "java\u0000",
115 "C:java",
116 "C:\\java",
117 "java\\lang\\Object.class"
118 };
119
120 // Resources in test module (can't use module-info.class as a test
121 // resource as it will be modified by the jmod tool)
122 private static final String[] TEST_RESOURCES = {
123 "p/Main.class",
124 "p/test.txt"
125 };
126
127 // (directory) resources that may be in the test module
128 private static final String[] MAYBE_TEST_RESOURCES = {
129 "p",
130 "p/"
131 };
132
133 // resource names that should not be found in the test module
134 private static final String[] NOT_TEST_RESOURCES = {
135 "NotFound",
136 "/p",
137 "//p",
138 "/p/Main.class",
139 "//p/Main.class",
140 "p/Main.class/",
141 "p//Main.class",
142 "./p/Main.class",
143 "p/./Main.class",
144 "../p/Main.class",
145 "p/../p/Main.class",
146
147 // junk resource names
148 "p\u0000",
149 "C:p",
150 "C:\\p",
151 "p\\Main.class"
152 };
153
154 @BeforeAll
155 public static void compileTestModules() throws Exception {
156 // Write simplest module-info class.
157 Path srcDir = Path.of("src", TEST_MODULE);
158 Files.createDirectories(srcDir);
159 Files.writeString(srcDir.resolve("module-info.java"), "module " + TEST_MODULE + " {}");
160
161 // Write and compile test class "p.Main".
162 Path pkgPath = Path.of("p");
163 Path javaSrc = srcDir.resolve(pkgPath).resolve("Main.java");
164 Files.createDirectories(javaSrc.getParent());
165 Files.writeString(javaSrc,
166 """
167 package p;
168 public class Main {
169 public static void main(String[] args) { }
170 }
171 """);
172
173 // javac -d <outDir> <srcDir>/**
174 Path outDir = MODS_DIR.resolve(TEST_MODULE);
175 boolean compiled = CompilerUtils.compile(srcDir, outDir);
176 assertTrue(compiled, "test module did not compile");
177
178 // Add two versions of a resource for preview mode testing.
179 Files.writeString(outDir.resolve(pkgPath).resolve("test.txt"), "Normal Version");
180 Path previewDir = outDir.resolve("META-INF", "preview").resolve(pkgPath);
181 Files.createDirectories(previewDir);
182 Files.writeString(previewDir.resolve("test.txt"), "Preview Version");
183 }
184
185 /**
186 * Test ModuleReader with module in runtime image.
187 */
188 @Test
189 public void testImage() throws IOException {
190 ModuleFinder finder = ModuleFinder.ofSystem();
191 ModuleReference mref = finder.find(BASE_MODULE).get();
192 ModuleReader reader = mref.open();
193
194 try (reader) {
195
196 for (String name : BASE_RESOURCES) {
197 byte[] expectedBytes;
198 Module baseModule = Object.class.getModule();
199 try (InputStream in = baseModule.getResourceAsStream(name)) {
200 expectedBytes = in.readAllBytes();
201 }
202
227 assertThrows(NullPointerException.class, () -> reader.find(null));
228 assertThrows(NullPointerException.class, () -> reader.open(null));
229 assertThrows(NullPointerException.class, () -> reader.read(null));
230 assertThrows(NullPointerException.class, () -> reader.release(null));
231 }
232
233 // test closed ModuleReader
234 assertThrows(IOException.class, () -> reader.open(BASE_RESOURCES[0]));
235 assertThrows(IOException.class, () -> reader.read(BASE_RESOURCES[0]));
236 assertThrows(IOException.class, reader::list);
237 }
238
239 /**
240 * Test ModuleReader with exploded module.
241 */
242 @Test
243 public void testExplodedModule() throws IOException {
244 test(MODS_DIR);
245 }
246
247 /**
248 * Test equivalent of the system ModuleReader with preview mode. This differs
249 * in behavior to other "exploded modules" because it supports preview mode.
250 * It also hides preview resources when preview mode is enabled.
251 *
252 * <p>Note: When preview mode is not enabled, preview resources are visible
253 * via their un-mapped path. This is not the same behavior as things like
254 * the JRT filesystem or non-exploded module readers, in which preview paths
255 * are always hidden.
256 */
257 @Test
258 public void testExplodedSystemModule() throws IOException {
259 ModuleFinder normalFinder = ModulePath.of(/* modulePatcher */ null, /* previewMode */ false, MODS_DIR);
260 try (ModuleReader reader = normalFinder.find(TEST_MODULE).get().open()) {
261 assertEquals("Normal Version", assertUtf8Resource(reader, "p/test.txt"));
262 // This file is not visible in an exploded image when using JRT filesystem.
263 assertEquals("Preview Version", assertUtf8Resource(reader, "META-INF/preview/p/test.txt"));
264 }
265 ModuleFinder previewFinder = ModulePath.of(/* modulePatcher */ null, /* previewMode */ true, MODS_DIR);
266 try (ModuleReader reader = previewFinder.find(TEST_MODULE).get().open()) {
267 assertEquals("Preview Version", assertUtf8Resource(reader, "p/test.txt"));
268 assertFalse(reader.find("META-INF/preview/p/test.txt").isPresent(), "unexpected preview resource");
269 }
270 }
271
272 private static String assertUtf8Resource(ModuleReader reader, String name) throws IOException {
273 // Check the resource can be found with the expected URI.
274 Optional<URI> uri = reader.find(name);
275 assertTrue(uri.isPresent(), "resource not found: " + name);
276 assertTrue(uri.get().getPath().endsWith(name), "unexpected path: " + uri.get());
277
278 // Open and read all resource bytes.
279 Optional<InputStream> is = reader.open(name);
280 assertTrue(is.isPresent(), "resource cannot be opened: " + name);
281 byte[] bytes = is.get().readAllBytes();
282
283 // Cross-check that read() returns the same bytes as open().
284 Optional<ByteBuffer> buffer = reader.read(name);
285 assertTrue(buffer.isPresent(), "resource cannot be read: " + name);
286 assertArrayEquals(buffer.get().array(), bytes, "resource bytes differ: " + name);
287 // Return the string of the UTF-8 bytes for checking the actual content.
288 return new String(bytes, StandardCharsets.UTF_8);
289 }
290
291 /**
292 * Test ModuleReader with module in modular JAR.
293 */
294 @Test
295 public void testModularJar() throws IOException {
296 Path dir = Utils.createTempDirectory("mlib");
297
298 // jar cf mlib/${TESTMODULE}.jar -C mods .
299 JarUtils.createJarFile(dir.resolve(TEST_MODULE + ".jar"),
300 MODS_DIR.resolve(TEST_MODULE));
301
302 test(dir);
303 }
304
305 /**
306 * Test ModuleReader with module in a JMOD file.
307 */
308 @Test
309 public void testJMod() throws IOException {
310 Path dir = Utils.createTempDirectory("mlib");
311
312 // jmod create --class-path mods/${TESTMODULE} mlib/${TESTMODULE}.jmod
313 String cp = MODS_DIR.resolve(TEST_MODULE).toString();
314 String jmod = dir.resolve(TEST_MODULE + ".jmod").toString();
315 String[] args = {"create", "--class-path", cp, jmod};
316 ToolProvider jmodTool = ToolProvider.findFirst("jmod")
317 .orElseThrow(() ->
318 new RuntimeException("jmod tool not found")
319 );
320 assertEquals(0, jmodTool.run(System.out, System.out, args), "jmod tool failed");
321
322 test(dir);
323 }
324
325 /**
326 * The test module is found on the given module path. Open a ModuleReader
327 * to the test module and test the reader.
328 */
329 void test(Path mp) throws IOException {
330 ModuleFinder finder = ModulePath.of(Runtime.version(), true, mp);
331 ModuleReference mref = finder.find(TEST_MODULE).get();
332 ModuleReader reader = mref.open();
333
334 try (reader) {
335
|