44 45 import com.sun.tools.classfile.Attribute; 46 import com.sun.tools.classfile.Attributes; 47 import com.sun.tools.classfile.ClassFile; 48 import com.sun.tools.classfile.ClassWriter; 49 import com.sun.tools.classfile.Module_attribute; 50 import toolbox.JavacTask; 51 import toolbox.JavapTask; 52 import toolbox.Task; 53 import toolbox.Task.Expect; 54 import toolbox.Task.OutputKind; 55 56 public class OpenModulesTest extends ModuleTestBase { 57 58 public static void main(String... args) throws Exception { 59 new OpenModulesTest().runTests(); 60 } 61 62 @Test 63 public void testStrongModule(Path base) throws Exception { 64 Path m1 = base.resolve("m1"); 65 tb.writeJavaFiles(m1, 66 "module m1 { exports api1; opens api2; }", 67 "package api1; public class Api1 {}", 68 "package api2; public class Api2 {}", 69 "package impl; public class Impl {}"); 70 Path classes = base.resolve("classes"); 71 Path m1Classes = classes.resolve("m1"); 72 tb.createDirectories(m1Classes); 73 74 String log = new JavacTask(tb) 75 .outdir(m1Classes) 76 .files(findJavaFiles(m1)) 77 .run() 78 .writeAll() 79 .getOutput(Task.OutputKind.DIRECT); 80 81 if (!log.isEmpty()) 82 throw new Exception("expected output not found: " + log); 83 84 String decompiled = new JavapTask(tb) 85 .options("--system", "none", "-bootclasspath", "") 86 .classes(m1Classes.resolve("module-info.class").toString()) 87 .run() 88 .writeAll() 89 .getOutput(OutputKind.DIRECT) 90 .replace(System.getProperty("line.separator"), "\n"); 91 92 String expected = "module m1 {\n" + 93 " requires java.base;\n" + 94 " exports api1;\n" + 95 " opens api2;\n" + 96 "}"; 97 98 if (!decompiled.contains(expected)) { 99 throw new Exception("expected output not found: " + decompiled); 100 } 101 102 //compiling against a strong module read from binary: 103 Path m2 = base.resolve("m2"); 104 tb.writeJavaFiles(m2, 105 "module m2 { requires m1; }", 106 "package test; public class Test { api1.Api1 a1; api2.Api2 a2; }"); 107 Path m2Classes = classes.resolve("m2"); 108 tb.createDirectories(m2Classes); 109 110 List<String> log2 = new JavacTask(tb) 111 .options("--module-path", m1Classes.toString(), 112 "-XDrawDiagnostics") 113 .outdir(m2Classes) 114 .files(findJavaFiles(m2)) 115 .run(Expect.FAIL) 116 .writeAll() 117 .getOutputLines(Task.OutputKind.DIRECT); 118 119 List<String> expected2 = Arrays.asList("Test.java:1:53: compiler.err.doesnt.exist: api2", 120 "1 error"); 121 if (!Objects.equals(log2, expected2)) 122 throw new Exception("expected output not found: " + log2); 123 } 124 125 @Test 126 public void testOpenModule(Path base) throws Exception { 127 Path m1 = base.resolve("m1"); 128 tb.writeJavaFiles(m1, 129 "open module m1 { exports api1; }", 130 "package api1; public class Api1 {}", 131 "package api2; public class Api2 {}", 132 "package impl; public class Impl {}"); 133 Path classes = base.resolve("classes"); 134 Path m1Classes = classes.resolve("m1"); 135 tb.createDirectories(m1Classes); 136 137 String log = new JavacTask(tb) 138 .outdir(m1Classes) 139 .files(findJavaFiles(m1)) 140 .run() 141 .writeAll() 142 .getOutput(Task.OutputKind.DIRECT); 143 144 if (!log.isEmpty()) 145 throw new Exception("expected output not found: " + log); 146 147 String decompiled = new JavapTask(tb) 148 .options("--system", "none", "-bootclasspath", "") 149 .classes(m1Classes.resolve("module-info.class").toString()) 150 .run() 151 .writeAll() 152 .getOutput(OutputKind.DIRECT) 153 .replace(System.getProperty("line.separator"), "\n"); 154 155 String expected = "open module m1 {\n" + 156 " requires java.base;\n" + 157 " exports api1;\n" + 158 "}"; 159 160 if (!decompiled.contains(expected)) { 161 throw new Exception("expected output not found: " + decompiled); 162 } 163 164 //compiling against a ordinary module read from binary: 165 Path m2 = base.resolve("m2"); 166 tb.writeJavaFiles(m2, 167 "module m2 { requires m1; }", 168 "package test; public class Test { api1.Api1 a1; api2.Api2 a2; }"); 169 Path m2Classes = classes.resolve("m2"); 170 tb.createDirectories(m2Classes); 171 172 List<String> log2 = new JavacTask(tb) 173 .options("--module-path", m1Classes.toString(), 174 "-XDrawDiagnostics") 175 .outdir(m2Classes) 176 .files(findJavaFiles(m2)) 177 .run(Expect.FAIL) 178 .writeAll() 179 .getOutputLines(Task.OutputKind.DIRECT); 180 181 List<String> expected2 = Arrays.asList("Test.java:1:53: compiler.err.doesnt.exist: api2", 182 "1 error"); 183 if (!Objects.equals(log2, expected2)) 184 throw new Exception("expected output not found: " + log2); 185 } 186 187 @Test 188 public void testOpenModuleNoOpens(Path base) throws Exception { 189 Path m1 = base.resolve("m1"); 190 tb.writeJavaFiles(m1, 191 "open module m1 { exports api1; opens api2; }", 192 "package api1; public class Api1 {}", 193 "package api2; public class Api2 {}", 194 "package impl; public class Impl {}"); 195 Path classes = base.resolve("classes"); 196 Path m1Classes = classes.resolve("m1"); 197 tb.createDirectories(m1Classes); 198 199 List<String> log = new JavacTask(tb) 200 .options("-XDrawDiagnostics") 201 .outdir(m1Classes) 202 .files(findJavaFiles(m1)) 203 .run(Expect.FAIL) 204 .writeAll() 205 .getOutputLines(Task.OutputKind.DIRECT); 206 207 List<String> expected = Arrays.asList("module-info.java:1:32: compiler.err.no.opens.unless.strong", 208 "1 error"); 209 210 if (!expected.equals(log)) 211 throw new Exception("expected output not found: " + log); 212 213 } 214 215 @Test 216 public void testNonZeroOpensInOpen(Path base) throws Exception { 217 Path m1 = base.resolve("m1"); 218 tb.writeJavaFiles(m1, 219 "module m1 { opens api; }", 220 "package api; public class Api {}"); 221 Path classes = base.resolve("classes"); 222 Path m1Classes = classes.resolve("m1"); 223 tb.createDirectories(m1Classes); 224 225 new JavacTask(tb) 226 .options("-XDrawDiagnostics") 227 .outdir(m1Classes) 228 .files(findJavaFiles(m1)) 229 .run(Expect.SUCCESS) 230 .writeAll(); 231 232 Path miClass = m1Classes.resolve("module-info.class"); 233 ClassFile cf = ClassFile.read(miClass); 234 Module_attribute module = (Module_attribute) cf.attributes.map.get(Attribute.Module); 235 Module_attribute newModule = new Module_attribute(module.attribute_name_index, 236 module.module_name, 237 module.module_flags | Module_attribute.ACC_OPEN, 238 module.requires, 239 module.exports, 240 module.opens, 241 module.uses_index, 242 module.provides); 243 Map<String, Attribute> attrs = new HashMap<>(cf.attributes.map); 244 245 attrs.put(Attribute.Module, newModule); 246 247 Attributes newAttributes = new Attributes(attrs); 248 ClassFile newClassFile = new ClassFile(cf.magic, 249 cf.minor_version, 250 cf.major_version, 251 cf.constant_pool, 252 cf.access_flags, 253 cf.this_class, 254 cf.super_class, 255 cf.interfaces, 256 cf.fields, 257 cf.methods, 258 newAttributes); 259 260 try (OutputStream out = Files.newOutputStream(miClass)) { 261 new ClassWriter().write(newClassFile, out); 262 } 263 264 Path test = base.resolve("test"); 265 tb.writeJavaFiles(test, 266 "package impl; public class Impl extends api.Api {}"); 267 Path testClasses = base.resolve("test-classes"); 268 tb.createDirectories(testClasses); 269 270 List<String> log = new JavacTask(tb) 271 .options("-XDrawDiagnostics", 272 "--module-path", classes.toString(), 273 "--add-modules", "m1") 274 .outdir(testClasses) 275 .files(findJavaFiles(test)) 276 .run(Expect.FAIL) 277 .writeAll() 278 .getOutputLines(Task.OutputKind.DIRECT); 279 280 List<String> expected = Arrays.asList("- compiler.err.cant.access: m1.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.module.non.zero.opens: m1))", 281 "1 error"); 282 283 if (!expected.equals(log)) 284 throw new Exception("expected output not found: " + log); 285 } 286 287 } | 44 45 import com.sun.tools.classfile.Attribute; 46 import com.sun.tools.classfile.Attributes; 47 import com.sun.tools.classfile.ClassFile; 48 import com.sun.tools.classfile.ClassWriter; 49 import com.sun.tools.classfile.Module_attribute; 50 import toolbox.JavacTask; 51 import toolbox.JavapTask; 52 import toolbox.Task; 53 import toolbox.Task.Expect; 54 import toolbox.Task.OutputKind; 55 56 public class OpenModulesTest extends ModuleTestBase { 57 58 public static void main(String... args) throws Exception { 59 new OpenModulesTest().runTests(); 60 } 61 62 @Test 63 public void testStrongModule(Path base) throws Exception { 64 Path m1 = base.resolve("m1x"); 65 tb.writeJavaFiles(m1, 66 "module m1x { exports api1; opens api2; }", 67 "package api1; public class Api1 {}", 68 "package api2; public class Api2 {}", 69 "package impl; public class Impl {}"); 70 Path classes = base.resolve("classes"); 71 Path m1Classes = classes.resolve("m1x"); 72 tb.createDirectories(m1Classes); 73 74 String log = new JavacTask(tb) 75 .outdir(m1Classes) 76 .files(findJavaFiles(m1)) 77 .run() 78 .writeAll() 79 .getOutput(Task.OutputKind.DIRECT); 80 81 if (!log.isEmpty()) 82 throw new Exception("expected output not found: " + log); 83 84 String decompiled = new JavapTask(tb) 85 .options("--system", "none", "-bootclasspath", "") 86 .classes(m1Classes.resolve("module-info.class").toString()) 87 .run() 88 .writeAll() 89 .getOutput(OutputKind.DIRECT) 90 .replace(System.getProperty("line.separator"), "\n") 91 .replaceAll("@[^;]*;", ";"); 92 93 String expected = "module m1x {\n" + 94 " requires java.base;\n" + 95 " exports api1;\n" + 96 " opens api2;\n" + 97 "}"; 98 99 if (!decompiled.contains(expected)) { 100 throw new Exception("expected output not found: " + decompiled); 101 } 102 103 //compiling against a strong module read from binary: 104 Path m2 = base.resolve("m2x"); 105 tb.writeJavaFiles(m2, 106 "module m2x { requires m1x; }", 107 "package test; public class Test { api1.Api1 a1; api2.Api2 a2; }"); 108 Path m2Classes = classes.resolve("m2x"); 109 tb.createDirectories(m2Classes); 110 111 List<String> log2 = new JavacTask(tb) 112 .options("--module-path", m1Classes.toString(), 113 "-XDrawDiagnostics") 114 .outdir(m2Classes) 115 .files(findJavaFiles(m2)) 116 .run(Expect.FAIL) 117 .writeAll() 118 .getOutputLines(Task.OutputKind.DIRECT); 119 120 List<String> expected2 = Arrays.asList("Test.java:1:53: compiler.err.doesnt.exist: api2", 121 "1 error"); 122 if (!Objects.equals(log2, expected2)) 123 throw new Exception("expected output not found: " + log2); 124 } 125 126 @Test 127 public void testOpenModule(Path base) throws Exception { 128 Path m1 = base.resolve("m1x"); 129 tb.writeJavaFiles(m1, 130 "open module m1x { exports api1; }", 131 "package api1; public class Api1 {}", 132 "package api2; public class Api2 {}", 133 "package impl; public class Impl {}"); 134 Path classes = base.resolve("classes"); 135 Path m1Classes = classes.resolve("m1x"); 136 tb.createDirectories(m1Classes); 137 138 String log = new JavacTask(tb) 139 .outdir(m1Classes) 140 .files(findJavaFiles(m1)) 141 .run() 142 .writeAll() 143 .getOutput(Task.OutputKind.DIRECT); 144 145 if (!log.isEmpty()) 146 throw new Exception("expected output not found: " + log); 147 148 String decompiled = new JavapTask(tb) 149 .options("--system", "none", "-bootclasspath", "") 150 .classes(m1Classes.resolve("module-info.class").toString()) 151 .run() 152 .writeAll() 153 .getOutput(OutputKind.DIRECT) 154 .replace(System.getProperty("line.separator"), "\n") 155 .replaceAll("@[^;]*;", ";"); 156 157 String expected = "open module m1x {\n" + 158 " requires java.base;\n" + 159 " exports api1;\n" + 160 "}"; 161 162 if (!decompiled.contains(expected)) { 163 throw new Exception("expected output not found: " + decompiled); 164 } 165 166 //compiling against a ordinary module read from binary: 167 Path m2 = base.resolve("m2x"); 168 tb.writeJavaFiles(m2, 169 "module m2x { requires m1x; }", 170 "package test; public class Test { api1.Api1 a1; api2.Api2 a2; }"); 171 Path m2Classes = classes.resolve("m2x"); 172 tb.createDirectories(m2Classes); 173 174 List<String> log2 = new JavacTask(tb) 175 .options("--module-path", m1Classes.toString(), 176 "-XDrawDiagnostics") 177 .outdir(m2Classes) 178 .files(findJavaFiles(m2)) 179 .run(Expect.FAIL) 180 .writeAll() 181 .getOutputLines(Task.OutputKind.DIRECT); 182 183 List<String> expected2 = Arrays.asList("Test.java:1:53: compiler.err.doesnt.exist: api2", 184 "1 error"); 185 if (!Objects.equals(log2, expected2)) 186 throw new Exception("expected output not found: " + log2); 187 } 188 189 @Test 190 public void testOpenModuleNoOpens(Path base) throws Exception { 191 Path m1 = base.resolve("m1x"); 192 tb.writeJavaFiles(m1, 193 "open module m1x { exports api1; opens api2; }", 194 "package api1; public class Api1 {}", 195 "package api2; public class Api2 {}", 196 "package impl; public class Impl {}"); 197 Path classes = base.resolve("classes"); 198 Path m1Classes = classes.resolve("m1x"); 199 tb.createDirectories(m1Classes); 200 201 List<String> log = new JavacTask(tb) 202 .options("-XDrawDiagnostics") 203 .outdir(m1Classes) 204 .files(findJavaFiles(m1)) 205 .run(Expect.FAIL) 206 .writeAll() 207 .getOutputLines(Task.OutputKind.DIRECT); 208 209 List<String> expected = Arrays.asList("module-info.java:1:33: compiler.err.no.opens.unless.strong", 210 "1 error"); 211 212 if (!expected.equals(log)) 213 throw new Exception("expected output not found: " + log); 214 215 } 216 217 @Test 218 public void testNonZeroOpensInOpen(Path base) throws Exception { 219 Path m1 = base.resolve("m1x"); 220 tb.writeJavaFiles(m1, 221 "module m1x { opens api; }", 222 "package api; public class Api {}"); 223 Path classes = base.resolve("classes"); 224 Path m1Classes = classes.resolve("m1x"); 225 tb.createDirectories(m1Classes); 226 227 new JavacTask(tb) 228 .options("-XDrawDiagnostics") 229 .outdir(m1Classes) 230 .files(findJavaFiles(m1)) 231 .run(Expect.SUCCESS) 232 .writeAll(); 233 234 Path miClass = m1Classes.resolve("module-info.class"); 235 ClassFile cf = ClassFile.read(miClass); 236 Module_attribute module = (Module_attribute) cf.attributes.map.get(Attribute.Module); 237 Module_attribute newModule = new Module_attribute(module.attribute_name_index, 238 module.module_name, 239 module.module_flags | Module_attribute.ACC_OPEN, 240 module.module_version_index, 241 module.requires, 242 module.exports, 243 module.opens, 244 module.uses_index, 245 module.provides); 246 Map<String, Attribute> attrs = new HashMap<>(cf.attributes.map); 247 248 attrs.put(Attribute.Module, newModule); 249 250 Attributes newAttributes = new Attributes(attrs); 251 ClassFile newClassFile = new ClassFile(cf.magic, 252 cf.minor_version, 253 cf.major_version, 254 cf.constant_pool, 255 cf.access_flags, 256 cf.this_class, 257 cf.super_class, 258 cf.interfaces, 259 cf.fields, 260 cf.methods, 261 newAttributes); 262 263 try (OutputStream out = Files.newOutputStream(miClass)) { 264 new ClassWriter().write(newClassFile, out); 265 } 266 267 Path test = base.resolve("test"); 268 tb.writeJavaFiles(test, 269 "package impl; public class Impl extends api.Api {}"); 270 Path testClasses = base.resolve("test-classes"); 271 tb.createDirectories(testClasses); 272 273 List<String> log = new JavacTask(tb) 274 .options("-XDrawDiagnostics", 275 "--module-path", classes.toString(), 276 "--add-modules", "m1x") 277 .outdir(testClasses) 278 .files(findJavaFiles(test)) 279 .run(Expect.FAIL) 280 .writeAll() 281 .getOutputLines(Task.OutputKind.DIRECT); 282 283 List<String> expected = Arrays.asList( 284 "- compiler.err.cant.access: m1x.module-info, " 285 + "(compiler.misc.bad.class.file.header: module-info.class, " 286 + "(compiler.misc.module.non.zero.opens: m1x))", 287 "1 error"); 288 289 if (!expected.equals(log)) 290 throw new Exception("expected output not found: " + log); 291 } 292 293 } |