1/* 2 * Copyright (c) 2015, 2016, 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 8161906 8161596 27 * @summary tests for "requires static" 28 * @library /tools/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.main 32 * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase 33 * @run main RequiresStaticTest 34 */ 35 36import java.io.File; 37import java.nio.file.Files; 38import java.nio.file.Path; 39 40import toolbox.JavaTask; 41import toolbox.JavacTask; 42import toolbox.Task; 43import toolbox.Task.OutputKind; 44 45public class RequiresStaticTest extends ModuleTestBase { 46 47 public static void main(String... args) throws Exception { 48 RequiresStaticTest t = new RequiresStaticTest(); 49 t.runTests(); 50 } 51 52 @Test 53 public void testJavaSE_OK(Path base) throws Exception { 54 Path src = base.resolve("src"); 55 tb.writeJavaFiles(src, 56 "module m { requires static java.se; }", 57 "import java.awt.Frame;\n" // in java.se 58 + "class Test {\n" 59 + " Frame f;\n" 60 + "}"); 61 Path classes = base.resolve("classes"); 62 Files.createDirectories(classes); 63 64 new JavacTask(tb, Task.Mode.CMDLINE) 65 .files(findJavaFiles(src)) 66 .outdir(classes) 67 .run() 68 .writeAll(); 69 } 70 71 @Test 72 public void testJavaSE_Fail(Path base) throws Exception { 73 Path src = base.resolve("src"); 74 tb.writeJavaFiles(src, 75 "module m { requires static java.se; }", 76 "import com.sun.source.tree.Tree;\n" // not in java.se (in jdk.compiler) 77 + "class Test {\n" 78 + " Tree t;\n" 79 + "}"); 80 Path classes = base.resolve("classes"); 81 Files.createDirectories(classes); 82 83 String log = new JavacTask(tb, Task.Mode.CMDLINE) 84 .options("-XDrawDiagnostics") 85 .files(findJavaFiles(src)) 86 .outdir(classes) 87 .run(Task.Expect.FAIL) 88 .writeAll() 89 .getOutput(Task.OutputKind.DIRECT); 90 91 if (!log.contains("Test.java:1:22: compiler.err.package.not.visible: com.sun.source.tree, (compiler.misc.not.def.access.does.not.read: m, com.sun.source.tree, jdk.compiler)")) 92 throw new Exception("expected output not found"); 93 } 94 95 @Test 96 public void testComplex_OK(Path base) throws Exception { 97 Path src = getComplexSrc(base, "", ""); 98 Path classes = base.resolve("classes"); 99 Files.createDirectories(classes); 100 101 new JavacTask(tb, Task.Mode.CMDLINE) 102 .options("--module-source-path", src.toString()) 103 .files(findJavaFiles(src)) 104 .outdir(classes) 105 .run() 106 .writeAll(); 107 } 108 109 @Test 110 public void testComplex_Fail(Path base) throws Exception { 111 Path src = getComplexSrc(base, 112 "import p5.C5; import p6.C6; import p7.C7; import p8.C8;\n", 113 "C5 c5; C6 c6; C7 c7; C8 c8;\n"); 114 Path classes = base.resolve("classes"); 115 Files.createDirectories(classes); 116 117 String log = new JavacTask(tb, Task.Mode.CMDLINE) 118 .options("-XDrawDiagnostics", 119 "--module-source-path", src.toString()) 120 .files(findJavaFiles(src)) 121 .outdir(classes) 122 .run(Task.Expect.FAIL) 123 .writeAll() 124 .getOutput(Task.OutputKind.DIRECT); 125 126 String[] expect = { 127 "C1.java:5:8: compiler.err.package.not.visible: p5, (compiler.misc.not.def.access.does.not.read: m1x, p5, m5x)", 128 "C1.java:5:22: compiler.err.package.not.visible: p6, (compiler.misc.not.def.access.does.not.read: m1x, p6, m6x)", 129 "C1.java:5:36: compiler.err.package.not.visible: p7, (compiler.misc.not.def.access.does.not.read: m1x, p7, m7x)", 130 "C1.java:5:50: compiler.err.package.not.visible: p8, (compiler.misc.not.def.access.does.not.read: m1x, p8, m8x)" 131 }; 132 133 for (String e: expect) { 134 if (!log.contains(e)) 135 throw new Exception("expected output not found: " + e); 136 } 137 } 138 139 /* 140 * Set up the following module graph 141 * m1x -> m2x => m3x -=-> m4x --> m5 142 * \ / 143 * \ / 144 * v v 145 * m6x => m7x --> m8 146 * where -> is requires, => is requires transitive, --> is requires static, -=-> is requires transitive static 147 */ 148 Path getComplexSrc(Path base, String m1_extraImports, String m1_extraUses) throws Exception { 149 Path src = base.resolve("src"); 150 151 Path src_m1 = src.resolve("m1x"); 152 tb.writeJavaFiles(src_m1, 153 "module m1x { requires m2x; }", 154 "package p1;\n" 155 + "import p2.C2;\n" 156 + "import p3.C3;\n" 157 + "import p4.C4;\n" 158 + m1_extraImports 159 + "class C1 {\n" 160 + " C2 c2; C3 c3; C4 c4;\n" 161 + m1_extraUses 162 + "}\n"); 163 164 Path src_m2 = src.resolve("m2x"); 165 tb.writeJavaFiles(src_m2, 166 "module m2x {\n" 167 + " requires transitive m3x;\n" 168 + " requires static m6x;\n" 169 + " exports p2;\n" 170 + "}", 171 "package p2;\n" 172 + "public class C2 {p7.C7 c7; p6.C6 c6; p4.C4 c4;}\n"); 173 174 Path src_m3 = src.resolve("m3x"); 175 tb.writeJavaFiles(src_m3, 176 "module m3x { requires transitive static m4x; exports p3; }", 177 "package p3;\n" 178 + "public class C3 { }\n"); 179 180 Path src_m4 = src.resolve("m4x"); 181 tb.writeJavaFiles(src_m4, 182 "module m4x { requires m5x; requires static m6x; exports p4; }", 183 "package p4;\n" 184 + "public class C4 { p6.C6 c6; p7.C7 c7;}\n"); 185 186 Path src_m5 = src.resolve("m5x"); 187 tb.writeJavaFiles(src_m5, 188 "module m5x { exports p5; }", 189 "package p5;\n" 190 + "public class C5 { }\n"); 191 192 Path src_m6 = src.resolve("m6x"); 193 tb.writeJavaFiles(src_m6, 194 "module m6x { requires transitive m7x; exports p6; }", 195 "package p6;\n" 196 + "public class C6 { p7.C7 c7; }\n"); 197 198 Path src_m7 = src.resolve("m7x"); 199 tb.writeJavaFiles(src_m7, 200 "module m7x { requires static m8x; exports p7; }", 201 "package p7;\n" 202 + "public class C7 { p8.C8 c8; }\n"); 203 204 Path src_m8 = src.resolve("m8x"); 205 tb.writeJavaFiles(src_m8, 206 "module m8x { exports p8; }", 207 "package p8;\n" 208 + "public class C8 { }\n"); 209 210 return src; 211 } 212 213 @Test 214 public void testRequiresStatic(Path base) throws Exception { 215 Path src = base.resolve("src"); 216 Path m1 = src.resolve("m1x"); 217 tb.writeJavaFiles(m1, 218 "module m1x { exports m1x; }", 219 "package m1x;" + 220 "public class Api { }\n"); 221 222 Path classes = base.resolve("classes"); 223 Path m1Classes = classes.resolve("m1x"); 224 Files.createDirectories(m1Classes); 225 226 new JavacTask(tb, Task.Mode.CMDLINE) 227 .files(findJavaFiles(m1)) 228 .outdir(m1Classes) 229 .run() 230 .writeAll(); 231 232 Path m3 = src.resolve("m3x"); 233 tb.writeJavaFiles(m3, 234 "module m3x { requires static m1x; }", 235 "package m3x;\n" + 236 "public class Test {\n" + 237 " public static void main(String... args) {\n" + 238 " try {\n" + 239 " Class.forName(\"m1x.Api\");\n" + 240 " } catch (ClassNotFoundException e) {\n" + 241 " System.err.println(\"ok\");\n" + 242 " }\n" + 243 " }\n" + 244 "}", 245 "package m3x;\n" + 246 "public class ApiUse{\n" + 247 " m1x.Api api;\n" + 248 "}"); 249 250 Path m3Classes = classes.resolve("m3x"); 251 Files.createDirectories(m3Classes); 252 253 new JavacTask(tb, Task.Mode.CMDLINE) 254 .options("--module-path", m1Classes.toString()) 255 .files(findJavaFiles(m3)) 256 .outdir(m3Classes) 257 .run() 258 .writeAll(); 259 260 String log = new JavaTask(tb) 261 .vmOptions("--module-path", m3Classes.toString(), "--add-modules", "m3x") 262 .className("m3x.Test") 263 .run() 264 .writeAll() 265 .getOutput(OutputKind.STDERR); 266 267 String expected = "ok" + System.getProperty("line.separator"); 268 269 if (!expected.equals(log)) { 270 throw new AssertionError("Unexpected output: " + log); 271 } 272 } 273 274 @Test 275 public void testRequiresTransitiveStatic(Path base) throws Exception { 276 Path src = base.resolve("src"); 277 Path m1 = src.resolve("m1x"); 278 tb.writeJavaFiles(m1, 279 "module m1x { exports m1x; }", 280 "package m1x;" + 281 "public class Api { }\n"); 282 283 Path classes = base.resolve("classes"); 284 Path m1Classes = classes.resolve("m1x"); 285 Files.createDirectories(m1Classes); 286 287 new JavacTask(tb, Task.Mode.CMDLINE) 288 .files(findJavaFiles(m1)) 289 .outdir(m1Classes) 290 .run() 291 .writeAll(); 292 293 Path m2 = src.resolve("m2x"); 294 tb.writeJavaFiles(m2, 295 "module m2x { requires transitive static m1x; }"); 296 297 Path m2Classes = classes.resolve("m2x"); 298 Files.createDirectories(m2Classes); 299 300 new JavacTask(tb, Task.Mode.CMDLINE) 301 .options("--module-path", m1Classes.toString()) 302 .files(findJavaFiles(m2)) 303 .outdir(m2Classes) 304 .run() 305 .writeAll(); 306 307 Path m3 = src.resolve("m3x"); 308 tb.writeJavaFiles(m3, 309 "module m3x { requires m2x; }", 310 "package m3x;\n" + 311 "public class Test {\n" + 312 " public static void main(String... args) {\n" + 313 " try {\n" + 314 " Class.forName(\"m1x.Api\");\n" + 315 " } catch (ClassNotFoundException e) {\n" + 316 " System.err.println(\"ok\");\n" + 317 " }\n" + 318 " }\n" + 319 "}", 320 "package m3x;\n" + 321 "public class ApiUse{\n" + 322 " m1x.Api api;\n" + 323 "}"); 324 325 Path m3Classes = classes.resolve("m3x"); 326 Files.createDirectories(m3Classes); 327 328 new JavacTask(tb, Task.Mode.CMDLINE) 329 .options("--module-path", m1Classes.toString() + File.pathSeparator + m2Classes.toString()) 330 .files(findJavaFiles(m3)) 331 .outdir(m3Classes) 332 .run() 333 .writeAll(); 334 335 String log = new JavaTask(tb) 336 .vmOptions("--module-path", m2Classes.toString() + File.pathSeparator + m3Classes.toString(), 337 "--add-modules", "m3x") 338 .className("m3x.Test") 339 .run() 340 .writeAll() 341 .getOutput(OutputKind.STDERR); 342 343 String expected = "ok" + System.getProperty("line.separator"); 344 345 if (!expected.equals(log)) { 346 throw new AssertionError("Unexpected output: " + log); 347 } 348 } 349 350 @Test 351 public void testRequiresStaticTransitive(Path base) throws Exception { 352 Path src = base.resolve("src"); 353 Path m1 = src.resolve("m1x"); 354 tb.writeJavaFiles(m1, 355 "module m1x { exports m1x; }", 356 "package m1x;" + 357 "public class Api { }\n"); 358 359 Path classes = base.resolve("classes"); 360 Path m1Classes = classes.resolve("m1x"); 361 Files.createDirectories(m1Classes); 362 363 new JavacTask(tb, Task.Mode.CMDLINE) 364 .files(findJavaFiles(m1)) 365 .outdir(m1Classes) 366 .run() 367 .writeAll(); 368 369 Path m2 = src.resolve("m2x"); 370 tb.writeJavaFiles(m2, 371 "module m2x { requires transitive static m1x; }"); 372 373 Path m2Classes = classes.resolve("m2x"); 374 Files.createDirectories(m2Classes); 375 376 new JavacTask(tb, Task.Mode.CMDLINE) 377 .options("--module-path", m1Classes.toString()) 378 .files(findJavaFiles(m2)) 379 .outdir(m2Classes) 380 .run() 381 .writeAll(); 382 } 383} 384