1 /*
2 * Copyright (c) 2023, 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 * @summary Basic test for Enable-Native-Access attribute in the
27 * manifest of a main application JAR
28 * @library /test/lib
29 * @requires jdk.foreign.linker != "UNSUPPORTED"
30 * @requires !vm.musl
31 * @comment Disable test for the zero VM config due to 8380059.
32 * @requires vm.flavor != "zero"
33 *
34 * @enablePreview
35 * @build TestEnableNativeAccessJarManifest
36 * panama_module/*
37 * org.openjdk.foreigntest.unnamed.PanamaMainUnnamedModule
38 * @run testng/native TestEnableNativeAccessJarManifest
39 */
40
41 import java.nio.file.Files;
42 import java.nio.file.Path;
43 import java.nio.file.Paths;
44 import java.util.List;
45 import java.util.ArrayList;
46 import java.util.jar.Attributes;
47 import java.util.jar.Manifest;
48
49 import jdk.test.lib.process.OutputAnalyzer;
50 import jdk.test.lib.process.ProcessTools;
51 import jdk.test.lib.util.JarUtils;
52
53 import org.testng.annotations.Test;
54 import org.testng.annotations.DataProvider;
55
56 public class TestEnableNativeAccessJarManifest extends TestEnableNativeAccessBase {
57
58 private static final String REINVOKER = "TestEnableNativeAccessJarManifest$Reinvoker";
59
60 static record Attribute(String name, String value) {}
61
62 @Test(dataProvider = "cases")
63 public void testEnableNativeAccessInJarManifest(String action, String cls, Result expectedResult,
64 List<Attribute> attributes, List<String> vmArgs, List<String> programArgs) throws Exception {
65 Manifest man = new Manifest();
66 Attributes attrs = man.getMainAttributes();
67 attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
68 attrs.put(Attributes.Name.MAIN_CLASS, cls);
69
70 for (Attribute attrib : attributes) {
71 attrs.put(new Attributes.Name(attrib.name()), attrib.value());
72 }
73
74 // create the JAR file with Test1 and Test2
75 Path jarfile = Paths.get(action + ".jar");
76 Files.deleteIfExists(jarfile);
77
78 Path classes = Paths.get(System.getProperty("test.classes", ""));
79 JarUtils.createJarFile(jarfile, man, classes, Paths.get(cls.replace('.', '/') + ".class"));
80
81 // java -jar test.jar
82 List<String> command = new ArrayList<>(List.of(
83 "-Djava.library.path=" + System.getProperty("java.library.path")
84 ));
85 command.addAll(vmArgs);
86 command.add("-jar");
87 command.add(jarfile.toString());
88 command.addAll(programArgs);
89 OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(command.toArray(String[]::new))
90 .outputTo(System.out)
91 .errorTo(System.out);
92 checkResult(expectedResult, outputAnalyzer);
93 }
94
95 @DataProvider
96 public Object[][] cases() {
97 return new Object[][] {
98 // simple cases where a jar contains a single main class with no dependencies
99 { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"),
100 List.of(), List.of(), List.of() },
101 { "panama_unnamed_module_native_access", UNNAMED, successNoWarning(),
102 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")), List.of(), List.of() },
103 { "panama_unnamed_module_native_access_invalid", UNNAMED,
104 failWithError("Error: illegal value \"asdf\" for Enable-Native-Access manifest attribute. Only ALL-UNNAMED is allowed"),
105 List.of(new Attribute("Enable-Native-Access", "asdf")), List.of(), List.of() },
106
107 // more complex cases where a jar invokes a module on the module path that does native access
108 { "panama_enable_native_access_false", REINVOKER, successWithWarning("panama_module"),
109 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
110 List.of("-p", MODULE_PATH, "--add-modules=panama_module"),
111 List.of(PANAMA_MAIN_CLS) },
112 { "panama_enable_native_access_reflection_false", REINVOKER, successWithWarning("panama_module"),
113 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
114 List.of("-p", MODULE_PATH, "--add-modules=panama_module"),
115 List.of(PANAMA_REFLECTION_CLS) },
116 { "panama_enable_native_access_invoke_false", REINVOKER, successWithWarning("panama_module"),
117 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
118 List.of("-p", MODULE_PATH, "--add-modules=panama_module"),
119 List.of(PANAMA_INVOKE_CLS) },
120
121 { "panama_enable_native_access_true", REINVOKER, successNoWarning(),
122 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
123 List.of("-p", MODULE_PATH, "--add-modules=panama_module", "--enable-native-access=panama_module"),
124 List.of(PANAMA_MAIN_CLS) },
125 { "panama_enable_native_access_reflection_true", REINVOKER, successNoWarning(),
126 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
127 List.of("-p", MODULE_PATH, "--add-modules=panama_module", "--enable-native-access=panama_module"),
128 List.of(PANAMA_REFLECTION_CLS) },
129 { "panama_enable_native_access_invoke_true", REINVOKER, successNoWarning(),
130 List.of(new Attribute("Enable-Native-Access", "ALL-UNNAMED")),
131 List.of("-p", MODULE_PATH, "--add-modules=panama_module", "--enable-native-access=panama_module"),
132 List.of(PANAMA_INVOKE_CLS) }
133 };
134 }
135
136 public class Reinvoker {
137 public static void main(String[] args) throws Throwable {
138 Class<?> realMainClass = Class.forName(args[0]);
139 realMainClass.getMethod("main", String[].class).invoke(null, (Object) new String[0]);
140 }
141 }
142 }