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 .outdir(testClasses) 194 .files(findJavaFiles(testSrc)) 195 .run(Expect.SUCCESS) 196 .writeAll() 197 .getOutputLines(Task.OutputKind.DIRECT); 198 199 expected = Arrays.asList( 200 "- compiler.note.incubating.modules: jdk.i" 201 ); 202 203 if (!expected.equals(log)) { 204 throw new AssertionError("Unexpected output: " + log); 205 } 206 207 Path testModuleSrc = base.resolve("test-module-src"); 208 tb.writeJavaFiles(testModuleSrc, 209 "module test { requires jdk.i; }", //explicit requires of an incubating module 210 "class T { api.Api api; }"); 211 Path testModuleClasses = base.resolve("test-module-classes"); 212 tb.createDirectories(testModuleClasses); 213 214 log = new JavacTask(tb) 215 .options("--module-path", classes.toString(), 216 "-XDrawDiagnostics") 217 .outdir(testModuleClasses) 218 .files(findJavaFiles(testModuleSrc)) 219 .run(Expect.SUCCESS) 220 .writeAll() 221 .getOutputLines(Task.OutputKind.DIRECT); 222 223 expected = Arrays.asList( 224 "- compiler.note.incubating.modules: jdk.i" 225 ); 226 227 if (!expected.equals(log)) { 228 throw new AssertionError("Unexpected output: " + log); 229 } 230 } 231 232 private void copyJavaBase(Path targetDir) throws IOException { 233 FileSystem jrt = FileSystems.getFileSystem(URI.create("jrt:/")); 234 Path javaBase = jrt.getPath("modules", "java.base"); 235 236 if (!Files.exists(javaBase)) { 237 throw new AssertionError("No java.base?"); 238 } 239 240 Path javaBaseClasses = targetDir.resolve("java.base"); 241 242 for (Path clazz : tb.findFiles("class", javaBase)) { 243 Path target = javaBaseClasses.resolve(javaBase.relativize(clazz).toString()); 244 Files.createDirectories(target.getParent()); 245 Files.copy(clazz, target); 246 } 247 } 248 249 private void addModuleResolutionAttribute(Path classfile, int resolution_flags) throws Exception { 250 ClassFile cf = ClassFile.read(classfile); 251 Attributes attrs = cf.attributes; 252 List<CPInfo> cpData = new ArrayList<>(); 253 cpData.add(null); 254 for (CPInfo info : cf.constant_pool.entries()) { 255 cpData.add(info); 256 if (info.size() == 2) 257 cpData.add(null); 258 } 259 cpData.add(new CONSTANT_Utf8_info(Attribute.ModuleResolution)); 260 ConstantPool newCP = new ConstantPool(cpData.toArray(new CPInfo[0])); 261 ModuleResolution_attribute res = new ModuleResolution_attribute(newCP, resolution_flags); 262 Map<String, Attribute> newAttributeMap = new HashMap<>(attrs.map); 263 newAttributeMap.put(Attribute.ModuleResolution, res); 264 Attributes newAttrs = new Attributes(newAttributeMap); 265 ClassFile newCF = new ClassFile(cf.magic, 266 cf.minor_version, 267 cf.major_version, 268 newCP, 269 cf.access_flags, 270 cf.this_class, 271 cf.super_class, 272 cf.interfaces, 273 cf.fields, 274 cf.methods, 275 newAttrs); 276 try (OutputStream out = Files.newOutputStream(classfile)) { 277 new ClassWriter().write(newCF, out); 278 } 279 } 280 }