1 /* 2 * Copyright (c) 2015, 2017, 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 8171177 27 * @summary Verify that ModuleResolution attribute flags are honored. 28 * @library /tools/lib 29 * @modules jdk.compiler/com.sun.tools.javac.api 30 * jdk.compiler/com.sun.tools.javac.main 31 * jdk.jdeps/com.sun.tools.classfile 32 * jdk.jdeps/com.sun.tools.javap 33 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavapTask ModuleTestBase 34 * @run main IncubatingTest 35 */ 36 37 import java.io.IOException; 38 import java.io.OutputStream; 39 import java.net.URI; 40 import java.nio.file.FileSystem; 41 import java.nio.file.FileSystems; 42 import java.nio.file.Files; 43 import java.nio.file.Path; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.HashMap; 47 import java.util.List; 48 import java.util.Map; 49 50 import com.sun.tools.classfile.Attribute; 51 import com.sun.tools.classfile.Attributes; 52 import com.sun.tools.classfile.ClassFile; 53 import com.sun.tools.classfile.ClassWriter; 54 import com.sun.tools.classfile.ConstantPool; 55 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; 56 import com.sun.tools.classfile.ConstantPool.CPInfo; 57 import com.sun.tools.classfile.ModuleResolution_attribute; 58 import toolbox.JavacTask; 59 import toolbox.Task; 60 import toolbox.Task.Expect; 61 62 public class IncubatingTest extends ModuleTestBase { 63 64 public static void main(String... args) throws Exception { 65 new IncubatingTest().runTests(); 66 } 67 68 @Test 69 public void testDoNotResolve(Path base) throws Exception { 70 Path src = base.resolve("src"); 71 tb.writeJavaFiles(src, 72 "module jdk.i { exports api; }", 73 "package api; public class Api { }"); 74 Path classes = base.resolve("classes"); 75 Files.deleteIfExists(classes); 76 Path iClasses = classes.resolve("jdk.i"); 77 tb.createDirectories(iClasses); 78 79 new JavacTask(tb) 80 .outdir(iClasses) 81 .files(findJavaFiles(src)) 82 .run() 83 .writeAll(); 84 85 copyJavaBase(classes); 86 87 Path jdkIModuleInfo = iClasses.resolve("module-info.class"); 88 addModuleResolutionAttribute(jdkIModuleInfo, ModuleResolution_attribute.DO_NOT_RESOLVE_BY_DEFAULT); 89 90 Path testSrc = base.resolve("test-src"); 91 tb.writeJavaFiles(testSrc, 92 "class T { api.Api api; }"); 93 Path testClasses = base.resolve("test-classes"); 94 tb.createDirectories(testClasses); 95 96 List<String> log; 97 List<String> expected; 98 99 log = new JavacTask(tb) 100 .options("--system", "none", 101 "--upgrade-module-path", classes.toString(), 102 "-XDrawDiagnostics") 103 .outdir(testClasses) 104 .files(findJavaFiles(testSrc)) 105 .run(Expect.FAIL) 106 .writeAll() 107 .getOutputLines(Task.OutputKind.DIRECT); 108 109 expected = Arrays.asList( 110 "T.java:1:11: compiler.err.package.not.visible: api, (compiler.misc.not.def.access.does.not.read.from.unnamed: api, jdk.i)", 111 "1 error" 112 ); 113 114 if (!expected.equals(log)) { 115 throw new AssertionError("Unexpected output: " + log); 116 } 117 118 log = new JavacTask(tb) 119 .options("--system", "none", 120 "--upgrade-module-path", classes.toString(), 121 "--add-modules", "ALL-SYSTEM", 122 "-XDrawDiagnostics") 123 .outdir(testClasses) 124 .files(findJavaFiles(testSrc)) 125 .run(Expect.SUCCESS) 126 .writeAll() 127 .getOutputLines(Task.OutputKind.DIRECT); 128 129 expected = Arrays.asList(""); 130 131 if (!expected.equals(log)) { 132 throw new AssertionError("Unexpected output: " + log); 133 } 134 135 new JavacTask(tb) 136 .options("--system", "none", 137 "--upgrade-module-path", classes.toString(), 138 "--add-modules", "jdk.i") 139 .outdir(testClasses) 140 .files(findJavaFiles(testSrc)) 141 .run() 142 .writeAll(); 143 144 Path testModuleSrc = base.resolve("test-module-src"); 145 tb.writeJavaFiles(testModuleSrc, 146 "module test { requires jdk.i; }", //explicit requires of an incubating module 147 "class T { api.Api api; }"); 148 Path testModuleClasses = base.resolve("test-module-classes"); 149 tb.createDirectories(testModuleClasses); 150 151 new JavacTask(tb) 152 .options("--system", "none", 153 "--upgrade-module-path", classes.toString()) 154 .outdir(testModuleClasses) 155 .files(findJavaFiles(testModuleSrc)) 156 .run() 157 .writeAll(); 158 } 159 160 @Test 161 public void testIncubating(Path base) throws Exception { 162 Path src = base.resolve("src"); 163 tb.writeJavaFiles(src, 164 "module jdk.i { exports api; }", 165 "package api; public class Api { }"); 166 Path classes = base.resolve("classes"); 167 Files.deleteIfExists(classes); 168 Path iClasses = classes.resolve("jdk.i"); 169 tb.createDirectories(iClasses); 170 171 new JavacTask(tb) 172 .outdir(iClasses) 173 .files(findJavaFiles(src)) 174 .run() 175 .writeAll(); 176 177 Path jdkIModuleInfo = iClasses.resolve("module-info.class"); 178 addModuleResolutionAttribute(jdkIModuleInfo, ModuleResolution_attribute.WARN_INCUBATING); 179 180 Path testSrc = base.resolve("test-src"); 181 tb.writeJavaFiles(testSrc, 182 "class T { api.Api api; }"); 183 Path testClasses = base.resolve("test-classes"); 184 tb.createDirectories(testClasses); 185 186 List<String> log; 187 List<String> expected; 188 189 log = new JavacTask(tb) 190 .options("--module-path", classes.toString(), 191 "--add-modules", "jdk.i", 192 "-XDrawDiagnostics", 193 "-Werror") 194 .outdir(testClasses) 195 .files(findJavaFiles(testSrc)) 196 .run(Expect.FAIL) 197 .writeAll() 198 .getOutputLines(Task.OutputKind.DIRECT); 199 200 expected = Arrays.asList( 201 "- compiler.warn.incubating.modules: jdk.i", 202 "- compiler.err.warnings.and.werror", 203 "1 error", 204 "1 warning" 205 ); 206 207 if (!expected.equals(log)) { 208 throw new AssertionError("Unexpected output: " + log); 209 } 210 211 Path testModuleSrc = base.resolve("test-module-src"); 212 tb.writeJavaFiles(testModuleSrc, 213 "module test { requires jdk.i; }", //explicit requires of an incubating module 214 "class T { api.Api api; }"); 215 Path testModuleClasses = base.resolve("test-module-classes"); 216 tb.createDirectories(testModuleClasses); 217 218 log = new JavacTask(tb) 219 .options("--module-path", classes.toString(), 220 "-XDrawDiagnostics", 221 "-Werror") 222 .outdir(testModuleClasses) 223 .files(findJavaFiles(testModuleSrc)) 224 .run(Expect.FAIL) 225 .writeAll() 226 .getOutputLines(Task.OutputKind.DIRECT); 227 228 expected = Arrays.asList( 229 "- compiler.warn.incubating.modules: jdk.i", 230 "- compiler.err.warnings.and.werror", 231 "1 error", 232 "1 warning" 233 ); 234 235 if (!expected.equals(log)) { 236 throw new AssertionError("Unexpected output: " + log); 237 } 238 } 239 240 private void copyJavaBase(Path targetDir) throws IOException { 241 FileSystem jrt = FileSystems.getFileSystem(URI.create("jrt:/")); 242 Path javaBase = jrt.getPath("modules", "java.base"); 243 244 if (!Files.exists(javaBase)) { 245 throw new AssertionError("No java.base?"); 246 } 247 248 Path javaBaseClasses = targetDir.resolve("java.base"); 249 250 for (Path clazz : tb.findFiles("class", javaBase)) { 251 Path target = javaBaseClasses.resolve(javaBase.relativize(clazz).toString()); 252 Files.createDirectories(target.getParent()); 253 Files.copy(clazz, target); 254 } 255 } 256 257 private void addModuleResolutionAttribute(Path classfile, int resolution_flags) throws Exception { 258 ClassFile cf = ClassFile.read(classfile); 259 Attributes attrs = cf.attributes; 260 List<CPInfo> cpData = new ArrayList<>(); 261 cpData.add(null); 262 for (CPInfo info : cf.constant_pool.entries()) { 263 cpData.add(info); 264 if (info.size() == 2) 265 cpData.add(null); 266 } 267 cpData.add(new CONSTANT_Utf8_info(Attribute.ModuleResolution)); 268 ConstantPool newCP = new ConstantPool(cpData.toArray(new CPInfo[0])); 269 ModuleResolution_attribute res = new ModuleResolution_attribute(newCP, resolution_flags); 270 Map<String, Attribute> newAttributeMap = new HashMap<>(attrs.map); 271 newAttributeMap.put(Attribute.ModuleResolution, res); 272 Attributes newAttrs = new Attributes(newAttributeMap); 273 ClassFile newCF = new ClassFile(cf.magic, 274 cf.minor_version, 275 cf.major_version, 276 newCP, 277 cf.access_flags, 278 cf.this_class, 279 cf.super_class, 280 cf.interfaces, 281 cf.fields, 282 cf.methods, 283 newAttrs); 284 try (OutputStream out = Files.newOutputStream(classfile)) { 285 new ClassWriter().write(newCF, out); 286 } 287 } 288 }