# HG changeset patch # User alanb # Date 1480582673 0 # Node ID a60f280f803c7cc71f484248051b53711b99c7b8 # Parent 7a4a59859ac00400ea73768a25409ecb7b9c3a80 8169069: Module system implementation refresh (11/2016) Reviewed-by: plevart, chegar, psandoz, mchung, alanb, dfuchs, naoto, coffeys, weijun Contributed-by: alan.bateman@oracle.com, mandy.chung@oracle.com, claes.redestad@oracle.com, mark.reinhold@oracle.com diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/data/jdwp/jdwp.spec --- a/jdk/make/data/jdwp/jdwp.spec Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/make/data/jdwp/jdwp.spec Thu Dec 01 08:57:53 2016 +0000 @@ -2709,22 +2709,6 @@ (Error VM_DEAD) ) ) - (Command CanRead=3 - "Returns true if this module can read the source module; false otherwise." - "

Since JDWP version 9." - (Out - (moduleID module "This module.") - (moduleID sourceModule "The source module.") - ) - (Reply - (boolean canRead "true if this module can read the source module; false otherwise.") - ) - (ErrorSet - (Error INVALID_MODULE "This module or sourceModule is not the ID of a module.") - (Error NOT_IMPLEMENTED) - (Error VM_DEAD) - ) - ) ) (CommandSet Event=64 (Command Composite=100 diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/launcher/Launcher-jdk.jconsole.gmk --- a/jdk/make/launcher/Launcher-jdk.jconsole.gmk Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/make/launcher/Launcher-jdk.jconsole.gmk Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,8 @@ $(eval $(call SetupBuildLauncher, jconsole, \ MAIN_CLASS := sun.tools.jconsole.JConsole, \ - JAVA_ARGS := -Djconsole.showOutputViewer, \ + JAVA_ARGS := --add-opens java.base/java.io=jdk.jconsole \ + -Djconsole.showOutputViewer, \ CFLAGS_windows := -DJAVAW, \ LIBS_windows := user32.lib, \ )) diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java --- a/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java Thu Dec 01 08:57:53 2016 +0000 @@ -65,7 +65,7 @@ String mn = entry.getFileName().toString(); Optional omref = finder.find(mn); if (omref.isPresent()) { - Set packages = omref.get().descriptor().conceals(); + Set packages = omref.get().descriptor().packages(); addPackagesAttribute(mi, packages); } } @@ -77,7 +77,7 @@ byte[] bytes; try (InputStream in = Files.newInputStream(mi)) { ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in); - extender.conceals(packages); + extender.packages(packages); ByteArrayOutputStream baos = new ByteArrayOutputStream(); extender.write(baos); bytes = baos.toByteArray(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java --- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java Thu Dec 01 08:57:53 2016 +0000 @@ -43,7 +43,7 @@ import java.util.TreeSet; import java.util.function.Function; import java.util.stream.Collectors; -import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC; +import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE; /** * Generate the DOT file for a module graph for each module in the JDK @@ -172,14 +172,14 @@ Graph graph = gengraph(cf); descriptors.forEach(md -> { String mn = md.name(); - Set requiresPublic = md.requires().stream() - .filter(d -> d.modifiers().contains(PUBLIC)) + Set requiresTransitive = md.requires().stream() + .filter(d -> d.modifiers().contains(TRANSITIVE)) .map(d -> d.name()) .collect(Collectors.toSet()); graph.adjacentNodes(mn).forEach(dn -> { String attr = dn.equals("java.base") ? REQUIRES_BASE - : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES); + : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES); int w = weightOf(mn, dn); if (w > 1) attr += "weight=" + w; @@ -194,8 +194,8 @@ /** * Returns a Graph of the given Configuration after transitive reduction. * - * Transitive reduction of requires public edge and requires edge have - * to be applied separately to prevent the requires public edges + * Transitive reduction of requires transitive edge and requires edge have + * to be applied separately to prevent the requires transitive edges * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V) * in which V would not be re-exported from U. */ @@ -208,21 +208,21 @@ .map(ResolvedModule::name) .forEach(target -> builder.addEdge(mn, target)); } - Graph rpg = requiresPublicGraph(cf); + Graph rpg = requiresTransitiveGraph(cf); return builder.build().reduce(rpg); } /** - * Returns a Graph containing only requires public edges + * Returns a Graph containing only requires transitive edges * with transitive reduction. */ - private Graph requiresPublicGraph(Configuration cf) { + private Graph requiresTransitiveGraph(Configuration cf) { Graph.Builder builder = new Graph.Builder<>(); for (ResolvedModule resolvedModule : cf.modules()) { ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); String mn = descriptor.name(); descriptor.requires().stream() - .filter(d -> d.modifiers().contains(PUBLIC)) + .filter(d -> d.modifiers().contains(TRANSITIVE)) .map(d -> d.name()) .forEach(d -> builder.addEdge(mn, d)); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java --- a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java Thu Dec 01 08:57:53 2016 +0000 @@ -299,7 +299,7 @@ static class HtmlDocument { final String title; final Map modules; - boolean requiresPublicNote = false; + boolean requiresTransitiveNote = false; boolean aggregatorNote = false; boolean totalBytesNote = false; HtmlDocument(String title, Map modules) { @@ -510,16 +510,16 @@ public String requiresColumn() { StringBuilder sb = new StringBuilder(); sb.append(String.format("")); - boolean footnote = requiresPublicNote; + boolean footnote = requiresTransitiveNote; ms.descriptor().requires().stream() .sorted(Comparator.comparing(Requires::name)) .forEach(r -> { - boolean requiresPublic = r.modifiers().contains(Requires.Modifier.PUBLIC); - Selector sel = requiresPublic ? REQUIRES_PUBLIC : REQUIRES; + boolean requiresTransitive = r.modifiers().contains(Requires.Modifier.TRANSITIVE); + Selector sel = requiresTransitive ? REQUIRES_PUBLIC : REQUIRES; String req = String.format("%s", sel, r.name(), r.name()); - if (!requiresPublicNote && requiresPublic) { - requiresPublicNote = true; + if (!requiresTransitiveNote && requiresTransitive) { + requiresTransitiveNote = true; req += "*"; } sb.append(req).append("\n").append("
"); @@ -534,8 +534,8 @@ sb.append("
"); sb.append("+").append(indirectDeps).append(" transitive dependencies"); } - if (footnote != requiresPublicNote) { - sb.append("

").append("* bold denotes requires public"); + if (footnote != requiresTransitiveNote) { + sb.append("

").append("* bold denotes requires transitive"); } sb.append(""); return sb.toString(); @@ -558,11 +558,10 @@ ms.descriptor().uses().stream() .sorted() .forEach(s -> sb.append("uses ").append(s).append("
").append("\n")); - ms.descriptor().provides().entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .flatMap(e -> e.getValue().providers().stream() - .map(p -> String.format("provides %s
    with %s", - e.getKey(), p))) + ms.descriptor().provides().stream() + .sorted(Comparator.comparing(Provides::service)) + .map(p -> String.format("provides %s
    with %s", + p.service(), p.providers())) .forEach(p -> sb.append(p).append("
").append("\n")); sb.append(""); return sb.toString(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java --- a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,219 +30,593 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; +import java.util.stream.Stream; +import static java.util.stream.Collectors.*; /** * A build tool to extend the module-info.java in the source tree for - * platform-specific exports, uses, and provides and write to the specified - * output file. Injecting platform-specific requires is not supported. + * platform-specific exports, opens, uses, and provides and write to + * the specified output file. + * + * GenModuleInfoSource will be invoked for each module that has + * module-info.java.extra in the source directory. * - * The extra exports, uses, provides can be specified in module-info.java.extra - * files and GenModuleInfoSource will be invoked for each module that has - * module-info.java.extra in the source directory. + * The extra exports, opens, uses, provides can be specified + * in module-info.java.extra. + * Injecting platform-specific requires is not supported. + * + * @see build.tools.module.ModuleInfoExtraTest for basic testing */ public class GenModuleInfoSource { private final static String USAGE = - "Usage: GenModuleInfoSource [option] -o \n" + - "Options are:\n" + - " -exports \n" + - " -exports [/]\n" + - " -uses \n" + - " -provides /\n"; + "Usage: GenModuleInfoSource -o \n" + + " --source-file \n" + + " --modules [,...]\n" + + " ...\n"; + static boolean verbose = false; public static void main(String... args) throws Exception { Path outfile = null; Path moduleInfoJava = null; - GenModuleInfoSource genModuleInfo = new GenModuleInfoSource(); - + Set modules = Collections.emptySet(); + List extras = new ArrayList<>(); // validate input arguments for (int i = 0; i < args.length; i++){ String option = args[i]; - if (option.startsWith("-")) { - String arg = args[++i]; - if (option.equals("-exports")) { - int index = arg.indexOf('/'); - if (index > 0) { - String pn = arg.substring(0, index); - String mn = arg.substring(index + 1, arg.length()); - genModuleInfo.exportTo(pn, mn); - } else { - genModuleInfo.export(arg); - } - } else if (option.equals("-uses")) { - genModuleInfo.use(arg); - } else if (option.equals("-provides")) { - int index = arg.indexOf('/'); - if (index <= 0) { - throw new IllegalArgumentException("invalid -provide argument: " + arg); - } - String service = arg.substring(0, index); - String impl = arg.substring(index + 1, arg.length()); - genModuleInfo.provide(service, impl); - } else if (option.equals("-o")) { + String arg = i+1 < args.length ? args[i+1] : null; + switch (option) { + case "-o": outfile = Paths.get(arg); - } else { - throw new IllegalArgumentException("invalid option: " + option); - } - } else if (moduleInfoJava != null) { - throw new IllegalArgumentException("more than one module-info.java"); - } else { - moduleInfoJava = Paths.get(option); - if (Files.notExists(moduleInfoJava)) { - throw new IllegalArgumentException(option + " not exist"); - } + i++; + break; + case "--source-file": + moduleInfoJava = Paths.get(arg); + if (Files.notExists(moduleInfoJava)) { + throw new IllegalArgumentException(moduleInfoJava + " not exist"); + } + i++; + break; + case "--modules": + modules = Arrays.stream(arg.split(",")) + .collect(toSet()); + i++; + break; + case "-v": + verbose = true; + break; + default: + Path file = Paths.get(option); + if (Files.notExists(file)) { + throw new IllegalArgumentException(file + " not exist"); + } + extras.add(file); } } - if (moduleInfoJava == null || outfile == null) { + if (moduleInfoJava == null || outfile == null || + modules.isEmpty() || extras.isEmpty()) { System.err.println(USAGE); System.exit(-1); } - // generate new module-info.java - genModuleInfo.generate(moduleInfoJava, outfile); - } + GenModuleInfoSource genModuleInfo = + new GenModuleInfoSource(moduleInfoJava, extras, modules); - private final Set exports = new HashSet<>(); - private final Map> exportsTo = new HashMap<>(); - private final Set uses = new HashSet<>(); - private final Map> provides = new HashMap<>(); - GenModuleInfoSource() { + // generate new module-info.java + genModuleInfo.generate(outfile); } - private void export(String p) { - Objects.requireNonNull(p); - if (exports.contains(p) || exportsTo.containsKey(p)) { - throw new RuntimeException("duplicated exports: " + p); + final Path sourceFile; + final List extraFiles; + final ModuleInfo extras; + final Set modules; + final ModuleInfo moduleInfo; + GenModuleInfoSource(Path sourceFile, List extraFiles, Set modules) + throws IOException + { + this.sourceFile = sourceFile; + this.extraFiles = extraFiles; + this.modules = modules; + this.moduleInfo = new ModuleInfo(); + this.moduleInfo.parse(sourceFile); + + // parse module-info.java.extra + this.extras = new ModuleInfo(); + for (Path file : extraFiles) { + extras.parse(file); } - exports.add(p); - } - private void exportTo(String p, String mn) { - Objects.requireNonNull(p); - Objects.requireNonNull(mn); - if (exports.contains(p)) { - throw new RuntimeException("unqualified exports already exists: " + p); - } - exportsTo.computeIfAbsent(p, _k -> new HashSet<>()).add(mn); + + // merge with module-info.java.extra + moduleInfo.augmentModuleInfo(extras, modules); } - private void use(String service) { - uses.add(service); - } + void generate(Path output) throws IOException { + List lines = Files.readAllLines(sourceFile); + try (BufferedWriter bw = Files.newBufferedWriter(output); + PrintWriter writer = new PrintWriter(bw)) { + // write the copyright header and lines up to module declaration + for (String l : lines) { + writer.println(l); + if (l.trim().startsWith("module ")) { + writer.format(" // source file: %s%n", sourceFile); + for (Path file: extraFiles) { + writer.format(" // %s%n", file); + } + break; + } + } - private void provide(String s, String impl) { - provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl); + // requires + for (String l : lines) { + if (l.trim().startsWith("requires")) + writer.println(l); + } + + // write exports, opens, uses, and provides + moduleInfo.print(writer); + + // close + writer.println("}"); + } } - private void generate(Path sourcefile, Path outfile) throws IOException { - Path parent = outfile.getParent(); - if (parent != null) - Files.createDirectories(parent); + + class ModuleInfo { + final Map exports = new HashMap<>(); + final Map opens = new HashMap<>(); + final Map uses = new HashMap<>(); + final Map provides = new HashMap<>(); + + Statement getStatement(String directive, String name) { + switch (directive) { + case "exports": + if (moduleInfo.exports.containsKey(name) && + moduleInfo.exports.get(name).isUnqualified()) { + throw new IllegalArgumentException(sourceFile + + " already has " + directive + " " + name); + } + return exports.computeIfAbsent(name, + _n -> new Statement("exports", "to", name)); + + case "opens": + if (moduleInfo.opens.containsKey(name) && + moduleInfo.opens.get(name).isUnqualified()) { + throw new IllegalArgumentException(sourceFile + + " already has " + directive + " " + name); + } + + if (moduleInfo.opens.containsKey(name)) { + throw new IllegalArgumentException(sourceFile + + " already has " + directive + " " + name); + } + return opens.computeIfAbsent(name, + _n -> new Statement("opens", "to", name)); + + case "uses": + return uses.computeIfAbsent(name, + _n -> new Statement("uses", "", name)); + + case "provides": + return provides.computeIfAbsent(name, + _n -> new Statement("provides", "with", name, true)); + + default: + throw new IllegalArgumentException(directive); + } + + } + + /* + * Augment this ModuleInfo with module-info.java.extra + */ + void augmentModuleInfo(ModuleInfo extraFiles, Set modules) { + // API package exported in the original module-info.java + extraFiles.exports.entrySet() + .stream() + .filter(e -> exports.containsKey(e.getKey()) && + e.getValue().filter(modules)) + .forEach(e -> mergeExportsOrOpens(exports.get(e.getKey()), + e.getValue(), + modules)); + + // add exports that are not defined in the original module-info.java + extraFiles.exports.entrySet() + .stream() + .filter(e -> !exports.containsKey(e.getKey()) && + e.getValue().filter(modules)) + .forEach(e -> addTargets(getStatement("exports", e.getKey()), + e.getValue(), + modules)); + + // API package opened in the original module-info.java + extraFiles.opens.entrySet() + .stream() + .filter(e -> opens.containsKey(e.getKey()) && + e.getValue().filter(modules)) + .forEach(e -> mergeExportsOrOpens(opens.get(e.getKey()), + e.getValue(), + modules)); + + // add opens that are not defined in the original module-info.java + extraFiles.opens.entrySet() + .stream() + .filter(e -> !opens.containsKey(e.getKey()) && + e.getValue().filter(modules)) + .forEach(e -> addTargets(getStatement("opens", e.getKey()), + e.getValue(), + modules)); + + // provides + extraFiles.provides.keySet() + .stream() + .filter(service -> provides.containsKey(service)) + .forEach(service -> mergeProvides(service, + extraFiles.provides.get(service))); + extraFiles.provides.keySet() + .stream() + .filter(service -> !provides.containsKey(service)) + .forEach(service -> provides.put(service, + extraFiles.provides.get(service))); + + // uses + extraFiles.uses.keySet() + .stream() + .filter(service -> !uses.containsKey(service)) + .forEach(service -> uses.put(service, extraFiles.uses.get(service))); + } + + // add qualified exports or opens to known modules only + private void addTargets(Statement statement, + Statement extra, + Set modules) + { + extra.targets.stream() + .filter(mn -> modules.contains(mn)) + .forEach(mn -> statement.addTarget(mn)); + } + + private void mergeExportsOrOpens(Statement statement, + Statement extra, + Set modules) + { + String pn = statement.name; + if (statement.isUnqualified() && extra.isQualified()) { + throw new RuntimeException("can't add qualified exports to " + + "unqualified exports " + pn); + } + + Set mods = extra.targets.stream() + .filter(mn -> statement.targets.contains(mn)) + .collect(toSet()); + if (mods.size() > 0) { + throw new RuntimeException("qualified exports " + pn + " to " + + mods.toString() + " already declared in " + sourceFile); + } + + // add qualified exports or opens to known modules only + addTargets(statement, extra, modules); + } + + private void mergeProvides(String service, Statement extra) { + Statement statement = provides.get(service); - List lines = Files.readAllLines(sourcefile); - try (BufferedWriter bw = Files.newBufferedWriter(outfile); - PrintWriter writer = new PrintWriter(bw)) { - int lineNumber = 0; - for (String l : lines) { - lineNumber++; - String[] s = l.trim().split("\\s+"); - String keyword = s[0].trim(); - int nextIndex = keyword.length(); - String exp = null; - int n = l.length(); - switch (keyword) { - case "exports": - boolean inExportsTo = false; - // assume package name immediately after exports - exp = s[1].trim(); - if (s.length >= 3) { - nextIndex = l.indexOf(exp, nextIndex) + exp.length(); - if (s[2].trim().equals("to")) { - inExportsTo = true; - n = l.indexOf("to", nextIndex) + "to".length(); - } else { + Set mods = extra.targets.stream() + .filter(mn -> statement.targets.contains(mn)) + .collect(toSet()); + + if (mods.size() > 0) { + throw new RuntimeException("qualified exports " + service + " to " + + mods.toString() + " already declared in " + sourceFile); + } + + extra.targets.stream() + .forEach(mn -> statement.addTarget(mn)); + } + + + void print(PrintWriter writer) { + // print unqualified exports + exports.entrySet().stream() + .filter(e -> e.getValue().targets.isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writer.println(e.getValue())); + + // print qualified exports + exports.entrySet().stream() + .filter(e -> !e.getValue().targets.isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writer.println(e.getValue())); + + // print unqualified opens + opens.entrySet().stream() + .filter(e -> e.getValue().targets.isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writer.println(e.getValue())); + + // print qualified opens + opens.entrySet().stream() + .filter(e -> !e.getValue().targets.isEmpty()) + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writer.println(e.getValue())); + + // uses and provides + writer.println(); + uses.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writer.println(e.getValue())); + provides.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> writer.println(e.getValue())); + } + + private void parse(Path sourcefile) throws IOException { + List lines = Files.readAllLines(sourcefile); + Statement statement = null; + boolean hasTargets = false; + + for (int lineNumber = 1; lineNumber <= lines.size(); ) { + String l = lines.get(lineNumber-1).trim(); + int index = 0; + + if (l.isEmpty()) { + lineNumber++; + continue; + } + + // comment block starts + if (l.startsWith("/*")) { + while (l.indexOf("*/") == -1) { // end comment block + l = lines.get(lineNumber++).trim(); + } + index = l.indexOf("*/") + 2; + if (index >= l.length()) { + lineNumber++; + continue; + } else { + // rest of the line + l = l.substring(index, l.length()).trim(); + index = 0; + } + } + + // skip comment and annotations + if (l.startsWith("//") || l.startsWith("@")) { + lineNumber++; + continue; + } + + int current = lineNumber; + int count = 0; + while (index < l.length()) { + if (current == lineNumber && ++count > 20) + throw new Error("Fail to parse line " + lineNumber + " " + sourcefile); + + int end = l.indexOf(';'); + if (end == -1) + end = l.length(); + String content = l.substring(0, end).trim(); + if (content.isEmpty()) { + index = end+1; + if (index < l.length()) { + // rest of the line + l = l.substring(index, l.length()).trim(); + index = 0; + } + continue; + } + + String[] s = content.split("\\s+"); + String keyword = s[0].trim(); + + String name = s.length > 1 ? s[1].trim() : null; + trace("%d: %s index=%d len=%d%n", lineNumber, l, index, l.length()); + switch (keyword) { + case "module": + case "requires": + case "}": + index = l.length(); // skip to the end + continue; + + case "exports": + case "opens": + case "provides": + case "uses": + // assume name immediately after exports, opens, provides, uses + statement = getStatement(keyword, name); + hasTargets = false; + + int i = l.indexOf(name, keyword.length()+1) + name.length() + 1; + l = i < l.length() ? l.substring(i, l.length()).trim() : ""; + index = 0; + + if (s.length >= 3) { + if (!s[2].trim().equals(statement.qualifier)) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed: " + s[2]); + } + } + + break; + + case "to": + case "with": + if (statement == null) { throw new RuntimeException(sourcefile + ", line " + - lineNumber + ", is malformed: " + s[2]); + lineNumber + ", is malformed"); } - } + + hasTargets = true; + String qualifier = statement.qualifier; + i = l.indexOf(qualifier, index) + qualifier.length() + 1; + l = i < l.length() ? l.substring(i, l.length()).trim() : ""; + index = 0; + break; + } - // inject the extra targets after "to" - if (inExportsTo) { - writer.println(injectExportTargets(exp, l, n)); + if (index >= l.length()) { + // skip to next line + continue; + } + + // comment block starts + if (l.startsWith("/*")) { + while (l.indexOf("*/") == -1) { // end comment block + l = lines.get(lineNumber++).trim(); + } + index = l.indexOf("*/") + 2; + if (index >= l.length()) { + continue; } else { - writer.println(l); + // rest of the line + l = l.substring(index, l.length()).trim(); + index = 0; } - break; - case "to": - if (exp == null) { - throw new RuntimeException(sourcefile + ", line " + - lineNumber + ", is malformed"); - } - n = l.indexOf("to", nextIndex) + "to".length(); - writer.println(injectExportTargets(exp, l, n)); - break; - case "}": - doAugments(writer); - // fall through - default: - writer.println(l); - // reset exports - exp = null; + } + + if (l.startsWith("//")) { + index = l.length(); + continue; + } + + if (statement == null) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ": missing keyword?"); + } + + if (!hasTargets) { + continue; + } + + if (index >= l.length()) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ": " + l); + } + + // parse the target module of exports, opens, or provides + Statement stmt = statement; + + int terminal = l.indexOf(';', index); + // determine up to which position to parse + int pos = terminal != -1 ? terminal : l.length(); + // parse up to comments + int pos1 = l.indexOf("//", index); + if (pos1 != -1 && pos1 < pos) { + pos = pos1; + } + int pos2 = l.indexOf("/*", index); + if (pos2 != -1 && pos2 < pos) { + pos = pos2; + } + // target module(s) for qualitifed exports or opens + // or provider implementation class(es) + String rhs = l.substring(index, pos).trim(); + index += rhs.length(); + trace("rhs: index=%d [%s] [line: %s]%n", index, rhs, l); + + String[] targets = rhs.split(","); + for (String t : targets) { + String n = t.trim(); + if (n.length() > 0) + stmt.addTarget(n); + } + + // start next statement + if (pos == terminal) { + statement = null; + hasTargets = false; + index = terminal + 1; + } + l = index < l.length() ? l.substring(index, l.length()).trim() : ""; + index = 0; } + + lineNumber++; } } } - private String injectExportTargets(String pn, String exp, int pos) { - Set targets = exportsTo.remove(pn); - if (targets != null) { - StringBuilder sb = new StringBuilder(); - // inject the extra targets after the given pos - sb.append(exp.substring(0, pos)) - .append("\n\t") - .append(targets.stream() - .collect(Collectors.joining(",", "", ","))) - .append(" /* injected */"); - if (pos < exp.length()) { - // print the remaining statement followed "to" - sb.append("\n\t") - .append(exp.substring(pos+1, exp.length())); + static class Statement { + final String directive; + final String qualifier; + final String name; + final Set targets = new LinkedHashSet<>(); + final boolean ordered; + + Statement(String directive, String qualifier, String name) { + this(directive, qualifier, name, false); + } + + Statement(String directive, String qualifier, String name, boolean ordered) { + this.directive = directive; + this.qualifier = qualifier; + this.name = name; + this.ordered = ordered; + } + + Statement addTarget(String mn) { + if (mn.isEmpty()) + throw new IllegalArgumentException("empty module name"); + targets.add(mn); + return this; + } + + boolean isQualified() { + return targets.size() > 0; + } + + boolean isUnqualified() { + return targets.isEmpty(); + } + + /** + * Returns true if this statement is unqualified or it has + * at least one target in the given names. + */ + boolean filter(Set names) { + if (isUnqualified()) { + return true; + } else { + return targets.stream() + .filter(mn -> names.contains(mn)) + .findAny().isPresent(); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(" "); + sb.append(directive).append(" ").append(name); + if (targets.isEmpty()) { + sb.append(";"); + } else if (targets.size() == 1) { + sb.append(" ").append(qualifier) + .append(orderedTargets().collect(joining(",", " ", ";"))); + } else { + sb.append(" ").append(qualifier) + .append(orderedTargets() + .map(target -> String.format(" %s", target)) + .collect(joining(",\n", "\n", ";"))); } return sb.toString(); - } else { - return exp; + } + + public Stream orderedTargets() { + return ordered ? targets.stream() + : targets.stream().sorted(); } } - private void doAugments(PrintWriter writer) { - if ((exports.size() + exportsTo.size() + uses.size() + provides.size()) == 0) - return; - - writer.println(" // augmented from module-info.java.extra"); - exports.stream() - .sorted() - .forEach(e -> writer.format(" exports %s;%n", e)); - // remaining injected qualified exports - exportsTo.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .map(e -> String.format(" exports %s to%n%s;", e.getKey(), - e.getValue().stream().sorted() - .map(mn -> String.format(" %s", mn)) - .collect(Collectors.joining(",\n")))) - .forEach(writer::println); - uses.stream().sorted() - .forEach(s -> writer.format(" uses %s;%n", s)); - provides.entrySet().stream() - .sorted(Map.Entry.comparingByKey()) - .flatMap(e -> e.getValue().stream().sorted() - .map(impl -> String.format(" provides %s with %s;", - e.getKey(), impl))) - .forEach(writer::println); + static void trace(String fmt, Object... params) { + if (verbose) { + System.out.format(fmt, params); + } } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.module; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import build.tools.module.GenModuleInfoSource.Statement; + +/** + * Sanity test for GenModuleInfoSource tool + */ +public class ModuleInfoExtraTest { + private static final Path DIR = Paths.get("test"); + public static void main(String... args) throws Exception { + if (args.length != 0) + GenModuleInfoSource.verbose = true; + + ModuleInfoExtraTest test = new ModuleInfoExtraTest("m", "m1", "m2", "m3"); + test.run(); + } + + String[] moduleInfo = new String[] { + "exports p", + "to", + " // comment", + " /* comment */ m1", + ",", + "m2,m3", + " ;", + "exports q to m1;", + "provides s with /* ", + " comment */ impl ; // comment", + "provides s1", + " with ", + " impl1, impl2;" + }; + + String[] moduleInfoExtra = new String[] { + "exports q", + "to", + " m2 // comment", + " /* comment */;", + " ;", + "opens p.q ", + " to /* comment */ m3", + " , // m1", + " /* comment */, m4;", + "provides s1 with impl3;" + }; + + String[] test1 = new String[] { + "exports p1 to m1;", + "exports p2" + }; + + String[] test2 = new String[] { + "exports to m1;" + }; + + String[] test3 = new String[]{ + "exports p3 to m1;", + " m2, m3;" + }; + + String[] test4 = new String[]{ + "provides s with impl1;", // typo ; should be , + " impl2, impl3;" + }; + + String[] test5 = new String[]{ + "uses s3", + "provides s3 with impl1,", + " impl2, impl3;" + }; + + final Builder builder; + ModuleInfoExtraTest(String name, String... modules) { + this.builder = new Builder(name).modules(modules); + } + + void run() throws IOException { + testModuleInfo(); + errorCases(); + } + + + void testModuleInfo() throws IOException { + GenModuleInfoSource source = builder.sourceFile(moduleInfo).build(); + Set targetsP = new HashSet<>(); + targetsP.add("m1"); + targetsP.add("m2"); + targetsP.add("m3"); + + Set targetsQ = new HashSet<>(); + targetsQ.add("m1"); + + Set providerS = new HashSet<>(); + providerS.add("impl"); + + Set providerS1 = new HashSet<>(); + providerS1.add("impl1"); + providerS1.add("impl2"); + + Set opensPQ = new HashSet<>(); + + check(source, targetsP, targetsQ, opensPQ, providerS, providerS1); + + // augment with extra + Path file = DIR.resolve("extra"); + Files.write(file, Arrays.asList(moduleInfoExtra)); + source = builder.build(file); + + targetsQ.add("m2"); + providerS1.add("impl3"); + + opensPQ.add("m3"); + check(source, targetsP, targetsQ, opensPQ, providerS, providerS1); + } + + void check(GenModuleInfoSource source, + Set targetsP, + Set targetsQ, + Set opensPQ, + Set providerS, + Set providerS1) { + source.moduleInfo.print(new PrintWriter(System.out, true)); + Statement export = source.moduleInfo.exports.get("p"); + if (!export.targets.equals(targetsP)) { + throw new Error("unexpected: " + export); + } + + export = source.moduleInfo.exports.get("q"); + if (!export.targets.equals(targetsQ)) { + throw new Error("unexpected: " + export); + } + + Statement provides = source.moduleInfo.provides.get("s"); + if (!provides.targets.equals(providerS)) { + throw new Error("unexpected: " + provides); + } + + provides = source.moduleInfo.provides.get("s1"); + if (!provides.targets.equals(providerS1)) { + throw new Error("unexpected: " + provides); + } + } + + + + void errorCases() throws IOException { + fail(test1); + fail(test2); + fail(test3); + fail(test4); + fail(test5); + } + + void fail(String... extras) throws IOException { + Path file = DIR.resolve("test1"); + Files.write(file, Arrays.asList(extras)); + try { + builder.build(file); + } catch (RuntimeException e) { + if (!e.getMessage().matches("test/test1, line .* is malformed.*") && + !e.getMessage().matches("test/test1, line .* missing keyword.*")) { + throw e; + } + } + } + + static class Builder { + final String moduleName; + final Path sourceFile; + final Set modules = new HashSet<>(); + public Builder(String name) { + this.moduleName = name; + this.sourceFile = DIR.resolve(name).resolve("module-info.java"); + } + + public Builder modules(String... names) { + Arrays.stream(names).forEach(modules::add); + return this; + } + + public Builder sourceFile(String... lines) throws IOException { + Files.createDirectories(sourceFile.getParent()); + try (BufferedWriter bw = Files.newBufferedWriter(sourceFile); + PrintWriter writer = new PrintWriter(bw)) { + writer.format("module %s {%n", moduleName); + for (String l : lines) { + writer.println(l); + } + writer.println("}"); + } + return this; + } + + public GenModuleInfoSource build() throws IOException { + return build(Collections.emptyList()); + } + + public GenModuleInfoSource build(Path extraFile) throws IOException { + return build(Collections.singletonList(extraFile)); + } + + public GenModuleInfoSource build(List extraFiles) throws IOException { + return new GenModuleInfoSource(sourceFile, extraFiles, modules); + } + } + +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties --- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties Thu Dec 01 08:57:53 2016 +0000 @@ -15,12 +15,12 @@ pack.class.attribute.CompilationID = RUH # Module attributes, supported by the tool and not JSR-200 -pack.class.attribute.Module = NH[RUHFH]NH[RUHNH[RUH]]NH[RCH]NH[RCHRCH] -pack.class.attribute.ConcealedPackages = NH[RUH] -pack.class.attribute.Version = RUH -pack.class.attribute.MainClass = RCH -pack.class.attribute.TargetPlatform = RUHRUHRUH -pack.class.attribute.Hashes = RUHNH[RUHRUH] +pack.class.attribute.Module = RUHFHNH[RUHFH]NH[RUHFHNH[RUH]]NH[RUHFHNH[RUH]]NH[RCH]NH[RCHNH[RCH]] +pack.class.attribute.ModulePackages = NH[RUH] +pack.class.attribute.ModuleVersion = RUH +pack.class.attribute.ModuleMainClass = RCH +pack.class.attribute.ModuleTarget = RUHRUHRUH +pack.class.attribute.ModuleHashes = RUHNH[RUHNH[B]] # Note: Zero-length ("marker") attributes do not need to be specified here. diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/Class.java --- a/jdk/src/java.base/share/classes/java/lang/Class.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/Class.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,46 +26,55 @@ package java.lang; import java.lang.annotation.Annotation; +import java.lang.module.ModuleDescriptor.Version; +import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.GenericDeclaration; -import java.lang.reflect.Member; -import java.lang.reflect.Field; -import java.lang.reflect.Executable; -import java.lang.reflect.Method; -import java.lang.reflect.Module; -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.AnnotatedType; -import java.lang.reflect.Proxy; import java.lang.ref.SoftReference; import java.io.IOException; import java.io.InputStream; import java.io.ObjectStreamField; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Layer; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Module; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.Set; -import java.util.Map; -import java.util.HashMap; -import java.util.Objects; import java.util.StringJoiner; +import java.util.stream.Collectors; + import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.loader.ResourceHelper; +import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; +import jdk.internal.module.ModuleHashes; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.ConstantPool; import jdk.internal.reflect.Reflection; @@ -442,21 +451,10 @@ PrivilegedAction pa = module::getClassLoader; ClassLoader cl = AccessController.doPrivileged(pa); - if (module.isNamed() && cl != null) { - return cl.loadLocalClass(module, name); - } - - final Class c; if (cl != null) { - c = cl.loadLocalClass(name); + return cl.loadClass(module, name); } else { - c = BootLoader.loadClassOrNull(name); - } - - if (c != null && c.getModule() == module) { - return c; - } else { - return null; + return BootLoader.loadClass(module, name); } } @@ -979,7 +977,7 @@ } // cached package name - private String packageName; + private transient String packageName; /** * Returns the interfaces directly implemented by the class or interface @@ -1976,6 +1974,22 @@ return method; } + /** + * Returns a {@code Method} object that reflects the specified public + * member method of the class or interface represented by this + * {@code Class} object. + * + * @param name the name of the method + * @param parameterTypes the list of parameters + * @return the {@code Method} object that matches the specified + * {@code name} and {@code parameterTypes}; {@code null} + * if the method is not found or the name is + * "<init>"or "<clinit>". + */ + Method getMethodOrNull(String name, Class... parameterTypes) { + return getMethod0(name, parameterTypes, true); + } + /** * Returns a {@code Constructor} object that reflects the specified @@ -2367,12 +2381,17 @@ } /** - * Finds a resource with a given name. If this class is in a named {@link - * Module Module}, and the caller of this method is in the same module, - * then this method will attempt to find the resource in that module. - * Otherwise, the rules for searching resources - * associated with a given class are implemented by the defining - * {@linkplain ClassLoader class loader} of the class. This method + * Finds a resource with a given name. + * + *

If this class is in a named {@link Module Module} then this method + * will attempt to find the resource in the module by means of the absolute + * resource name, subject to the rules for encapsulation specified in the + * {@code Module} {@link Module#getResourceAsStream getResourceAsStream} + * method. + * + *

Otherwise, if this class is not in a named module then the rules for + * searching resources associated with a given class are implemented by the + * defining {@linkplain ClassLoader class loader} of the class. This method * delegates to this object's class loader. If this object was loaded by * the bootstrap class loader, the method delegates to {@link * ClassLoader#getSystemResourceAsStream}. @@ -2400,8 +2419,11 @@ * * * @param name name of the desired resource - * @return A {@link java.io.InputStream} object or {@code null} if - * no resource with this name is found + * @return A {@link java.io.InputStream} object; {@code null} if no + * resource with this name is found, the resource is in a package + * that is not {@link Module#isOpen(String, Module) open} to at + * least the caller module, or access to the resource is denied + * by the security manager. * @throws NullPointerException If {@code name} is {@code null} * @since 1.1 */ @@ -2409,35 +2431,41 @@ public InputStream getResourceAsStream(String name) { name = resolveName(name); - // if this Class and the caller are in the same named module - // then attempt to get an input stream to the resource in the - // module Module module = getModule(); if (module.isNamed()) { - Class caller = Reflection.getCallerClass(); - if (caller != null && caller.getModule() == module) { - ClassLoader cl = getClassLoader0(); - String mn = module.getName(); - try { - - // special-case built-in class loaders to avoid the - // need for a URL connection - if (cl == null) { - return BootLoader.findResourceAsStream(mn, name); - } else if (cl instanceof BuiltinClassLoader) { - return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name); - } else { - URL url = cl.findResource(mn, name); - return (url != null) ? url.openStream() : null; + if (!ResourceHelper.isSimpleResource(name)) { + Module caller = Reflection.getCallerClass().getModule(); + if (caller != module) { + Set packages = module.getDescriptor().packages(); + String pn = ResourceHelper.getPackageName(name); + if (packages.contains(pn) && !module.isOpen(pn, caller)) { + // resource is in package not open to caller + return null; } - - } catch (IOException | SecurityException e) { - return null; } } + + String mn = module.getName(); + ClassLoader cl = getClassLoader0(); + try { + + // special-case built-in class loaders to avoid the + // need for a URL connection + if (cl == null) { + return BootLoader.findResourceAsStream(mn, name); + } else if (cl instanceof BuiltinClassLoader) { + return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name); + } else { + URL url = cl.findResource(mn, name); + return (url != null) ? url.openStream() : null; + } + + } catch (IOException | SecurityException e) { + return null; + } } - // this Class and caller not in the same named module + // unnamed module ClassLoader cl = getClassLoader0(); if (cl == null) { return ClassLoader.getSystemResourceAsStream(name); @@ -2447,12 +2475,17 @@ } /** - * Finds a resource with a given name. If this class is in a named {@link - * Module Module}, and the caller of this method is in the same module, - * then this method will attempt to find the resource in that module. - * Otherwise, the rules for searching resources - * associated with a given class are implemented by the defining - * {@linkplain ClassLoader class loader} of the class. This method + * Finds a resource with a given name. + * + *

If this class is in a named {@link Module Module} then this method + * will attempt to find the resource in the module by means of the absolute + * resource name, subject to the rules for encapsulation specified in the + * {@code Module} {@link Module#getResourceAsStream getResourceAsStream} + * method. + * + *

Otherwise, if this class is not in a named module then the rules for + * searching resources associated with a given class are implemented by the + * defining {@linkplain ClassLoader class loader} of the class. This method * delegates to this object's class loader. If this object was loaded by * the bootstrap class loader, the method delegates to {@link * ClassLoader#getSystemResource}. @@ -2479,35 +2512,46 @@ * * * @param name name of the desired resource - * @return A {@link java.net.URL} object; {@code null} if no - * resource with this name is found or the resource cannot - * be located by a URL. + * @return A {@link java.net.URL} object; {@code null} if no resource with + * this name is found, the resource cannot be located by a URL, the + * resource is in a package that is not + * {@link Module#isOpen(String, Module) open} to at least the caller + * module, or access to the resource is denied by the security + * manager. + * @throws NullPointerException If {@code name} is {@code null} * @since 1.1 */ @CallerSensitive public URL getResource(String name) { name = resolveName(name); - // if this Class and the caller are in the same named module - // then attempt to get URL to the resource in the module Module module = getModule(); if (module.isNamed()) { - Class caller = Reflection.getCallerClass(); - if (caller != null && caller.getModule() == module) { - String mn = getModule().getName(); - ClassLoader cl = getClassLoader0(); - try { - if (cl == null) { - return BootLoader.findResource(mn, name); - } else { - return cl.findResource(mn, name); + if (!ResourceHelper.isSimpleResource(name)) { + Module caller = Reflection.getCallerClass().getModule(); + if (caller != module) { + Set packages = module.getDescriptor().packages(); + String pn = ResourceHelper.getPackageName(name); + if (packages.contains(pn) && !module.isOpen(pn, caller)) { + // resource is in package not open to caller + return null; } - } catch (IOException ioe) { - return null; } } + String mn = getModule().getName(); + ClassLoader cl = getClassLoader0(); + try { + if (cl == null) { + return BootLoader.findResource(mn, name); + } else { + return cl.findResource(mn, name); + } + } catch (IOException ioe) { + return null; + } } + // unnamed module ClassLoader cl = getClassLoader0(); if (cl == null) { return ClassLoader.getSystemResource(name); @@ -2632,9 +2676,6 @@ * if name is absolute */ private String resolveName(String name) { - if (name == null) { - return name; - } if (!name.startsWith("/")) { Class c = this; while (c.isArray()) { diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/ClassLoader.java --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Thu Dec 01 08:57:53 2016 +0000 @@ -42,15 +42,14 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.HashSet; import java.util.Hashtable; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.Stack; -import java.util.NoSuchElementException; import java.util.Vector; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; @@ -59,7 +58,6 @@ import java.util.stream.StreamSupport; import jdk.internal.perf.PerfCounter; -import jdk.internal.module.ServicesCatalog; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; import jdk.internal.misc.SharedSecrets; @@ -411,7 +409,6 @@ this(checkCreateClassLoader(), null, parent); } - /** * Creates a new class loader using the ClassLoader returned by * the method {@link #getSystemClassLoader() @@ -431,7 +428,6 @@ this(checkCreateClassLoader(), null, getSystemClassLoader()); } - /** * Returns the name of this class loader or {@code null} if * this class loader is not named. @@ -581,7 +577,7 @@ * @return The resulting {@code Class} object in a module defined by * this class loader, or {@code null} if the class could not be found. */ - final Class loadLocalClass(Module module, String name) { + final Class loadClass(Module module, String name) { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); @@ -597,34 +593,6 @@ } /** - * Loads the class with the specified binary name - * defined by this class loader. This method returns {@code null} - * if the class could not be found. - * - * @apiNote This method does not delegate to the parent class loader. - * - * @param name - * The binary name of the class - * - * @return The resulting {@code Class} object in a module defined by - * this class loader, or {@code null} if the class could not be found. - */ - final Class loadLocalClass(String name) { - synchronized (getClassLoadingLock(name)) { - // First, check if the class has already been loaded - Class c = findLoadedClass(name); - if (c == null) { - try { - return findClass(name); - } catch (ClassNotFoundException e) { - // ignore - } - } - return c; - } - } - - /** * Returns the lock object for class loading operations. * For backward compatibility, the default implementation of this method * behaves as follows. If this ClassLoader object is registered as @@ -724,12 +692,17 @@ * should override this method. * * @apiNote This method returns {@code null} rather than throwing - * {@code ClassNotFoundException} if the class could not be found + * {@code ClassNotFoundException} if the class could not be found. * - * @implSpec The default implementation returns {@code null}. + * @implSpec The default implementation attempts to find the class by + * invoking {@link #findClass(String)} when the {@code moduleName} is + * {@code null}. It otherwise returns {@code null}. * * @param moduleName - * The module name + * The module name; or {@code null} to find the class in the + * {@linkplain #getUnnamedModule() unnamed module} for this + * class loader + * @param name * The binary name of the class * @@ -739,6 +712,11 @@ * @since 9 */ protected Class findClass(String moduleName, String name) { + if (moduleName == null) { + try { + return findClass(name); + } catch (ClassNotFoundException ignore) { } + } return null; } @@ -1286,10 +1264,20 @@ * Class loader implementations that support the loading from modules * should override this method. * - * @implSpec The default implementation returns {@code null}. + * @apiNote This method is the basis for the {@code Class} {@link + * Class#getResource getResource} and {@link Class#getResourceAsStream + * getResourceAsStream} methods. It is not subject to the rules for + * encapsulation specified by {@code Module} {@link + * Module#getResourceAsStream getResourceAsStream}. + * + * @implSpec The default implementation attempts to find the resource by + * invoking {@link #findResource(String)} when the {@code moduleName} is + * {@code null}. It otherwise returns {@code null}. * * @param moduleName - * The module name + * The module name; or {@code null} to find a resource in the + * {@linkplain #getUnnamedModule() unnamed module} for this + * class loader * @param name * The resource name * @@ -1306,7 +1294,11 @@ * @since 9 */ protected URL findResource(String moduleName, String name) throws IOException { - return null; + if (moduleName == null) { + return findResource(name); + } else { + return null; + } } /** @@ -1314,9 +1306,6 @@ * (images, audio, text, etc) that can be accessed by class code in a way * that is independent of the location of the code. * - * Resources in a named module are private to that module. This method does - * not find resource in named modules. - * *

The name of a resource is a '/'-separated path name that * identifies the resource. * @@ -1325,16 +1314,30 @@ * built-in to the virtual machine is searched. That failing, this method * will invoke {@link #findResource(String)} to find the resource.

* - * @apiNote When overriding this method it is recommended that an - * implementation ensures that any delegation is consistent with the {@link + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally (even if the caller of this method is in the + * same module as the resource).

+ * + * @apiNote Where several modules are defined to the same class loader, + * and where more than one module contains a resource with the given name, + * then the ordering that modules are searched is not specified and may be + * very unpredictable. + * When overriding this method it is recommended that an implementation + * ensures that any delegation is consistent with the {@link * #getResources(java.lang.String) getResources(String)} method. * * @param name * The resource name * - * @return A URL object for reading the resource, or - * null if the resource could not be found or the invoker - * doesn't have adequate privileges to get the resource. + * @return {@code URL} object for reading the resource; {@code null} if + * the resource could not be found, a {@code URL} could not be + * constructed to locate the resource, the resource is in a package + * that is not opened unconditionally, or access to the resource is + * denied by the security manager. * * @since 1.1 */ @@ -1356,16 +1359,24 @@ * (images, audio, text, etc) that can be accessed by class code in a way * that is independent of the location of the code. * - * Resources in a named module are private to that module. This method does - * not find resources in named modules. - * - *

The name of a resource is a /-separated path name that + *

The name of a resource is a /-separated path name that * identifies the resource. * - *

The search order is described in the documentation for {@link - * #getResource(String)}.

+ *

The delegation order for searching is described in the documentation + * for {@link #getResource(String)}.

* - * @apiNote When overriding this method it is recommended that an + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally (even if the caller of this method is in the + * same module as the resource).

+ * + * @apiNote Where several modules are defined to the same class loader, + * and where more than one module contains a resource with the given name, + * then the ordering is not specified and may be very unpredictable. + * When overriding this method it is recommended that an * implementation ensures that any delegation is consistent with the {@link * #getResource(java.lang.String) getResource(String)} method. This should * ensure that the first element returned by the Enumeration's @@ -1376,9 +1387,11 @@ * The resource name * * @return An enumeration of {@link java.net.URL URL} objects for - * the resource. If no resources could be found, the enumeration - * will be empty. Resources that the class loader doesn't have - * access to will not be in the enumeration. + * the resource. If no resources could be found, the enumeration + * will be empty. Resources for which a {@code URL} cannot be + * constructed, are in package that is not opened unconditionally, + * or access to the resource is denied by the security manager, + * are not returned in the enumeration. * * @throws IOException * If I/O errors occur @@ -1406,9 +1419,6 @@ * can be accessed by class code in a way that is independent of the * location of the code. * - * Resources in a named module are private to that module. This method does - * not find resources in named modules. - * *

The name of a resource is a {@code /}-separated path name that * identifies the resource. * @@ -1420,6 +1430,14 @@ * exception is wrapped in an {@link UncheckedIOException} that is then * thrown. * + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally (even if the caller of this method is in the + * same module as the resource).

+ * * @apiNote When overriding this method it is recommended that an * implementation ensures that any delegation is consistent with the {@link * #getResource(java.lang.String) getResource(String)} method. This should @@ -1430,9 +1448,10 @@ * The resource name * * @return A stream of resource {@link java.net.URL URL} objects. If no - * resources could be found, the stream will be empty. Resources - * that the class loader doesn't have access to will not be in the - * stream. + * resources could be found, the stream will be empty. Resources + * for which a {@code URL} cannot be constructed, are in a package + * that is not opened unconditionally, or access to the resource + * is denied by the security manager, will not be in the stream. * * @see #findResources(String) * @@ -1455,14 +1474,21 @@ * Finds the resource with the given name. Class loader implementations * should override this method to specify where to find resources. * - * Resources in a named module are private to that module. This method does - * not find resources in named modules defined to this class loader. + *

For resources in named modules then the method must implement the + * rules for encapsulation specified in the {@code Module} {@link + * Module#getResourceAsStream getResourceAsStream} method. Additionally, + * it must not find non-"{@code .class}" resources in packages of named + * modules unless the package is {@link Module#isOpen(String) opened} + * unconditionally.

* * @param name * The resource name * - * @return A URL object for reading the resource, or - * null if the resource could not be found + * @return {@code URL} object for reading the resource; {@code null} if + * the resource could not be found, a {@code URL} could not be + * constructed to locate the resource, the resource is in a package + * that is not opened unconditionally, or access to the resource is + * denied by the security manager. * * @since 1.2 */ @@ -1476,14 +1502,22 @@ * implementations should override this method to specify where to load * resources from. * - * Resources in a named module are private to that module. This method does - * not find resources in named modules defined to this class loader. + *

For resources in named modules then the method must implement the + * rules for encapsulation specified in the {@code Module} {@link + * Module#getResourceAsStream getResourceAsStream} method. Additionally, + * it must not find non-"{@code .class}" resources in packages of named + * modules unless the package is {@link Module#isOpen(String) opened} + * unconditionally.

* * @param name * The resource name * * @return An enumeration of {@link java.net.URL URL} objects for - * the resources + * the resource. If no resources could be found, the enumeration + * will be empty. Resources for which a {@code URL} cannot be + * constructed, are in a package that is not opened unconditionally, + * or access to the resource is denied by the security manager, + * are not returned in the enumeration. * * @throws IOException * If I/O errors occur @@ -1491,7 +1525,7 @@ * @since 1.2 */ protected Enumeration findResources(String name) throws IOException { - return java.util.Collections.emptyEnumeration(); + return Collections.emptyEnumeration(); } /** @@ -1541,14 +1575,21 @@ * classes. This method locates the resource through the system class * loader (see {@link #getSystemClassLoader()}). * - * Resources in a named module are private to that module. This method does - * not find resources in named modules. + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally.

* * @param name * The resource name * - * @return A {@link java.net.URL URL} object for reading the - * resource, or null if the resource could not be found + * @return A {@link java.net.URL URL} to the resource; {@code + * null} if the resource could not be found, a URL could not be + * constructed to locate the resource, the resource is in a package + * that is not opened unconditionally or access to the resource is + * denied by the security manager. * * @since 1.1 */ @@ -1562,17 +1603,25 @@ * {@link java.util.Enumeration Enumeration} of {@link * java.net.URL URL} objects. * - * Resources in a named module are private to that module. This method does - * not find resources in named modules. - * *

The search order is described in the documentation for {@link * #getSystemResource(String)}.

* + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally.

+ * * @param name * The resource name * - * @return An enumeration of resource {@link java.net.URL URL} - * objects + * @return An enumeration of {@link java.net.URL URL} objects for + * the resource. If no resources could be found, the enumeration + * will be empty. Resources for which a {@code URL} cannot be + * constructed, are in a package that is not opened unconditionally, + * or access to the resource is denied by the security manager, + * are not returned in the enumeration. * * @throws IOException * If I/O errors occur @@ -1588,17 +1637,23 @@ /** * Returns an input stream for reading the specified resource. * - * Resources in a named module are private to that module. This method does - * not find resources in named modules. - * *

The search order is described in the documentation for {@link * #getResource(String)}.

* + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally.

+ * * @param name * The resource name * - * @return An input stream for reading the resource, or null - * if the resource could not be found + * @return An input stream for reading the resource; {@code null} if the + * resource could not be found, the resource is in a package that + * is not opened unconditionally, or access to the resource is + * denied by the security manager. * * @since 1.1 */ @@ -1616,14 +1671,20 @@ * used to load classes. This method locates the resource through the * system class loader (see {@link #getSystemClassLoader()}). * - * Resources in a named module are private to that module. This method does - * not find resources in named modules. + *

Resources in named modules are subject to the encapsulation rules + * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * Additionally, and except for the special case where the resource has a + * name ending with "{@code .class}", this method will only find resources in + * packages of named modules when the package is {@link Module#isOpen(String) + * opened} unconditionally.

* * @param name * The resource name * - * @return An input stream for reading the resource, or null - * if the resource could not be found + * @return An input stream for reading the resource; {@code null} if the + * resource could not be found, the resource is in a package that + * is not opened unconditionally, or access to the resource is + * denied by the security manager. * * @since 1.1 */ @@ -2709,33 +2770,7 @@ private static native AssertionStatusDirectives retrieveDirectives(); - /** - * Returns the ServiceCatalog for modules defined to this class loader - * or {@code null} if this class loader does not have a services catalog. - */ - ServicesCatalog getServicesCatalog() { - return servicesCatalog; - } - - /** - * Returns the ServiceCatalog for modules defined to this class loader, - * creating it if it doesn't already exist. - */ - ServicesCatalog createOrGetServicesCatalog() { - ServicesCatalog catalog = servicesCatalog; - if (catalog == null) { - catalog = ServicesCatalog.create(); - boolean set = trySetObjectField("servicesCatalog", catalog); - if (!set) { - // beaten by someone else - catalog = servicesCatalog; - } - } - return catalog; - } - - // the ServiceCatalog for modules associated with this class loader. - private volatile ServicesCatalog servicesCatalog; + // -- Misc -- /** * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s) diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/Deprecated.java --- a/jdk/src/java.base/share/classes/java/lang/Deprecated.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/Deprecated.java Thu Dec 01 08:57:53 2016 +0000 @@ -40,6 +40,11 @@ * annotation on a local variable declaration or on a parameter declaration * or a package declaration has no effect on the warnings issued by a compiler. * + *

When a module is deprecated, the use of that module in {@code + * requires}, but not in {@code exports} or {@code opens} clauses causes + * a warning to be issued. A module being deprecated does not cause + * warnings to be issued for uses of types within the module. + * *

This annotation type has a string-valued element {@code since}. The value * of this element indicates the version in which the annotated program element * was first deprecated. @@ -74,7 +79,7 @@ */ @Documented @Retention(RetentionPolicy.RUNTIME) -@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) +@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE}) public @interface Deprecated { /** * Returns the version in which the annotated element became deprecated. diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/Package.java --- a/jdk/src/java.base/share/classes/java/lang/Package.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/Package.java Thu Dec 01 08:57:53 2016 +0000 @@ -398,10 +398,16 @@ if (packageInfo == null) { // find package-info.class defined by loader String cn = packageName() + ".package-info"; - PrivilegedAction pa = module()::getClassLoader; + Module module = module(); + PrivilegedAction pa = module::getClassLoader; ClassLoader loader = AccessController.doPrivileged(pa); - Class c = loader != null ? loader.loadLocalClass(cn) - : BootLoader.loadClassOrNull(cn); + Class c; + if (loader != null) { + c = loader.loadClass(module, cn); + } else { + c = BootLoader.loadClass(module, cn); + } + if (c != null) { packageInfo = c; } else { diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java --- a/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java Thu Dec 01 08:57:53 2016 +0000 @@ -35,6 +35,9 @@ * a superset of the warnings suppressed in all containing elements. For * example, if you annotate a class to suppress one warning and annotate a * method to suppress another, both warnings will be suppressed in the method. + * However, note that if a warning is suppressed in a {@code + * module-info} file, the suppression applies to elements within the + * file and not to types contained within the module. * *

As a matter of style, programmers should always use this annotation * on the most deeply nested element where it is effective. If you want to @@ -49,7 +52,7 @@ * @jls 5.5.2 Checked Casts and Unchecked Casts * @jls 9.6.4.5 @SuppressWarnings */ -@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) +@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/System.java --- a/jdk/src/java.base/share/classes/java/lang/System.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/System.java Thu Dec 01 08:57:53 2016 +0000 @@ -38,6 +38,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Layer; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Module; import java.net.URL; @@ -69,7 +70,6 @@ import jdk.internal.logger.LocalizedLoggerWrapper; import jdk.internal.module.ModuleBootstrap; -import jdk.internal.module.ServicesCatalog; /** * The System class contains several useful class fields @@ -1987,7 +1987,10 @@ private static void setJavaLangAccess() { // Allow privileged classes outside of java.lang - SharedSecrets.setJavaLangAccess(new JavaLangAccess(){ + SharedSecrets.setJavaLangAccess(new JavaLangAccess() { + public Method getMethodOrNull(Class klass, String name, Class... parameterTypes) { + return klass.getMethodOrNull(name, parameterTypes); + } public jdk.internal.reflect.ConstantPool getConstantPool(Class klass) { return klass.getConstantPool(); } @@ -2031,12 +2034,6 @@ public Layer getBootLayer() { return bootLayer; } - public ServicesCatalog getServicesCatalog(ClassLoader cl) { - return cl.getServicesCatalog(); - } - public ServicesCatalog createOrGetServicesCatalog(ClassLoader cl) { - return cl.createOrGetServicesCatalog(); - } public ConcurrentHashMap createOrGetClassLoaderValueMap(ClassLoader cl) { return cl.createOrGetClassLoaderValueMap(); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/VersionProps.java.template --- a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template Thu Dec 01 08:57:53 2016 +0000 @@ -123,27 +123,25 @@ /** * In case you were wondering this method is called by java -version. - * Sad that it prints to stderr; would be nicer if default printed on - * stdout. */ - public static void print() { - print(System.err); + public static void print(boolean err) { + print(err, false); } /** * This is the same as print except that it adds an extra line-feed * at the end, typically used by the -showversion in the launcher */ - public static void println() { - print(System.err); - System.err.println(); + public static void println(boolean err) { + print(err, true); } /** - * Give a stream, it will print version info on it. + * Print version info. */ - public static void print(PrintStream ps) { + private static void print(boolean err, boolean newln) { boolean isHeadless = false; + PrintStream ps = err ? System.err : System.out; /* Report that we're running headless if the property is true */ String headless = System.getProperty("java.awt.headless"); @@ -152,10 +150,14 @@ } /* First line: platform version. */ - ps.println(launcher_name + " version \"" + java_version + "\""); + if (err) { + ps.println(launcher_name + " version \"" + java_version + "\""); + } else { + /* Use a format more in line with GNU conventions */ + ps.println(launcher_name + " " + java_version); + } /* Second line: runtime version (ie, libraries). */ - String jdk_debug_level = System.getProperty("jdk.debug", "release"); /* Debug level is not printed for "release" builds */ if ("release".equals(jdk_debug_level)) { diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java --- a/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java Thu Dec 01 08:57:53 2016 +0000 @@ -37,10 +37,10 @@ * type contexts , where annotations apply to types used in * declarations and expressions. * - *

The constants {@link #ANNOTATION_TYPE} , {@link #CONSTRUCTOR} , {@link - * #FIELD} , {@link #LOCAL_VARIABLE} , {@link #METHOD} , {@link #PACKAGE} , - * {@link #PARAMETER} , {@link #TYPE} , and {@link #TYPE_PARAMETER} correspond - * to the declaration contexts in JLS 9.6.4.1. + *

The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link + * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link + * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER} + * correspond to the declaration contexts in JLS 9.6.4.1. * *

For example, an annotation whose type is meta-annotated with * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a @@ -107,5 +107,12 @@ * * @since 1.8 */ - TYPE_USE + TYPE_USE, + + /** + * Module declaration. + * + * @since 9 + */ + MODULE } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Thu Dec 01 08:57:53 2016 +0000 @@ -42,6 +42,7 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Module; import java.lang.reflect.ReflectPermission; import java.nio.ByteOrder; import java.util.ArrayList; @@ -142,6 +143,59 @@ } /** + * Returns a {@link Lookup lookup object} with full capabilities to emulate all + * supported bytecode behaviors, including + * private access, on a target class. + * This method checks that a caller, specified as a {@code Lookup} object, is allowed to + * do deep reflection on the target class. If {@code m1} is the module containing + * the {@link Lookup#lookupClass() lookup class}, and {@code m2} is the module containing + * the target class, then this check ensures that + *

+ *

+ * If there is a security manager, its {@code checkPermission} method is called to + * check {@code ReflectPermission("suppressAccessChecks")}. + * @apiNote The {@code MODULE} lookup mode serves to authenticate that the lookup object + * was created by code in the caller module (or derived from a lookup object originally + * created by the caller). A lookup object with the {@code MODULE} lookup mode can be + * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE} + * access to the caller. + * @param targetClass the target class + * @param lookup the caller lookup object + * @return a lookup object for the target class, with private access + * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class + * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null} + * @throws IllegalAccessException if the access check specified above fails + * @throws SecurityException if denied by the security manager + * @since 9 + */ + public static Lookup privateLookupIn(Class targetClass, Lookup lookup) throws IllegalAccessException { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) sm.checkPermission(ACCESS_PERMISSION); + if (targetClass.isPrimitive()) + throw new IllegalArgumentException(targetClass + " is a primitive class"); + if (targetClass.isArray()) + throw new IllegalArgumentException(targetClass + " is an array class"); + Module targetModule = targetClass.getModule(); + Module callerModule = lookup.lookupClass().getModule(); + if (callerModule != targetModule && targetModule.isNamed()) { + if (!callerModule.canRead(targetModule)) + throw new IllegalAccessException(callerModule + " does not read " + targetModule); + String pn = targetClass.getPackageName(); + assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module"; + if (!targetModule.isOpen(pn, callerModule)) + throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule); + } + if ((lookup.lookupModes() & Lookup.MODULE) == 0) + throw new IllegalAccessException("lookup does not have MODULE lookup mode"); + return new Lookup(targetClass); + } + + /** * Performs an unchecked "crack" of a * direct method handle. * The result is as if the user had obtained a lookup object capable enough @@ -1807,7 +1861,12 @@ return callerClass; } - private boolean hasPrivateAccess() { + /** + * Returns {@code true} if this lookup has {@code PRIVATE} access. + * @return {@code true} if this lookup has {@code PRIVATE} acesss. + * @since 9 + */ + public boolean hasPrivateAccess() { return (allowedModes & PRIVATE) != 0; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/Configuration.java --- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,14 +26,20 @@ package java.lang.module; import java.io.PrintStream; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; +import java.util.Deque; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * The configuration that is the result of resolution or resolution with @@ -46,14 +52,14 @@ * dependences expressed by {@code requires} clauses. * * The dependence graph is augmented with edges that take account of - * implicitly declared dependences ({@code requires public}) to create a + * implicitly declared dependences ({@code requires transitive}) to create a * readability graph. A {@code Configuration} encapsulates the * resulting graph of {@link ResolvedModule resolved modules}. * *

Suppose we have the following observable modules:

*
 {@code
  *     module m1 { requires m2; }
- *     module m2 { requires public m3; }
+ *     module m2 { requires transitive m3; }
  *     module m3 { }
  *     module m4 { }
  * } 
@@ -70,8 +76,10 @@ *

Resolution is an additive process. When computing the transitive closure * then the dependence relation may include dependences on modules in parent * configurations. The result is a relative configuration that is - * relative to a parent configuration and where the readability graph may have - * edges from modules in the configuration to modules in a parent configuration. + * relative to one or more parent configurations and where the readability graph + * may have edges from modules in the configuration to modules in parent + * configurations. + * *

* *

Suppose we have the following observable modules:

@@ -96,9 +104,9 @@ *

{@link ModuleDescriptor#isAutomatic() Automatic} modules receive special * treatment during resolution. Each automatic module is resolved so that it * reads all other modules in the configuration and all parent configurations. - * Each automatic module is also resolved as if it {@code requires public} all - * other automatic modules in the configuration (and all automatic modules in - * parent configurations).

+ * Each automatic module is also resolved as if it {@code requires transitive} + * all other automatic modules in the configuration (and all automatic modules + * in parent configurations).

*

Service binding

* @@ -171,54 +179,157 @@ // @see Configuration#empty() private static final Configuration EMPTY_CONFIGURATION = new Configuration(); - private final Configuration parent; + // parent configurations, in search order + private final List parents; private final Map> graph; private final Set modules; private final Map nameToModule; private Configuration() { - this.parent = null; + this.parents = Collections.emptyList(); this.graph = Collections.emptyMap(); this.modules = Collections.emptySet(); this.nameToModule = Collections.emptyMap(); } - private Configuration(Configuration parent, + private Configuration(List parents, Resolver resolver, boolean check) { Map> g = resolver.finish(this, check); - Map nameToModule = new HashMap<>(); + @SuppressWarnings(value = {"rawtypes", "unchecked"}) + Entry[] nameEntries + = (Entry[])new Entry[g.size()]; + ResolvedModule[] moduleArray = new ResolvedModule[g.size()]; + int i = 0; for (ResolvedModule resolvedModule : g.keySet()) { - nameToModule.put(resolvedModule.name(), resolvedModule); + moduleArray[i] = resolvedModule; + nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule); + i++; } - this.parent = parent; + this.parents = Collections.unmodifiableList(parents); this.graph = g; - this.modules = Collections.unmodifiableSet(g.keySet()); - this.nameToModule = Collections.unmodifiableMap(nameToModule); + this.modules = Set.of(moduleArray); + this.nameToModule = Map.ofEntries(nameEntries); } /** * Resolves a collection of root modules, with this configuration as its - * parent, to create a new configuration. + * parent, to create a new configuration. This method works exactly as + * specified by the static {@link + * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires} + * method when invoked with this configuration as the parent. In other words, + * if this configuration is {@code cf} then this method is equivalent to + * invoking: + *
 {@code
+     *     Configuration.resolveRequires(before, List.of(cf), after, roots);
+     * }
+ * + * @param before + * The before module finder to find modules + * @param after + * The after module finder to locate modules when a + * module cannot be located by the {@code before} module finder + * and the module is not in this configuration + * @param roots + * The possibly-empty collection of module names of the modules + * to resolve + * + * @return The configuration that is the result of resolving the given + * root modules + * + * @throws ResolutionException + * If resolution or the post-resolution checks fail + * @throws SecurityException + * If locating a module is denied by the security manager + */ + public Configuration resolveRequires(ModuleFinder before, + ModuleFinder after, + Collection roots) + { + return resolveRequires(before, List.of(this), after, roots); + } + + + /** + * Resolves a collection of root modules, with service binding, and with + * this configuration as its parent, to create a new configuration. + * This method works exactly as specified by the static {@link + * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection) + * resolveRequiresAndUses} method when invoked with this configuration + * as the parent. In other words, if this configuration is {@code cf} then + * this method is equivalent to invoking: + *
 {@code
+     *     Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
+     * }
+ * + * + * @param before + * The before module finder to find modules + * @param after + * The after module finder to locate modules when not + * located by the {@code before} module finder and this + * configuration + * @param roots + * The possibly-empty collection of module names of the modules + * to resolve + * + * @return The configuration that is the result of resolving the given + * root modules + * + * @throws ResolutionException + * If resolution or the post-resolution checks fail + * @throws SecurityException + * If locating a module is denied by the security manager + */ + public Configuration resolveRequiresAndUses(ModuleFinder before, + ModuleFinder after, + Collection roots) + { + return resolveRequiresAndUses(before, List.of(this), after, roots); + } + + + /** + * Resolves a collection of root modules, with service binding, and with + * the empty configuration as its parent. The post resolution checks + * are optionally run. + * + * This method is used to create the configuration for the boot layer. + */ + static Configuration resolveRequiresAndUses(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput) + { + List parents = List.of(empty()); + Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput); + resolver.resolveRequires(roots).resolveUses(); + + return new Configuration(parents, resolver, check); + } + + + /** + * Resolves a collection of root modules to create a configuration. * *

Each root module is located using the given {@code before} module * finder. If a module is not found then it is located in the parent * configuration as if by invoking the {@link #findModule(String) - * findModule} method. If not found then the module is located using the - * given {@code after} module finder. The same search order is used to - * locate transitive dependences. Root modules or dependences that are - * located in a parent configuration are resolved no further and are not - * included in the resulting configuration.

+ * findModule} method on each parent in iteration order. If not found then + * the module is located using the given {@code after} module finder. The + * same search order is used to locate transitive dependences. Root modules + * or dependences that are located in a parent configuration are resolved + * no further and are not included in the resulting configuration.

* *

When all modules have been resolved then the resulting dependency * graph is checked to ensure that it does not contain cycles. A - * readability graph is constructed and then, in conjunction with the - * module exports and service use, checked for consistency.

+ * readability graph is constructed and in conjunction with the module + * exports and service use, checked for consistency.

* *

Resolution and the (post-resolution) consistency checks may fail for * following reasons:

@@ -262,6 +373,8 @@ * * @param before * The before module finder to find modules + * @param parents + * The list parent configurations in search order * @param after * The after module finder to locate modules when not * located by the {@code before} module finder or in parent @@ -274,31 +387,37 @@ * root modules * * @throws ResolutionException - * If resolution or the post-resolution checks fail for any of the - * reasons listed + * If resolution or the post-resolution checks fail + * @throws IllegalArgumentException + * If the list of parents is empty * @throws SecurityException * If locating a module is denied by the security manager */ - public Configuration resolveRequires(ModuleFinder before, - ModuleFinder after, - Collection roots) + public static Configuration resolveRequires(ModuleFinder before, + List parents, + ModuleFinder after, + Collection roots) { Objects.requireNonNull(before); Objects.requireNonNull(after); Objects.requireNonNull(roots); - Resolver resolver = new Resolver(before, this, after, null); + List parentList = new ArrayList<>(parents); + if (parentList.isEmpty()) + throw new IllegalArgumentException("'parents' is empty"); + + Resolver resolver = new Resolver(before, parentList, after, null); resolver.resolveRequires(roots); - return new Configuration(this, resolver, true); + return new Configuration(parentList, resolver, true); } - /** - * Resolves a collection of root modules, with service binding, and with - * this configuration as its parent, to create a new configuration. + * Resolves a collection of root modules, with service binding, to create + * configuration. * - *

This method works exactly as specified by {@link #resolveRequires + *

This method works exactly as specified by {@link + * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) * resolveRequires} except that the graph of resolved modules is augmented * with modules induced by the service-use dependence relation.

* @@ -319,6 +438,8 @@ * * @param before * The before module finder to find modules + * @param parents + * The list parent configurations in search order * @param after * The after module finder to locate modules when not * located by the {@code before} module finder or in parent @@ -331,51 +452,35 @@ * root modules * * @throws ResolutionException - * If resolution or the post-resolution checks fail for any of the - * reasons listed + * If resolution or the post-resolution checks fail + * @throws IllegalArgumentException + * If the list of parents is empty * @throws SecurityException * If locating a module is denied by the security manager */ - public Configuration resolveRequiresAndUses(ModuleFinder before, - ModuleFinder after, - Collection roots) + public static Configuration resolveRequiresAndUses(ModuleFinder before, + List parents, + ModuleFinder after, + Collection roots) { Objects.requireNonNull(before); Objects.requireNonNull(after); Objects.requireNonNull(roots); - Resolver resolver = new Resolver(before, this, after, null); + List parentList = new ArrayList<>(parents); + if (parentList.isEmpty()) + throw new IllegalArgumentException("'parents' is empty"); + + Resolver resolver = new Resolver(before, parentList, after, null); resolver.resolveRequires(roots).resolveUses(); - return new Configuration(this, resolver, true); + return new Configuration(parentList, resolver, true); } /** - * Resolves a collection of root modules, with service binding, and with - * the empty configuration as its parent. The post resolution checks - * are optionally run. - * - * This method is used to create the configuration for the boot layer. - */ - static Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput) - { - Configuration parent = empty(); - - Resolver resolver - = new Resolver(finder, parent, ModuleFinder.of(), traceOutput); - resolver.resolveRequires(roots).resolveUses(); - - return new Configuration(parent, resolver, check); - } - - - /** - * Returns the empty configuration. The empty configuration does - * not contain any modules and does not have a parent. + * Returns the empty configuration. There are no modules in the + * empty configuration. It has no parents. * * @return The empty configuration */ @@ -385,13 +490,14 @@ /** - * Returns this configuration's parent unless this is the {@linkplain #empty - * empty configuration}, which has no parent. + * Returns an unmodifiable list of this configuration's parents, in search + * order. If this is the {@linkplain #empty empty configuration} then an + * empty list is returned. * - * @return This configuration's parent + * @return A possibly-empty unmodifiable list of this parent configurations */ - public Optional parent() { - return Optional.ofNullable(parent); + public List parents() { + return parents; } @@ -408,23 +514,35 @@ /** * Finds a resolved module in this configuration, or if not in this - * configuration, the {@linkplain #parent parent} configurations. + * configuration, the {@linkplain #parents parent} configurations. + * Finding a module in parent configurations is equivalent to invoking + * {@code findModule} on each parent, in search order, until the module + * is found or all parents have been searched. In a tree of + * configurations then this is equivalent to a depth-first search. * * @param name * The module name of the resolved module to find * * @return The resolved module with the given name or an empty {@code * Optional} if there isn't a module with this name in this - * configuration or any parent configuration + * configuration or any parent configurations */ public Optional findModule(String name) { Objects.requireNonNull(name); - if (parent == null) - return Optional.empty(); ResolvedModule m = nameToModule.get(name); if (m != null) return Optional.of(m); - return parent().flatMap(x -> x.findModule(name)); + + if (!parents.isEmpty()) { + return configurations() + .skip(1) // skip this configuration + .map(cf -> cf.nameToModule) + .filter(map -> map.containsKey(name)) + .map(map -> map.get(name)) + .findFirst(); + } + + return Optional.empty(); } @@ -444,9 +562,46 @@ } /** + * Returns an ordered stream of configurations. The first element is this + * configuration, the remaining elements are the parent configurations + * in DFS order. + * + * @implNote For now, the assumption is that the number of elements will + * be very low and so this method does not use a specialized spliterator. + */ + Stream configurations() { + List allConfigurations = this.allConfigurations; + if (allConfigurations == null) { + allConfigurations = new ArrayList<>(); + Set visited = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + visited.add(this); + stack.push(this); + while (!stack.isEmpty()) { + Configuration layer = stack.pop(); + allConfigurations.add(layer); + + // push in reverse order + for (int i = layer.parents.size() - 1; i >= 0; i--) { + Configuration parent = layer.parents.get(i); + if (!visited.contains(parent)) { + visited.add(parent); + stack.push(parent); + } + } + } + this.allConfigurations = Collections.unmodifiableList(allConfigurations); + } + return allConfigurations.stream(); + } + + private volatile List allConfigurations; + + + /** * Returns a string describing this configuration. * - * @return A string describing this configuration + * @return A possibly empty string describing this configuration */ @Override public String toString() { diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/Dependence.java --- a/jdk/src/java.base/share/classes/java/lang/module/Dependence.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.module; - -import java.util.*; -import java.util.stream.*; - - -class Dependence { - - private Dependence() { } - - static Stream toStringStream(Set s) { - return s.stream().map(e -> e.toString().toLowerCase()); - } - - static String toString(Set mods, String what) { - return (Stream.concat(toStringStream(mods), Stream.of(what))) - .collect(Collectors.joining(" ")); - } - -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Thu Dec 01 08:57:53 2016 +0000 @@ -45,6 +45,8 @@ import java.util.Optional; import java.util.Set; import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static jdk.internal.module.Checks.*; import static java.util.Objects.*; @@ -57,9 +59,11 @@ * A module descriptor. * *

A {@code ModuleDescriptor} is typically created from the binary form - * of a module declaration. The associated {@link ModuleDescriptor.Builder} - * class can also be used to create a {@code ModuleDescriptor} from its - * components.

+ * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder} + * class can be used to create a {@code ModuleDescriptor} from its components. + * The {@link #module module}, {@link #openModule openModule}, and {@link + * #automaticModule automaticModule} methods create builders for building + * different kinds of modules.

* *

{@code ModuleDescriptor} objects are immutable and safe for use by * multiple concurrent threads.

@@ -95,7 +99,13 @@ * module to have an implicitly declared dependence on the module * named by the {@code Requires}. */ - PUBLIC, + TRANSITIVE, + + /** + * The dependence is mandatory in the static phase, during compilation, + * but is optional in the dynamic phase, during execution. + */ + STATIC, /** * The dependence was not explicitly or implicitly declared in the @@ -115,16 +125,18 @@ private final String name; private Requires(Set ms, String mn) { - this(ms, mn, true); + if (ms.isEmpty()) { + ms = Collections.emptySet(); + } else { + ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); + } + this.mods = ms; + this.name = mn; } - private Requires(Set ms, String mn, boolean check) { - if (ms == null || ms.isEmpty()) { - mods = Collections.emptySet(); - } else { - mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms)) - : ms; - } - this.name = check ? requireModuleName(mn) : mn; + + private Requires(Set ms, String mn, boolean unused) { + this.mods = ms; + this.name = mn; } /** @@ -223,9 +235,8 @@ */ @Override public String toString() { - return Dependence.toString(mods, name); + return ModuleDescriptor.toString(mods, name); } - } @@ -239,36 +250,61 @@ public final static class Exports { + /** + * A modifier on a module export. + * + * @since 9 + */ + public static enum Modifier { + + /** + * The export was not explicitly or implicitly declared in the + * source of the module declaration. + */ + SYNTHETIC, + + /** + * The export was implicitly declared in the source of the module + * declaration. + */ + MANDATED; + + } + + private final Set mods; private final String source; private final Set targets; // empty if unqualified export /** - * Constructs a qualified export. + * Constructs an export */ - private Exports(String source, Set targets) { - this(source, targets, true); + private Exports(Set ms, String source, Set targets) { + if (ms.isEmpty()) { + ms = Collections.emptySet(); + } else { + ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); + } + this.mods = ms; + this.source = source; + this.targets = emptyOrUnmodifiableSet(targets); } - private Exports(String source, Set targets, boolean check) { - this.source = check ? requirePackageName(source) : source; - targets = check ? Collections.unmodifiableSet(new HashSet<>(targets)) - : Collections.unmodifiableSet(targets); - if (targets.isEmpty()) - throw new IllegalArgumentException("Empty target set"); - if (check) - targets.stream().forEach(Checks::requireModuleName); + private Exports(Set ms, + String source, + Set targets, + boolean unused) { + this.mods = ms; + this.source = source; this.targets = targets; } /** - * Constructs an unqualified export. + * Returns the set of modifiers. + * + * @return A possibly-empty unmodifiable set of modifiers */ - private Exports(String source) { - this(source, true); - } - private Exports(String source, boolean check) { - this.source = check ? requirePackageName(source) : source; - this.targets = Collections.emptySet(); + public Set modifiers() { + return mods; } /** @@ -304,25 +340,27 @@ /** * Computes a hash code for this module export. * - *

The hash code is based upon the package name, and for a - * qualified export, the set of modules names to which the package - * is exported. It satisfies the general contract of the {@link - * Object#hashCode Object.hashCode} method. + *

The hash code is based upon the modifiers, the package name, + * and for a qualified export, the set of modules names to which the + * package is exported. It satisfies the general contract of the + * {@link Object#hashCode Object.hashCode} method. * * @return The hash-code value for this module export */ @Override public int hashCode() { - return hash(source, targets); + int hash = mods.hashCode(); + hash = hash * 43 + source.hashCode(); + return hash * 43 + targets.hashCode(); } /** * Tests this module export for equality with the given object. * *

If the given object is not an {@code Exports} then this method - * returns {@code false}. Two module exports objects are equal if the - * package names are equal and the set of target module names is equal. - *

+ * returns {@code false}. Two module exports objects are equal if their + * set of modifiers is equal, the package names are equal and the set + * of target module names is equal.

* *

This method satisfies the general contract of the {@link * java.lang.Object#equals(Object) Object.equals} method.

@@ -338,8 +376,9 @@ if (!(ob instanceof Exports)) return false; Exports other = (Exports)ob; - return Objects.equals(this.source, other.source) && - Objects.equals(this.targets, other.targets); + return Objects.equals(this.mods, other.mods) + && Objects.equals(this.source, other.source) + && Objects.equals(this.targets, other.targets); } /** @@ -349,15 +388,177 @@ */ @Override public String toString() { + String s = ModuleDescriptor.toString(mods, source); if (targets.isEmpty()) - return source; + return s; else - return source + " to " + targets; + return s + " to " + targets; + } + } + + + /** + *

Represents a module opens directive, may be qualified or + * unqualified.

+ * + *

The opens directive in a module declaration declares a + * package to be open to allow all types in the package, and all their + * members, not just public types and their public members to be reflected + * on by APIs that support private access or a way to bypass or suppress + * default Java language access control checks.

+ * + * @see ModuleDescriptor#opens() + * @since 9 + */ + + public final static class Opens { + + /** + * A modifier on a module opens directive. + * + * @since 9 + */ + public static enum Modifier { + + /** + * The opens was not explicitly or implicitly declared in the + * source of the module declaration. + */ + SYNTHETIC, + + /** + * The opens was implicitly declared in the source of the module + * declaration. + */ + MANDATED; + + } + + private final Set mods; + private final String source; + private final Set targets; // empty if unqualified export + + /** + * Constructs an Opens + */ + private Opens(Set ms, String source, Set targets) { + if (ms.isEmpty()) { + ms = Collections.emptySet(); + } else { + ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); + } + this.mods = ms; + this.source = source; + this.targets = emptyOrUnmodifiableSet(targets); + } + + private Opens(Set ms, + String source, + Set targets, + boolean unused) { + this.mods = ms; + this.source = source; + this.targets = targets; + } + + /** + * Returns the set of modifiers. + * + * @return A possibly-empty unmodifiable set of modifiers + */ + public Set modifiers() { + return mods; } + /** + * Returns {@code true} if this is a qualified opens. + * + * @return {@code true} if this is a qualified opens + */ + public boolean isQualified() { + return !targets.isEmpty(); + } + + /** + * Returns the package name. + * + * @return The package name + */ + public String source() { + return source; + } + + /** + * For a qualified opens, returns the non-empty and immutable set + * of the module names to which the package is open. For an + * unqualified opens, returns an empty set. + * + * @return The set of target module names or for an unqualified + * opens, an empty set + */ + public Set targets() { + return targets; + } + + /** + * Computes a hash code for this module opens. + * + *

The hash code is based upon the modifiers, the package name, + * and for a qualified opens, the set of modules names to which the + * package is opened. It satisfies the general contract of the + * {@link Object#hashCode Object.hashCode} method. + * + * @return The hash-code value for this module opens + */ + @Override + public int hashCode() { + int hash = mods.hashCode(); + hash = hash * 43 + source.hashCode(); + return hash * 43 + targets.hashCode(); + } + + /** + * Tests this module opens for equality with the given object. + * + *

If the given object is not an {@code Opens} then this method + * returns {@code false}. Two {@code Opens} objects are equal if their + * set of modifiers is equal, the package names are equal and the set + * of target module names is equal.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * dependence that is equal to this module dependence + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Opens)) + return false; + Opens other = (Opens)ob; + return Objects.equals(this.mods, other.mods) + && Objects.equals(this.source, other.source) + && Objects.equals(this.targets, other.targets); + } + + /** + * Returns a string describing module opens. + * + * @return A string describing module opens + */ + @Override + public String toString() { + String s = ModuleDescriptor.toString(mods, source); + if (targets.isEmpty()) + return s; + else + return s + " to " + targets; + } } - /** *

A service that a module provides one or more implementations of.

@@ -369,21 +570,15 @@ public final static class Provides { private final String service; - private final Set providers; + private final List providers; - private Provides(String service, Set providers) { - this(service, providers, true); + private Provides(String service, List providers) { + this.service = service; + this.providers = Collections.unmodifiableList(providers); } - private Provides(String service, Set providers, boolean check) { - this.service = check ? requireServiceTypeName(service) : service; - providers = check - ? Collections.unmodifiableSet(new LinkedHashSet<>(providers)) - : Collections.unmodifiableSet(providers); - if (providers.isEmpty()) - throw new IllegalArgumentException("Empty providers set"); - if (check) - providers.forEach(Checks::requireServiceProviderName); + private Provides(String service, List providers, boolean unused) { + this.service = service; this.providers = providers; } @@ -395,12 +590,13 @@ public String service() { return service; } /** - * Returns the set of the fully qualified class names of the providers. + * Returns the list of the fully qualified class names of the providers + * or provider factories. * - * @return A non-empty and unmodifiable set of the fully qualified class - * names of the providers. + * @return A non-empty and unmodifiable list of the fully qualified class + * names of the providers or provider factories */ - public Set providers() { return providers; } + public List providers() { return providers; } /** * Computes a hash code for this provides. @@ -413,7 +609,7 @@ */ @Override public int hashCode() { - return hash(service, providers); + return service.hashCode() * 43 + providers.hashCode(); } /** @@ -421,7 +617,7 @@ * *

If the given object is not a {@code Provides} then this method * returns {@code false}. Two {@code Provides} objects are equal if the - * service type is equal and the set of providers is equal.

+ * service type is equal and the list of providers is equal.

* *

This method satisfies the general contract of the {@link * java.lang.Object#equals(Object) Object.equals} method.

@@ -774,10 +970,7 @@ // From module declarations private final String name; - private final Set requires; - private final Set exports; - private final Set uses; - private final Map provides; + private final boolean open; // Indicates if synthesised for a JAR file found on the module path private final boolean automatic; @@ -785,6 +978,12 @@ // Not generated from a module-info.java private final boolean synthetic; + private final Set requires; + private final Set exports; + private final Set opens; + private final Set uses; + private final Set provides; + // "Extended" information, added post-compilation by tools private final Version version; private final String mainClass; @@ -796,12 +995,14 @@ private ModuleDescriptor(String name, + boolean open, boolean automatic, boolean synthetic, - Map requires, + Set requires, + Set exports, + Set opens, Set uses, - Map exports, - Map provides, + Set provides, Version version, String mainClass, String osName, @@ -812,31 +1013,24 @@ { this.name = name; + this.open = open; this.automatic = automatic; this.synthetic = synthetic; - Set rqs = new HashSet<>(requires.values()); - assert (rqs.stream().map(Requires::name).sorted().distinct().count() - == rqs.size()) - : "Module " + name + " has duplicate requires"; - this.requires = emptyOrUnmodifiableSet(rqs); + assert (requires.stream().map(Requires::name).distinct().count() + == requires.size()); + this.requires = emptyOrUnmodifiableSet(requires); - Set exs = new HashSet<>(exports.values()); - assert (exs.stream().map(Exports::source).sorted().distinct().count() - == exs.size()) - : "Module " + name + " has duplicate exports"; - this.exports = emptyOrUnmodifiableSet(exs); - + this.exports = emptyOrUnmodifiableSet(exports); + this.opens = emptyOrUnmodifiableSet(opens); this.uses = emptyOrUnmodifiableSet(uses); - this.provides = emptyOrUnmodifiableMap(provides); - + this.provides = emptyOrUnmodifiableSet(provides); this.version = version; this.mainClass = mainClass; this.osName = osName; this.osArch = osArch; this.osVersion = osVersion; this.hashes = hashes; - this.packages = emptyOrUnmodifiableSet(packages); } @@ -845,11 +1039,13 @@ */ ModuleDescriptor(ModuleDescriptor md, Set pkgs) { this.name = md.name; + this.open = md.open; this.automatic = md.automatic; this.synthetic = md.synthetic; this.requires = md.requires; this.exports = md.exports; + this.opens = md.opens; this.uses = md.uses; this.provides = md.provides; @@ -866,38 +1062,44 @@ } /** - * Creates a module descriptor from its components. This method is intended - * for use by the jlink plugin. + * Creates a module descriptor from its components. + * The arguments are pre-validated and sets are unmodifiable sets. */ ModuleDescriptor(String name, + boolean open, boolean automatic, boolean synthetic, Set requires, + Set exports, + Set opens, Set uses, - Set exports, - Map provides, + Set provides, Version version, String mainClass, String osName, String osArch, String osVersion, Set packages, - ModuleHashes hashes) { + ModuleHashes hashes, + int hashCode, + boolean unused) { this.name = name; + this.open = open; this.automatic = automatic; this.synthetic = synthetic; - this.requires = Collections.unmodifiableSet(requires); - this.exports = Collections.unmodifiableSet(exports); - this.uses = Collections.unmodifiableSet(uses); - this.provides = Collections.unmodifiableMap(provides); - this.packages = Collections.unmodifiableSet(packages); - + this.requires = requires; + this.exports = exports; + this.opens = opens; + this.uses = uses; + this.provides = provides; + this.packages = packages; this.version = version; this.mainClass = mainClass; this.osName = osName; this.osArch = osArch; this.osVersion = osVersion; this.hashes = hashes; + this.hash = hashCode; } /** @@ -910,6 +1112,19 @@ } /** + *

Returns {@code true} if this is an open module.

+ * + *

An open module does not declare any open packages (the {@link #opens() + * opens} method returns an empty set) but the resulting module is treated + * as if all packages are open.

+ * + * @return {@code true} if this is an open module + */ + public boolean isOpen() { + return open; + } + + /** *

Returns {@code true} if this is an automatic module.

* *

An automatic module is defined implicitly rather than explicitly @@ -933,8 +1148,6 @@ * * @return {@code true} if this module descriptor was not generated by * an explicit or implicit module declaration - * - * @jvms 4.7.8 The {@code Synthetic} Attribute */ public boolean isSynthetic() { return synthetic; @@ -950,6 +1163,33 @@ } /** + *

The module exports.

+ * + * @return A possibly-empty unmodifiable set of exported packages + */ + public Set exports() { + return exports; + } + + /** + *

The module opens directives.

+ * + *

Each {@code Opens} object in the set represents a package (and + * the set of target module names when qualified) where all types in the + * package, and all their members, not just public types and their public + * members, can be reflected on when using APIs that bypass or suppress + * default Java language access control checks.

+ * + *

This method returns an empty set when invoked on {@link #isOpen() + * open} module.

+ * + * @return A possibly-empty unmodifiable set of open packages + */ + public Set opens() { + return opens; + } + + /** *

The service dependences of this module.

* * @return A possibly-empty unmodifiable set of the fully qualified class @@ -962,24 +1202,14 @@ /** *

The services that this module provides.

* - * @return The possibly-empty unmodifiable map of the services that this - * module provides. The map key is fully qualified class name of - * the service type. + * @return The possibly-empty unmodifiable set of the services that this + * module provides */ - public Map provides() { + public Set provides() { return provides; } /** - *

The module exports.

- * - * @return A possibly-empty unmodifiable set of exported packages - */ - public Set exports() { - return exports; - } - - /** * Returns this module's version. * * @return This module's version @@ -1046,22 +1276,9 @@ } /** - * Returns the names of the packages defined in, but not exported by, this - * module. + * Returns the names of all packages in this module. * - * @return A possibly-empty unmodifiable set of the concealed packages - */ - public Set conceals() { - Set conceals = new HashSet<>(packages); - exports.stream().map(Exports::source).forEach(conceals::remove); - return emptyOrUnmodifiableSet(conceals); - } - - /** - * Returns the names of all the packages defined in this module, whether - * exported or concealed. - * - * @return A possibly-empty unmodifiable set of the all packages + * @return A possibly-empty unmodifiable set of all packages in the module */ public Set packages() { return packages; @@ -1078,31 +1295,39 @@ /** * A builder used for building {@link ModuleDescriptor} objects. * - *

Example usage:

+ *

{@code ModuleDescriptor} defines the {@link #module module}, {@link + * #openModule openModule}, and {@link #automaticModule automaticModule} + * methods to create builders for building different kinds of modules.

* - *
{@code
-     *     ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1")
+     * 

Example usage:

+ *
{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
+     *         .exports("p")
      *         .requires("m2")
-     *         .exports("p")
      *         .build();
      * }
* - * @apiNote A {@code Builder} cannot be used to create an {@link - * ModuleDescriptor#isAutomatic() automatic} or a {@link - * ModuleDescriptor#isSynthetic() synthetic} module. + * @apiNote A {@code Builder} checks the components and invariants as + * components are added to the builder. The rational for this is to detect + * errors as early as possible and not defer all validation to the + * {@link #build build} method. A {@code Builder} cannot be used to create + * a {@link ModuleDescriptor#isSynthetic() synthetic} module. * * @since 9 */ public static final class Builder { - final String name; + final boolean strict; // true if module names are checked + boolean open; boolean automatic; boolean synthetic; final Map requires = new HashMap<>(); - final Set uses = new HashSet<>(); + final Map exports = new HashMap<>(); + final Map opens = new HashMap<>(); + final Set concealedPackages = new HashSet<>(); + + final Set uses = new HashSet<>(); final Map provides = new HashMap<>(); - Set conceals = Collections.emptySet(); Version version; String osName; String osArch; @@ -1113,29 +1338,30 @@ /** * Initializes a new builder with the given module name. * - * @param name - * The module name - * - * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * @param strict + * Indicates whether module names are checked or not */ - public Builder(String name) { - this.name = requireModuleName(name); + Builder(String name, boolean strict) { + this.strict = strict; + this.name = (strict) ? requireModuleName(name) : name; } - /** - * Updates the builder so that it builds an automatic module. - * - * @return This builder - * - * @see ModuleDescriptor#isAutomatic() - */ - /* package */ Builder automatic() { - this.automatic = true; + /* package */ Builder open(boolean open) { + this.open = open; return this; } + /* package */ Builder automatic(boolean automatic) { + this.automatic = automatic; + return this; + } + + /* package */ boolean isOpen() { return open; } + + /* package */ boolean isAutomatic() { + return automatic; + } + /** * Adds a dependence on a module. * @@ -1165,7 +1391,7 @@ * Adds a dependence on a module with the given (and possibly empty) * set of modifiers. * - * @param mods + * @param ms * The set of modifiers * @param mn * The module name @@ -1179,14 +1405,10 @@ * @throws IllegalStateException * If the dependence on the module has already been declared */ - public Builder requires(Set mods, String mn) { - if (name.equals(mn)) - throw new IllegalArgumentException("Dependence on self"); - if (requires.containsKey(mn)) - throw new IllegalStateException("Dependence upon " + mn - + " already declared"); - requires.put(mn, new Requires(mods, mn)); // checks mn - return this; + public Builder requires(Set ms, String mn) { + if (strict) + mn = requireModuleName(mn); + return requires(new Requires(ms, mn)); } /** @@ -1209,62 +1431,6 @@ } /** - * Adds a dependence on a module with the given modifier. - * - * @param mod - * The modifier - * @param mn - * The module name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder - * was initialized to build - * @throws IllegalStateException - * If the dependence on the module has already been declared - */ - public Builder requires(Requires.Modifier mod, String mn) { - return requires(EnumSet.of(mod), mn); - } - - /** - * Adds a service dependence. - * - * @param st - * The service type - * - * @return This builder - * - * @throws IllegalArgumentException - * If the service type is {@code null} or is not a legal Java - * identifier - * @throws IllegalStateException - * If a dependency on the service type has already been declared - */ - public Builder uses(String st) { - if (uses.contains(requireServiceTypeName(st))) - throw new IllegalStateException("Dependence upon service " - + st + " already declared"); - uses.add(st); - return this; - } - - /** - * Ensures that the given package name has not been declared as an - * exported or concealed package. - */ - private void ensureNotExportedOrConcealed(String pn) { - if (exports.containsKey(pn)) - throw new IllegalStateException("Export of package " - + pn + " already declared"); - if (conceals.contains(pn)) - throw new IllegalStateException("Concealed package " - + pn + " already declared"); - } - - /** * Adds an export. * * @param e @@ -1273,18 +1439,90 @@ * @return This builder * * @throws IllegalStateException - * If the package is already declared as an exported or - * concealed package + * If the package is already declared as a package with the + * {@link #contains contains} method or the package is already + * declared as exported */ public Builder exports(Exports e) { - String pn = e.source(); - ensureNotExportedOrConcealed(pn); - exports.put(pn, e); + // can't be exported and concealed + String source = e.source(); + if (concealedPackages.contains(source)) { + throw new IllegalStateException("Package " + source + + " already declared"); + } + if (exports.containsKey(source)) { + throw new IllegalStateException("Exported package " + source + + " already declared"); + } + + exports.put(source, e); return this; } /** - * Adds an export to a set of target modules. + * Adds an export, with the given (and possibly empty) set of modifiers, + * to export a package to a set of target modules. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name or any of the target modules is {@code + * null} or is not a legal Java identifier, or the set of + * targets is empty + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method or the package is already + * declared as exported + */ + public Builder exports(Set ms, + String pn, + Set targets) + { + Exports e = new Exports(ms, requirePackageName(pn), targets); + + // check targets + targets = e.targets(); + if (targets.isEmpty()) + throw new IllegalArgumentException("Empty target set"); + if (strict) + targets.stream().forEach(Checks::requireModuleName); + + return exports(e); + } + + /** + * Adds an unqualified export with the given (and possibly empty) set + * of modifiers. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal Java + * identifier + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method or the package is already + * declared as exported + */ + public Builder exports(Set ms, String pn) { + Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet()); + return exports(e); + } + + /** + * Adds an export to export a package to a set of target modules. * * @param pn * The package name @@ -1298,38 +1536,16 @@ * null} or is not a legal Java identifier, or the set of * targets is empty * @throws IllegalStateException - * If the package is already declared as an exported or - * concealed package + * If the package is already declared as a package with the + * {@link #contains contains} method or the package is already + * declared as exported */ public Builder exports(String pn, Set targets) { - ensureNotExportedOrConcealed(pn); - exports.put(pn, new Exports(pn, targets)); // checks pn and targets - return this; + return exports(Collections.emptySet(), pn, targets); } /** - * Adds an export to a target module. - * - * @param pn - * The package name - * @param target - * The target module name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name or target module is {@code null} or is - * not a legal Java identifier - * @throws IllegalStateException - * If the package is already declared as an exported or - * concealed package - */ - public Builder exports(String pn, String target) { - return exports(pn, Collections.singleton(target)); - } - - /** - * Adds an export. + * Adds an unqualified export. * * @param pn * The package name @@ -1340,18 +1556,186 @@ * If the package name is {@code null} or is not a legal Java * identifier * @throws IllegalStateException - * If the package is already declared as an exported or - * concealed package + * If the package is already declared as a package with the + * {@link #contains contains} method or the package is already + * declared as exported */ public Builder exports(String pn) { - ensureNotExportedOrConcealed(pn); - exports.put(pn, new Exports(pn)); // checks pn + return exports(Collections.emptySet(), pn); + } + + /** + * Adds an opens directive. + * + * @param obj + * The {@code Opens} object + * + * @return This builder + * + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method, the package is already + * declared as open, or this is a builder for an open module + */ + public Builder opens(Opens obj) { + if (open) { + throw new IllegalStateException("open modules cannot declare" + + " open packages"); + } + + // can't be open and concealed + String source = obj.source(); + if (concealedPackages.contains(source)) { + throw new IllegalStateException("Package " + source + + " already declared"); + } + if (opens.containsKey(source)) { + throw new IllegalStateException("Open package " + source + + " already declared"); + } + + opens.put(source, obj); return this; } + + /** + * Adds an opens directive, with the given (and possibly empty) + * set of modifiers, to open a package to a set of target modules. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name or any of the target modules is {@code + * null} or is not a legal Java identifier, or the set of + * targets is empty + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method, the package is already + * declared as open, or this is a builder for an open module + */ + public Builder opens(Set ms, + String pn, + Set targets) + { + Opens e = new Opens(ms, requirePackageName(pn), targets); + + // check targets + targets = e.targets(); + if (targets.isEmpty()) + throw new IllegalArgumentException("Empty target set"); + if (strict) + targets.stream().forEach(Checks::requireModuleName); + + return opens(e); + } + + /** + * Adds an opens directive to open a package with the given (and + * possibly empty) set of modifiers. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal Java + * identifier + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method, the package is already + * declared as open, or this is a builder for an open module + */ + public Builder opens(Set ms, String pn) { + Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet()); + return opens(e); + } + + /** + * Adds an opens directive to open a package to a set of target + * modules. + * + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name or any of the target modules is {@code + * null} or is not a legal Java identifier, or the set of + * targets is empty + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method, the package is already + * declared as open, or this is a builder for an open module + */ + public Builder opens(String pn, Set targets) { + return opens(Collections.emptySet(), pn, targets); + } + + /** + * Adds an opens directive to open a package. + * + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal Java + * identifier + * @throws IllegalStateException + * If the package is already declared as a package with the + * {@link #contains contains} method, the package is already + * declared as open, or this is a builder for an open module + */ + public Builder opens(String pn) { + return opens(Collections.emptySet(), pn); + } + + // Used by ModuleInfo, after a packageFinder is invoked - /* package */ Set exportedPackages() { - return exports.keySet(); + /* package */ Set exportedAndOpenPackages() { + if (opens.isEmpty()) + return exports.keySet(); + Set result = new HashSet<>(); + result.addAll(exports.keySet()); + result.addAll(opens.keySet()); + return result; + } + + /** + * Adds a service dependence. + * + * @param service + * The service type + * + * @return This builder + * + * @throws IllegalArgumentException + * If the service type is {@code null} or is not a legal Java + * identifier + * @throws IllegalStateException + * If a dependency on the service type has already been declared + */ + public Builder uses(String service) { + if (uses.contains(requireServiceTypeName(service))) + throw new IllegalStateException("Dependence upon service " + + service + " already declared"); + uses.add(service); + return this; } /** @@ -1376,38 +1760,47 @@ } /** - * Provides service {@code st} with implementations {@code pcs}. + * Provides implementations of a service. * - * @param st + * @param service * The service type - * @param pcs - * The set of provider class names + * @param providers + * The list of provider or provider factory class names * * @return This builder * * @throws IllegalArgumentException * If the service type or any of the provider class names is - * {@code null} or is not a legal Java identifier, or the set + * {@code null} or is not a legal Java identifier, or the list * of provider class names is empty * @throws IllegalStateException * If the providers for the service type have already been * declared */ - public Builder provides(String st, Set pcs) { - if (provides.containsKey(st)) + public Builder provides(String service, List providers) { + if (provides.containsKey(service)) throw new IllegalStateException("Providers of service " - + st + " already declared"); - provides.put(st, new Provides(st, pcs)); // checks st and pcs + + service + " already declared by " + name); + + Provides p = new Provides(requireServiceTypeName(service), providers); + + // check providers after the set has been copied. + List providerNames = p.providers(); + if (providerNames.isEmpty()) + throw new IllegalArgumentException("Empty providers set"); + providerNames.forEach(Checks::requireServiceProviderName); + + provides.put(service, p); return this; } /** - * Provides service {@code st} with implementation {@code pc}. + * Provides an implementation of a service. * - * @param st + * @param service * The service type - * @param pc - * The provider class name + * @param provider + * The provider or provider factory class name * * @return This builder * @@ -1418,15 +1811,17 @@ * If the providers for the service type have already been * declared */ - public Builder provides(String st, String pc) { - return provides(st, Collections.singleton(pc)); + public Builder provides(String service, String provider) { + if (provider == null) + throw new IllegalArgumentException("'provider' is null"); + return provides(service, List.of(provider)); } /** - * Adds a set of (possible empty) concealed packages. + * Adds a (possible empty) set of packages to the module * * @param pns - * The set of package names of the concealed packages + * The set of package names * * @return This builder * @@ -1434,16 +1829,17 @@ * If any of the package names is {@code null} or is not a * legal Java identifier * @throws IllegalStateException - * If any of packages are already declared as a concealed or - * exported package + * If any of packages are already declared as packages in + * the module. This includes packages that are already + * declared as exported or open packages. */ - public Builder conceals(Set pns) { - pns.forEach(this::conceals); + public Builder contains(Set pns) { + pns.forEach(this::contains); return this; } /** - * Adds a concealed package. + * Adds a package to the module. * * @param pn * The package name @@ -1454,15 +1850,25 @@ * If the package name is {@code null}, or is not a legal Java * identifier * @throws IllegalStateException - * If the package is already declared as a concealed or exported - * package + * If the package is already declared as a package in the + * module. This includes the package already declared as an + * exported or open package. */ - public Builder conceals(String pn) { + public Builder contains(String pn) { Checks.requirePackageName(pn); - ensureNotExportedOrConcealed(pn); - if (conceals.isEmpty()) - conceals = new HashSet<>(); - conceals.add(pn); + if (concealedPackages.contains(pn)) { + throw new IllegalStateException("Package " + pn + + " already declared"); + } + if (exports.containsKey(pn)) { + throw new IllegalStateException("Exported package " + + pn + " already declared"); + } + if (opens.containsKey(pn)) { + throw new IllegalStateException("Open package " + + pn + " already declared"); + } + concealedPackages.add(pn); return this; } @@ -1473,13 +1879,8 @@ * The version * * @return This builder - * - * @throws IllegalStateException - * If the module version is already set */ public Builder version(Version v) { - if (version != null) - throw new IllegalStateException("module version already set"); version = requireNonNull(v); return this; } @@ -1494,16 +1895,11 @@ * * @throws IllegalArgumentException * If {@code v} is null or cannot be parsed as a version string - * @throws IllegalStateException - * If the module version is already set * * @see Version#parse(String) */ public Builder version(String v) { - if (version != null) - throw new IllegalStateException("module version already set"); - version = Version.parse(v); - return this; + return version(Version.parse(v)); } /** @@ -1516,12 +1912,8 @@ * * @throws IllegalArgumentException * If {@code mainClass} is null or is not a legal Java identifier - * @throws IllegalStateException - * If the module main class is already set */ public Builder mainClass(String mc) { - if (mainClass != null) - throw new IllegalStateException("main class already set"); mainClass = requireJavaIdentifier("main class name", mc); return this; } @@ -1536,12 +1928,8 @@ * * @throws IllegalArgumentException * If {@code name} is null or the empty String - * @throws IllegalStateException - * If the operating system name is already set */ public Builder osName(String name) { - if (osName != null) - throw new IllegalStateException("OS name already set"); if (name == null || name.isEmpty()) throw new IllegalArgumentException("OS name is null or empty"); osName = name; @@ -1558,12 +1946,8 @@ * * @throws IllegalArgumentException * If {@code name} is null or the empty String - * @throws IllegalStateException - * If the operating system architecture is already set */ public Builder osArch(String arch) { - if (osArch != null) - throw new IllegalStateException("OS arch already set"); if (arch == null || arch.isEmpty()) throw new IllegalArgumentException("OS arch is null or empty"); osArch = arch; @@ -1580,12 +1964,8 @@ * * @throws IllegalArgumentException * If {@code name} is null or the empty String - * @throws IllegalStateException - * If the operating system version is already set */ public Builder osVersion(String version) { - if (osVersion != null) - throw new IllegalStateException("OS version already set"); if (version == null || version.isEmpty()) throw new IllegalArgumentException("OS version is null or empty"); osVersion = version; @@ -1597,7 +1977,6 @@ return this; } - /* package */ Builder synthetic(boolean v) { this.synthetic = v; return this; @@ -1609,16 +1988,24 @@ * @return The module descriptor */ public ModuleDescriptor build() { - assert name != null; + Set requires = new HashSet<>(this.requires.values()); + + Set packages = new HashSet<>(exportedAndOpenPackages()); + packages.addAll(concealedPackages); - Set packages = new HashSet<>(conceals); - packages.addAll(exportedPackages()); + Set exports = new HashSet<>(this.exports.values()); + Set opens = new HashSet<>(this.opens.values()); + + Set provides = new HashSet<>(this.provides.values()); + return new ModuleDescriptor(name, + open, automatic, synthetic, requires, + exports, + opens, uses, - exports, provides, version, mainClass, @@ -1631,7 +2018,6 @@ } - /** * Compares this module descriptor to another. * @@ -1689,11 +2075,13 @@ return false; ModuleDescriptor that = (ModuleDescriptor)ob; return (name.equals(that.name) + && open == that.open && automatic == that.automatic && synthetic == that.synthetic && requires.equals(that.requires) + && exports.equals(that.exports) + && opens.equals(that.opens) && uses.equals(that.uses) - && exports.equals(that.exports) && provides.equals(that.provides) && Objects.equals(version, that.version) && Objects.equals(mainClass, that.mainClass) @@ -1720,11 +2108,13 @@ int hc = hash; if (hc == 0) { hc = name.hashCode(); + hc = hc * 43 + Boolean.hashCode(open); hc = hc * 43 + Boolean.hashCode(automatic); hc = hc * 43 + Boolean.hashCode(synthetic); hc = hc * 43 + requires.hashCode(); + hc = hc * 43 + exports.hashCode(); + hc = hc * 43 + opens.hashCode(); hc = hc * 43 + uses.hashCode(); - hc = hc * 43 + exports.hashCode(); hc = hc * 43 + provides.hashCode(); hc = hc * 43 + Objects.hashCode(version); hc = hc * 43 + Objects.hashCode(mainClass); @@ -1748,36 +2138,101 @@ @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("Module { name: ").append(toNameAndVersion()); + + if (isOpen()) + sb.append("open "); + sb.append("module { name: ").append(toNameAndVersion()); if (!requires.isEmpty()) sb.append(", ").append(requires); if (!uses.isEmpty()) sb.append(", ").append(uses); if (!exports.isEmpty()) sb.append(", exports: ").append(exports); + if (!opens.isEmpty()) + sb.append(", opens: ").append(opens); if (!provides.isEmpty()) { - sb.append(", provides: ["); - for (Map.Entry entry : provides.entrySet()) { - sb.append(entry.getKey()) - .append(" with ") - .append(entry.getValue()); - } - sb.append("]"); + sb.append(", provides: ").append(provides); } sb.append(" }"); return sb.toString(); } + + /** + * Instantiates a builder to build a module descriptor. + * + * @param name + * The module name + * + * @return A new builder + * + * @throws IllegalArgumentException + * If the module name is {@code null} or is not a legal Java + * identifier + */ + public static Builder module(String name) { + return new Builder(name, true); + } + + /** + * Instantiates a builder to build a module descriptor for an open module. + * An open module does not declare any open packages but the resulting + * module is treated as if all packages are open. + * + *

As an example, the following creates a module descriptor for an open + * name "{@code m}" containing two packages, one of which is exported.

+ *
{@code
+     *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
+     *         .requires("java.base")
+     *         .exports("p")
+     *         .contains("q")
+     *         .build();
+     * }
+ * + * @param name + * The module name + * + * @return A new builder that builds an open module + * + * @throws IllegalArgumentException + * If the module name is {@code null} or is not a legal Java + * identifier + */ + public static Builder openModule(String name) { + return new Builder(name, true).open(true); + } + + /** + * Instantiates a builder to build a module descriptor for an automatic + * module. Automatic modules receive special treatment during resolution + * (see {@link Configuration}) so that they read all other modules. When + * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module} + * then the Module reads every unnamed module in the Java virtual machine. + * + * @param name + * The module name + * + * @return A new builder that builds an automatic module + * + * @throws IllegalArgumentException + * If the module name is {@code null} or is not a legal Java + * identifier + * + * @see ModuleFinder#of(Path[]) + */ + public static Builder automaticModule(String name) { + return new Builder(name, true).automatic(true); + } + + /** * Reads the binary form of a module declaration from an input stream * as a module descriptor. * *

If the descriptor encoded in the input stream does not indicate a - * set of concealed packages then the {@code packageFinder} will be - * invoked. The packages it returns, except for those indicated as - * exported in the encoded descriptor, will be considered to be concealed. - * If the {@code packageFinder} throws an {@link UncheckedIOException} then - * {@link IOException} cause will be re-thrown.

+ * set of packages in the module then the {@code packageFinder} will be + * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException} + * then {@link IOException} cause will be re-thrown.

* *

If there are bytes following the module descriptor then it is * implementation specific as to whether those bytes are read, ignored, @@ -1789,12 +2244,12 @@ * * @apiNote The {@code packageFinder} parameter is for use when reading * module descriptors from legacy module-artifact formats that do not - * record the set of concealed packages in the descriptor itself. + * record the set of packages in the descriptor itself. * * @param in * The input stream * @param packageFinder - * A supplier that can produce a set of package names + * A supplier that can produce the set of packages * * @return The module descriptor * @@ -1834,10 +2289,7 @@ * as a module descriptor. * *

If the descriptor encoded in the byte buffer does not indicate a - * set of concealed packages then the {@code packageFinder} will be - * invoked. The packages it returns, except for those indicated as - * exported in the encoded descriptor, will be considered to be - * concealed.

+ * set of packages then the {@code packageFinder} will be invoked.

* *

The module descriptor is read from the buffer stating at index * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position() @@ -1853,12 +2305,12 @@ * * @apiNote The {@code packageFinder} parameter is for use when reading * module descriptors from legacy module-artifact formats that do not - * record the set of concealed packages in the descriptor itself. + * record the set of packages in the descriptor itself. * * @param bb * The byte buffer * @param packageFinder - * A supplier that can produce a set of package names + * A supplier that can produce the set of packages * * @return The module descriptor * @@ -1908,6 +2360,15 @@ } } + /** + * Returns a string containing the given set of modifiers and label. + */ + private static String toString(Set mods, String what) { + return (Stream.concat(mods.stream().map(e -> e.toString().toLowerCase()), + Stream.of(what))) + .collect(Collectors.joining(" ")); + } + static { /** * Setup the shared secret to allow code in other packages access @@ -1915,25 +2376,48 @@ */ jdk.internal.misc.SharedSecrets .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() { + @Override + public Builder newModuleBuilder(String mn, boolean strict) { + return new Builder(mn, strict); + } + + @Override + public Builder newOpenModuleBuilder(String mn, boolean strict) { + return new Builder(mn, strict).open(true); + } @Override public Requires newRequires(Set ms, String mn) { - return new Requires(ms, mn, false); + return new Requires(ms, mn, true); + } + + @Override + public Exports newExports(Set ms, String source) { + return new Exports(ms, source, Collections.emptySet(), true); } @Override - public Exports newExports(String source, Set targets) { - return new Exports(source, targets, false); + public Exports newExports(Set ms, + String source, + Set targets) { + return new Exports(ms, source, targets, true); } @Override - public Exports newExports(String source) { - return new Exports(source, false); + public Opens newOpens(Set ms, + String source, + Set targets) { + return new Opens(ms, source, targets, true); } @Override - public Provides newProvides(String service, Set providers) { - return new Provides(service, providers, false); + public Opens newOpens(Set ms, String source) { + return new Opens(ms, source, Collections.emptySet(), true); + } + + @Override + public Provides newProvides(String service, List providers) { + return new Provides(service, providers, true); } @Override @@ -1949,25 +2433,30 @@ @Override public ModuleDescriptor newModuleDescriptor(String name, + boolean open, boolean automatic, boolean synthetic, Set requires, + Set exports, + Set opens, Set uses, - Set exports, - Map provides, + Set provides, Version version, String mainClass, String osName, String osArch, String osVersion, Set packages, - ModuleHashes hashes) { + ModuleHashes hashes, + int hashCode) { return new ModuleDescriptor(name, + open, automatic, synthetic, requires, + exports, + opens, uses, - exports, provides, version, mainClass, @@ -1975,7 +2464,14 @@ osArch, osVersion, packages, - hashes); + hashes, + hashCode, + false); + } + + @Override + public Optional hashes(ModuleDescriptor descriptor) { + return descriptor.hashes(); } @Override @@ -1995,11 +2491,6 @@ } @Override - public Optional hashes(ModuleDescriptor descriptor) { - return descriptor.hashes(); - } - - @Override public ModuleFinder newModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) { diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java Thu Dec 01 08:57:53 2016 +0000 @@ -233,10 +233,11 @@ * ModuleDescriptor.Version} and ignored if it cannot be parsed as * a {@code Version}.

* - *
  • For the module name, then all non-alphanumeric - * characters ({@code [^A-Za-z0-9])} are replaced with a dot - * ({@code "."}), all repeating dots are replaced with one dot, - * and all leading and trailing dots are removed.

  • + *
  • For the module name, then any trailing digits and dots + * are removed, all non-alphanumeric characters ({@code [^A-Za-z0-9]}) + * are replaced with a dot ({@code "."}), all repeating dots are + * replaced with one dot, and all leading and trailing dots are + * removed.

  • * *
  • As an example, a JAR file named {@code foo-bar.jar} will * derive a module name {@code foo.bar} and no version. A JAR file diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,13 +31,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; -import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.module.ModuleDescriptor.Builder; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -56,15 +60,12 @@ final class ModuleInfo { - // supplies the set of packages when ConcealedPackages not present + // supplies the set of packages when ModulePackages attribute not present private final Supplier> packageFinder; - // indicates if the Hashes attribute should be parsed + // indicates if the ModuleHashes attribute should be parsed private final boolean parseHashes; - // the builder, created when parsing - private ModuleDescriptor.Builder builder; - private ModuleInfo(Supplier> pf, boolean ph) { packageFinder = pf; parseHashes = ph; @@ -86,9 +87,8 @@ { try { return new ModuleInfo(pf).doRead(new DataInputStream(in)); - } catch (IllegalArgumentException iae) { - // IllegalArgumentException means a malformed class - throw invalidModuleDescriptor(iae.getMessage()); + } catch (IllegalArgumentException | IllegalStateException e) { + throw invalidModuleDescriptor(e.getMessage()); } catch (EOFException x) { throw truncatedModuleDescriptor(); } @@ -105,9 +105,8 @@ { try { return new ModuleInfo(pf).doRead(new DataInputWrapper(bb)); - } catch (IllegalArgumentException iae) { - // IllegalArgumentException means a malformed class - throw invalidModuleDescriptor(iae.getMessage()); + } catch (IllegalArgumentException | IllegalStateException e) { + throw invalidModuleDescriptor(e.getMessage()); } catch (EOFException x) { throw truncatedModuleDescriptor(); } catch (IOException ioe) { @@ -117,7 +116,7 @@ /** * Reads a {@code module-info.class} from the given byte buffer - * but ignore the {@code Hashes} attribute. + * but ignore the {@code ModuleHashes} attribute. * * @throws InvalidModuleDescriptorException * @throws UncheckedIOException @@ -127,8 +126,8 @@ { try { return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb)); - } catch (IllegalArgumentException iae) { - throw invalidModuleDescriptor(iae.getMessage()); + } catch (IllegalArgumentException | IllegalStateException e) { + throw invalidModuleDescriptor(e.getMessage()); } catch (EOFException x) { throw truncatedModuleDescriptor(); } catch (IOException ioe) { @@ -164,12 +163,8 @@ throw invalidModuleDescriptor("access_flags should be ACC_MODULE"); int this_class = in.readUnsignedShort(); - String mn = cpool.getClassName(this_class); - int suffix = mn.indexOf("/module-info"); - if (suffix < 1) - throw invalidModuleDescriptor("this_class not of form name/module-info"); - mn = mn.substring(0, suffix).replace('/', '.'); - builder = new ModuleDescriptor.Builder(mn); + if (this_class != 0) + throw invalidModuleDescriptor("this_class must be 0"); int super_class = in.readUnsignedShort(); if (super_class > 0) @@ -192,6 +187,13 @@ // the names of the attributes found in the class file Set attributes = new HashSet<>(); + Builder builder = null; + Set packages = null; + String version = null; + String mainClass = null; + String[] osValues = null; + ModuleHashes hashes = null; + for (int i = 0; i < attributes_count ; i++) { int name_index = in.readUnsignedShort(); String attribute_name = cpool.getUtf8(name_index); @@ -206,28 +208,28 @@ switch (attribute_name) { case MODULE : - readModuleAttribute(mn, in, cpool); + builder = readModuleAttribute(in, cpool); break; - case CONCEALED_PACKAGES : - readConcealedPackagesAttribute(in, cpool); + case MODULE_PACKAGES : + packages = readModulePackagesAttribute(in, cpool); break; - case VERSION : - readVersionAttribute(in, cpool); + case MODULE_VERSION : + version = readModuleVersionAttribute(in, cpool); break; - case MAIN_CLASS : - readMainClassAttribute(in, cpool); + case MODULE_MAIN_CLASS : + mainClass = readModuleMainClassAttribute(in, cpool); break; - case TARGET_PLATFORM : - readTargetPlatformAttribute(in, cpool); + case MODULE_TARGET : + osValues = readModuleTargetAttribute(in, cpool); break; - case HASHES : + case MODULE_HASHES : if (parseHashes) { - readHashesAttribute(in, cpool); + hashes = readModuleHashesAttribute(in, cpool); } else { in.skipBytes(length); } @@ -245,53 +247,91 @@ } // the Module attribute is required - if (!attributes.contains(MODULE)) { + if (builder == null) { throw invalidModuleDescriptor(MODULE + " attribute not found"); } - // If the ConcealedPackages attribute is not present then the - // packageFinder is used to to find any non-exported packages. - if (!attributes.contains(CONCEALED_PACKAGES) && packageFinder != null) { - Set pkgs; + // If the ModulePackages attribute is not present then the packageFinder + // is used to find the set of packages + boolean usedPackageFinder = false; + if (packages == null && packageFinder != null) { try { - pkgs = new HashSet<>(packageFinder.get()); + packages = new HashSet<>(packageFinder.get()); } catch (UncheckedIOException x) { throw x.getCause(); } - pkgs.removeAll(builder.exportedPackages()); - builder.conceals(pkgs); + usedPackageFinder = true; + } + if (packages != null) { + for (String pn : builder.exportedAndOpenPackages()) { + if (!packages.contains(pn)) { + String tail; + if (usedPackageFinder) { + tail = " not found by package finder"; + } else { + tail = " missing from ModulePackages attribute"; + } + throw invalidModuleDescriptor("Package " + pn + tail); + } + packages.remove(pn); + } + builder.contains(packages); } - // Was the Synthetic attribute present? - if (attributes.contains(SYNTHETIC)) - builder.synthetic(true); + if (version != null) + builder.version(version); + if (mainClass != null) + builder.mainClass(mainClass); + if (osValues != null) { + if (osValues[0] != null) builder.osName(osValues[0]); + if (osValues[1] != null) builder.osArch(osValues[1]); + if (osValues[2] != null) builder.osVersion(osValues[2]); + } + if (hashes != null) + builder.hashes(hashes); return builder.build(); } /** - * Reads the Module attribute. + * Reads the Module attribute, returning the ModuleDescriptor.Builder to + * build the corresponding ModuleDescriptor. */ - private void readModuleAttribute(String mn, DataInput in, ConstantPool cpool) + private Builder readModuleAttribute(DataInput in, ConstantPool cpool) throws IOException { + // module_name + int module_name_index = in.readUnsignedShort(); + String mn = cpool.getUtf8AsBinaryName(module_name_index); + + Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false); + + int module_flags = in.readUnsignedShort(); + boolean open = ((module_flags & ACC_OPEN) != 0); + if (open) + builder.open(true); + if ((module_flags & ACC_SYNTHETIC) != 0) + builder.synthetic(true); + int requires_count = in.readUnsignedShort(); boolean requiresJavaBase = false; for (int i=0; i mods; + String dn = cpool.getUtf8AsBinaryName(index); + Set mods; if (flags == 0) { mods = Collections.emptySet(); } else { mods = new HashSet<>(); - if ((flags & ACC_PUBLIC) != 0) - mods.add(Modifier.PUBLIC); + if ((flags & ACC_TRANSITIVE) != 0) + mods.add(Requires.Modifier.TRANSITIVE); + if ((flags & ACC_STATIC_PHASE) != 0) + mods.add(Requires.Modifier.STATIC); if ((flags & ACC_SYNTHETIC) != 0) - mods.add(Modifier.SYNTHETIC); + mods.add(Requires.Modifier.SYNTHETIC); if ((flags & ACC_MANDATED) != 0) - mods.add(Modifier.MANDATED); + mods.add(Requires.Modifier.MANDATED); } builder.requires(mods, dn); if (dn.equals("java.base")) @@ -311,17 +351,66 @@ if (exports_count > 0) { for (int i=0; i mods; + int flags = in.readUnsignedShort(); + if (flags == 0) { + mods = Collections.emptySet(); + } else { + mods = new HashSet<>(); + if ((flags & ACC_SYNTHETIC) != 0) + mods.add(Exports.Modifier.SYNTHETIC); + if ((flags & ACC_MANDATED) != 0) + mods.add(Exports.Modifier.MANDATED); + } + int exports_to_count = in.readUnsignedShort(); if (exports_to_count > 0) { Set targets = new HashSet<>(exports_to_count); for (int j=0; j 0) { + if (open) { + throw invalidModuleDescriptor("The opens table for an open" + + " module must be 0 length"); + } + for (int i=0; i mods; + int flags = in.readUnsignedShort(); + if (flags == 0) { + mods = Collections.emptySet(); + } else { + mods = new HashSet<>(); + if ((flags & ACC_SYNTHETIC) != 0) + mods.add(Opens.Modifier.SYNTHETIC); + if ((flags & ACC_MANDATED) != 0) + mods.add(Opens.Modifier.MANDATED); + } + + int open_to_count = in.readUnsignedShort(); + if (open_to_count > 0) { + Set targets = new HashSet<>(open_to_count); + for (int j=0; j 0) { for (int i=0; i 0) { - Map> pm = new HashMap<>(); for (int i=0; i providers = pm.get(sn); - if (providers == null) { - providers = new LinkedHashSet<>(); // preserve order - pm.put(sn, providers); + String sn = cpool.getClassNameAsBinaryName(index); + int with_count = in.readUnsignedShort(); + List providers = new ArrayList<>(with_count); + for (int j=0; j> e : pm.entrySet()) { - builder.provides(e.getKey(), e.getValue()); + builder.provides(sn, providers); } } + + return builder; } /** - * Reads the ConcealedPackages attribute + * Reads the ModulePackages attribute */ - private void readConcealedPackagesAttribute(DataInput in, ConstantPool cpool) + private Set readModulePackagesAttribute(DataInput in, ConstantPool cpool) throws IOException { int package_count = in.readUnsignedShort(); + Set packages = new HashSet<>(package_count); for (int i=0; i map = new HashMap<>(hash_count); + Map map = new HashMap<>(hash_count); for (int i=0; i notAllowed = predefinedNotAllowed; @@ -477,12 +569,11 @@ "LineNumberTable", "LocalVariableTable", "LocalVariableTypeTable", - "RuntimeVisibleAnnotations", - "RuntimeInvisibleAnnotations", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "RuntimeVisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", + "Synthetic", "AnnotationDefault", "BootstrapMethods", "MethodParameters"); @@ -495,7 +586,6 @@ private static volatile Set predefinedNotAllowed; - /** * The constant pool in a class file. */ @@ -628,6 +718,11 @@ return getUtf8(((IndexEntry) e).index); } + String getClassNameAsBinaryName(int index) { + String value = getClassName(index); + return value.replace('/', '.'); // internal form -> binary name + } + String getUtf8(int index) { checkIndex(index); Entry e = pool[index]; @@ -638,6 +733,11 @@ return (String) (((ValueEntry) e).value); } + String getUtf8AsBinaryName(int index) { + String value = getUtf8(index); + return value.replace('/', '.'); // internal -> binary name + } + void checkIndex(int index) { if (index < 1 || index >= pool.length) throw invalidModuleDescriptor("Index into constant pool out of range"); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/ModulePath.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java Thu Dec 01 08:57:53 2016 +0000 @@ -40,9 +40,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -54,7 +55,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import jdk.internal.jmod.JmodFile; @@ -399,8 +399,8 @@ * * 1. The module name (and optionally the version) is derived from the file * name of the JAR file - * 2. The packages of all .class files in the JAR file are exported - * 3. It has no module-private/concealed packages + * 2. All packages are exported and open + * 3. It has no non-exported/non-open packages * 4. The contents of any META-INF/services configuration files are mapped * to "provides" declarations * 5. The Main-Class attribute in the main attributes of the JAR manifest @@ -440,8 +440,7 @@ // Builder throws IAE if module name is empty or invalid ModuleDescriptor.Builder builder - = new ModuleDescriptor.Builder(mn) - .automatic() + = ModuleDescriptor.automaticModule(mn) .requires(Set.of(Requires.Modifier.MANDATED), "java.base"); if (vs != null) builder.version(vs); @@ -455,13 +454,12 @@ Set resources = map.get(Boolean.FALSE); Set configFiles = map.get(Boolean.TRUE); - - // all packages are exported + // all packages are exported and open resources.stream() .map(this::toPackageName) .flatMap(Optional::stream) .distinct() - .forEach(builder::exports); + .forEach(pn -> builder.exports(pn).opens(pn)); // map names of service configuration files to service names Set serviceNames = configFiles.stream() @@ -472,7 +470,7 @@ // parse each service configuration file for (String sn : serviceNames) { JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn); - Set providerClasses = new LinkedHashSet<>(); + List providerClasses = new ArrayList<>(); try (InputStream in = jf.getInputStream(entry)) { BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); @@ -493,7 +491,7 @@ Attributes attrs = man.getMainAttributes(); String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS); if (mainClass != null) - builder.mainClass(mainClass); + builder.mainClass(mainClass.replace("/", ".")); } return builder.build(); @@ -504,6 +502,7 @@ */ private static class Patterns { static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))"); + static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$"); static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]"); static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+"); static final Pattern LEADING_DOTS = Pattern.compile("^\\."); @@ -514,6 +513,9 @@ * Clean up candidate module name derived from a JAR file name. */ private static String cleanModuleName(String mn) { + // drop trailing version from name + mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll(""); + // replace non-alphanumeric mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll("."); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java Thu Dec 01 08:57:53 2016 +0000 @@ -60,8 +60,8 @@ // the function that computes the hash of this module reference private final HashSupplier hasher; - // cached hash string to avoid needing to compute it many times - private String cachedHash; + // cached hash to avoid needing to compute it many times + private byte[] cachedHash; /** @@ -183,13 +183,13 @@ } /** - * Computes the hash of this module, returning it as a hex string. - * Returns {@code null} if the hash cannot be computed. + * Computes the hash of this module. Returns {@code null} if the hash + * cannot be computed. * * @throws java.io.UncheckedIOException if an I/O error occurs */ - String computeHash(String algorithm) { - String result = cachedHash; + byte[] computeHash(String algorithm) { + byte[] result = cachedHash; if (result != null) return result; if (hasher == null) @@ -211,8 +211,11 @@ public int hashCode() { int hc = hash; if (hc == 0) { - hc = Objects.hash(descriptor, location, readerSupplier, hasher, - Boolean.valueOf(patched)); + hc = descriptor.hashCode(); + hc = 43 * hc + readerSupplier.hashCode(); + hc = 43 * hc + Objects.hashCode(location); + hc = 43 * hc + Objects.hashCode(hasher); + hc = 43 * hc + Boolean.hashCode(patched); if (hc == 0) hc = -1; hash = hc; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java Thu Dec 01 08:57:53 2016 +0000 @@ -51,6 +51,7 @@ import jdk.internal.jmod.JmodFile; import jdk.internal.misc.JavaLangAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleHashes.HashSupplier; import jdk.internal.module.ModulePatcher; @@ -80,9 +81,8 @@ HashSupplier hasher) { ModuleReference mref = new ModuleReference(md, uri, supplier, hasher); - if (JLA.getBootLayer() == null) - mref = ModulePatcher.interposeIfNeeded(mref); + mref = ModuleBootstrap.patcher().patchIfNeeded(mref); return mref; } @@ -93,7 +93,7 @@ static ModuleReference newJarModule(ModuleDescriptor md, Path file) { URI uri = file.toUri(); Supplier supplier = () -> new JarModuleReader(file, uri); - HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a); + HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a); return newModule(md, uri, supplier, hasher); } @@ -103,7 +103,7 @@ static ModuleReference newJModModule(ModuleDescriptor md, Path file) { URI uri = file.toUri(); Supplier supplier = () -> new JModModuleReader(file, uri); - HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a); + HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a); return newModule(md, file.toUri(), supplier, hasher); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/Resolver.java --- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,9 +26,12 @@ package java.lang.module; import java.io.PrintStream; +import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.reflect.Layer; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Deque; import java.util.HashMap; @@ -47,12 +50,15 @@ /** * The resolver used by {@link Configuration#resolveRequires} and * {@link Configuration#resolveRequiresAndUses}. + * + * @implNote The resolver is used at VM startup and so deliberately avoids + * using lambda and stream usages in code paths used during startup. */ final class Resolver { private final ModuleFinder beforeFinder; - private final Configuration parent; + private final List parents; private final ModuleFinder afterFinder; private final PrintStream traceOutput; @@ -61,11 +67,11 @@ Resolver(ModuleFinder beforeFinder, - Configuration parent, + List parents, ModuleFinder afterFinder, PrintStream traceOutput) { this.beforeFinder = beforeFinder; - this.parent = parent; + this.parents = parents; this.afterFinder = afterFinder; this.traceOutput = traceOutput; } @@ -85,10 +91,12 @@ // find root module ModuleReference mref = findWithBeforeFinder(root); if (mref == null) { - if (parent.findModule(root).isPresent()) { + + if (findInParent(root) != null) { // in parent, nothing to do continue; } + mref = findWithAfterFinder(root); if (mref == null) { fail("Module %s not found", root); @@ -125,13 +133,21 @@ // process dependences for (ModuleDescriptor.Requires requires : descriptor.requires()) { + + // only required at compile-time + if (requires.modifiers().contains(Modifier.STATIC)) + continue; + String dn = requires.name(); // find dependence ModuleReference mref = findWithBeforeFinder(dn); if (mref == null) { - if (parent.findModule(dn).isPresent()) + + if (findInParent(dn) != null) { + // dependence is in parent continue; + } mref = findWithAfterFinder(dn); if (mref == null) { @@ -174,7 +190,9 @@ ModuleDescriptor descriptor = mref.descriptor(); if (!descriptor.provides().isEmpty()) { - for (String sn : descriptor.provides().keySet()) { + for (Provides provides : descriptor.provides()) { + String sn = provides.service(); + // computeIfAbsent Set providers = availableProviders.get(sn); if (providers == null) { @@ -191,19 +209,23 @@ Deque q = new ArrayDeque<>(); // the initial set of modules that may use services - Set candidateConsumers = new HashSet<>(); - Configuration p = parent; - while (p != null) { - candidateConsumers.addAll(p.descriptors()); - p = p.parent().orElse(null); + Set initialConsumers; + if (Layer.boot() == null) { + initialConsumers = new HashSet<>(); + } else { + initialConsumers = parents.stream() + .flatMap(Configuration::configurations) + .distinct() + .flatMap(c -> c.descriptors().stream()) + .collect(Collectors.toSet()); } for (ModuleReference mref : nameToReference.values()) { - candidateConsumers.add(mref.descriptor()); + initialConsumers.add(mref.descriptor()); } - // Where there is a consumer of a service then resolve all modules // that provide an implementation of that service + Set candidateConsumers = initialConsumers; do { for (ModuleDescriptor descriptor : candidateConsumers) { if (!descriptor.uses().isEmpty()) { @@ -234,7 +256,6 @@ } candidateConsumers = resolve(q); - } while (!candidateConsumers.isEmpty()); return this; @@ -429,21 +450,21 @@ for (String dn : hashes.names()) { ModuleReference other = nameToReference.get(dn); if (other == null) { - other = parent.findModule(dn) - .map(ResolvedModule::reference) - .orElse(null); + ResolvedModule resolvedModule = findInParent(dn); + if (resolvedModule != null) + other = resolvedModule.reference(); } // skip checking the hash if the module has been patched if (other != null && !other.isPatched()) { - String recordedHash = hashes.hashFor(dn); - String actualHash = other.computeHash(algorithm); + byte[] recordedHash = hashes.hashFor(dn); + byte[] actualHash = other.computeHash(algorithm); if (actualHash == null) fail("Unable to compute the hash of module %s", dn); - if (!recordedHash.equals(actualHash)) { + if (!Arrays.equals(recordedHash, actualHash)) { fail("Hash of %s (%s) differs to expected hash (%s)" + - " recorded in %s", dn, actualHash, recordedHash, - descriptor.name()); + " recorded in %s", dn, toHexString(actualHash), + toHexString(recordedHash), descriptor.name()); } } } @@ -451,52 +472,68 @@ } } + private static String toHexString(byte[] ba) { + StringBuilder sb = new StringBuilder(ba.length * 2); + for (byte b: ba) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } + /** * Computes the readability graph for the modules in the given Configuration. * * The readability graph is created by propagating "requires" through the - * "public requires" edges of the module dependence graph. So if the module - * dependence graph has m1 requires m2 && m2 requires public m3 then the - * resulting readability graph will contain m1 reads m2, m1 reads m3, and - * m2 reads m3. + * "requires transitive" edges of the module dependence graph. So if the + * module dependence graph has m1 requires m2 && m2 requires transitive m3 + * then the resulting readability graph will contain m1 reads m2, m1 reads m3, + * and m2 reads m3. */ private Map> makeGraph(Configuration cf) { + // initial capacity of maps to avoid resizing + int capacity = 1 + (4 * nameToReference.size())/ 3; + // the "reads" graph starts as a module dependence graph and // is iteratively updated to be the readability graph - Map> g1 = new HashMap<>(); - - // the "requires public" graph, contains requires public edges only - Map> g2 = new HashMap<>(); + Map> g1 = new HashMap<>(capacity); - - // need "requires public" from the modules in parent configurations as - // there may be selected modules that have a dependency on modules in - // the parent configuration. + // the "requires transitive" graph, contains requires transitive edges only + Map> g2; - Configuration p = parent; - while (p != null) { - for (ModuleDescriptor descriptor : p.descriptors()) { - String name = descriptor.name(); - ResolvedModule m1 = p.findModule(name) - .orElseThrow(() -> new InternalError(name + " not found")); - for (ModuleDescriptor.Requires requires : descriptor.requires()) { - if (requires.modifiers().contains(Modifier.PUBLIC)) { - String dn = requires.name(); - ResolvedModule m2 = p.findModule(dn) - .orElseThrow(() -> new InternalError(dn + " not found")); - g2.computeIfAbsent(m1, k -> new HashSet<>()).add(m2); - } - } - } - - p = p.parent().orElse(null); + // need "requires transitive" from the modules in parent configurations + // as there may be selected modules that have a dependency on modules in + // the parent configuration. + if (Layer.boot() == null) { + g2 = new HashMap<>(capacity); + } else { + g2 = parents.stream() + .flatMap(Configuration::configurations) + .distinct() + .flatMap(c -> + c.modules().stream().flatMap(m1 -> + m1.descriptor().requires().stream() + .filter(r -> r.modifiers().contains(Modifier.TRANSITIVE)) + .flatMap(r -> { + Optional m2 = c.findModule(r.name()); + assert m2.isPresent() + || r.modifiers().contains(Modifier.STATIC); + return m2.stream(); + }) + .map(m2 -> Map.entry(m1, m2)) + ) + ) + // stream of m1->m2 + .collect(Collectors.groupingBy(Map.Entry::getKey, + HashMap::new, + Collectors.mapping(Map.Entry::getValue, Collectors.toSet()) + )); } // populate g1 and g2 with the dependences from the selected modules - Map nameToResolved = new HashMap<>(); + Map nameToResolved = new HashMap<>(capacity); for (ModuleReference mref : nameToReference.values()) { ModuleDescriptor descriptor = mref.descriptor(); @@ -505,20 +542,21 @@ ResolvedModule m1 = computeIfAbsent(nameToResolved, name, cf, mref); Set reads = new HashSet<>(); - Set requiresPublic = new HashSet<>(); + Set requiresTransitive = new HashSet<>(); for (ModuleDescriptor.Requires requires : descriptor.requires()) { String dn = requires.name(); - ResolvedModule m2; + ResolvedModule m2 = null; ModuleReference mref2 = nameToReference.get(dn); if (mref2 != null) { // same configuration m2 = computeIfAbsent(nameToResolved, dn, cf, mref2); } else { // parent configuration - m2 = parent.findModule(dn).orElse(null); + m2 = findInParent(dn); if (m2 == null) { + assert requires.modifiers().contains(Modifier.STATIC); continue; } } @@ -526,9 +564,9 @@ // m1 requires m2 => m1 reads m2 reads.add(m2); - // m1 requires public m2 - if (requires.modifiers().contains(Modifier.PUBLIC)) { - requiresPublic.add(m2); + // m1 requires transitive m2 + if (requires.modifiers().contains(Modifier.TRANSITIVE)) { + requiresTransitive.add(m2); } } @@ -538,7 +576,7 @@ if (descriptor.isAutomatic()) { // reads all selected modules - // `requires public` all selected automatic modules + // `requires transitive` all selected automatic modules for (ModuleReference mref2 : nameToReference.values()) { ModuleDescriptor descriptor2 = mref2.descriptor(); String name2 = descriptor2.name(); @@ -548,40 +586,42 @@ = computeIfAbsent(nameToResolved, name2, cf, mref2); reads.add(m2); if (descriptor2.isAutomatic()) - requiresPublic.add(m2); + requiresTransitive.add(m2); } } // reads all modules in parent configurations - // `requires public` all automatic modules in parent configurations - p = parent; - while (p != null) { - for (ResolvedModule m : p.modules()) { - reads.add(m); - if (m.reference().descriptor().isAutomatic()) - requiresPublic.add(m); - } - p = p.parent().orElse(null); + // `requires transitive` all automatic modules in parent + // configurations + for (Configuration parent : parents) { + parent.configurations() + .map(Configuration::modules) + .flatMap(Set::stream) + .forEach(m -> { + reads.add(m); + if (m.reference().descriptor().isAutomatic()) + requiresTransitive.add(m); + }); } - } g1.put(m1, reads); - g2.put(m1, requiresPublic); + g2.put(m1, requiresTransitive); } - // Iteratively update g1 until there are no more requires public to propagate + // Iteratively update g1 until there are no more requires transitive + // to propagate boolean changed; - Set toAdd = new HashSet<>(); + List toAdd = new ArrayList<>(); do { changed = false; for (Set m1Reads : g1.values()) { for (ResolvedModule m2 : m1Reads) { - Set m2RequiresPublic = g2.get(m2); - if (m2RequiresPublic != null) { - for (ResolvedModule m3 : m2RequiresPublic) { + Set m2RequiresTransitive = g2.get(m2); + if (m2RequiresTransitive != null) { + for (ResolvedModule m3 : m2RequiresTransitive) { if (!m1Reads.contains(m3)) { - // m1 reads m2, m2 requires public m3 + // m1 reads m2, m2 requires transitive m3 // => need to add m1 reads m3 toAdd.add(m3); } @@ -655,7 +695,7 @@ // source is exported to descriptor2 String source = export.source(); ModuleDescriptor other - = packageToExporter.put(source, descriptor2); + = packageToExporter.putIfAbsent(source, descriptor2); if (other != null && other != descriptor2) { // package might be local to descriptor1 @@ -692,12 +732,8 @@ } // provides S - for (Map.Entry entry : - descriptor1.provides().entrySet()) { - String service = entry.getKey(); - ModuleDescriptor.Provides provides = entry.getValue(); - - String pn = packageName(service); + for (ModuleDescriptor.Provides provides : descriptor1.provides()) { + String pn = packageName(provides.service()); if (!packageToExporter.containsKey(pn)) { fail("Module %s does not read a module that exports %s", descriptor1.name(), pn); @@ -717,6 +753,18 @@ } + /** + * Find a module of the given name in the parent configurations + */ + private ResolvedModule findInParent(String mn) { + for (Configuration parent : parents) { + Optional om = parent.findModule(mn); + if (om.isPresent()) + return om.get(); + } + return null; + } + /** * Invokes the beforeFinder to find method to find the given module. @@ -755,15 +803,18 @@ if (afterModules.isEmpty()) return beforeModules; - if (beforeModules.isEmpty() && parent == Configuration.empty()) + if (beforeModules.isEmpty() + && parents.size() == 1 + && parents.get(0) == Configuration.empty()) return afterModules; Set result = new HashSet<>(beforeModules); for (ModuleReference mref : afterModules) { String name = mref.descriptor().name(); if (!beforeFinder.find(name).isPresent() - && !parent.findModule(name).isPresent()) + && findInParent(name) == null) { result.add(mref); + } } return result; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java --- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java Thu Dec 01 08:57:53 2016 +0000 @@ -39,6 +39,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -53,6 +54,7 @@ import jdk.internal.jimage.ImageReaderFactory; import jdk.internal.misc.JavaNetUriAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleHashes.HashSupplier; import jdk.internal.module.SystemModules; @@ -64,7 +66,7 @@ * run-time image. * * The modules linked into the run-time image are assumed to have the - * ConcealedPackages attribute. + * Packages attribute. */ class SystemModuleFinder implements ModuleFinder { @@ -102,8 +104,11 @@ int n = names.length; moduleCount.add(n); - Set mods = new HashSet<>(n); - Map map = new HashMap<>(n); + ModuleReference[] mods = new ModuleReference[n]; + + @SuppressWarnings(value = {"rawtypes", "unchecked"}) + Entry[] map + = (Entry[])new Entry[n]; for (int i = 0; i < n; i++) { ModuleDescriptor md = descriptors[i]; @@ -111,16 +116,16 @@ // create the ModuleReference ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i])); - mods.add(mref); - map.put(names[i], mref); + mods[i] = mref; + map[i] = Map.entry(names[i], mref); // counters packageCount.add(md.packages().size()); exportsCount.add(md.exports().size()); } - modules = Collections.unmodifiableSet(mods); - nameToModule = map; + modules = Set.of(mods); + nameToModule = Map.ofEntries(map); initTime.addElapsedTimeFrom(t0); } @@ -190,7 +195,7 @@ new ModuleReference(md, uri, readerSupplier, hash); // may need a reference to a patched module if --patch-module specified - mref = ModulePatcher.interposeIfNeeded(mref); + mref = ModuleBootstrap.patcher().patchIfNeeded(mref); return mref; } @@ -199,7 +204,7 @@ if (isFastPathSupported()) { return new HashSupplier() { @Override - public String generate(String algorithm) { + public byte[] generate(String algorithm) { return SystemModules.MODULES_TO_HASH[index]; } }; @@ -213,7 +218,7 @@ * It will get the recorded hashes from module-info.class. */ private static class Hashes { - static Map hashes = new HashMap<>(); + static Map hashes = new HashMap<>(); static void add(ModuleDescriptor descriptor) { Optional ohashes = descriptor.hashes(); @@ -228,7 +233,7 @@ return new HashSupplier() { @Override - public String generate(String algorithm) { + public byte[] generate(String algorithm) { return hashes.get(name); } }; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java --- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,12 +25,12 @@ package java.lang.reflect; +import java.lang.annotation.Annotation; import java.security.AccessController; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.ReflectionFactory; -import java.lang.annotation.Annotation; /** * The AccessibleObject class is the base class for Field, Method and @@ -81,8 +81,10 @@ *

    This method cannot be used to enable access to an object that is a * {@link Member member} of a class in a different module to the caller and * where the class is in a package that is not exported to the caller's - * module. Additionally, this method cannot be used to enable access to - * non-public members of {@code AccessibleObject} or {@link Module}. + * module. Additionally, if the member is non-public or its declaring + * class is non-public, then this method can only be used to enable access + * if the package is {@link Module#isOpen(String,Module) open} to at least + * the caller's module. * *

    If there is a security manager, its * {@code checkPermission} method is first called with a @@ -126,8 +128,10 @@ *

    This method cannot be used to enable access to an object that is a * {@link Member member} of a class in a different module to the caller and * where the class is in a package that is not exported to the caller's - * module. Additionally, this method cannot be used to enable access to - * non-public members of {@code AccessibleObject} or {@link Module}. + * module. Additionally, if the member is non-public or its declaring + * class is non-public, then this method can only be used to enable access + * if the package is {@link Module#isOpen(String,Module) open} to at least + * the caller's module. * *

    If there is a security manager, its * {@code checkPermission} method is first called with a @@ -138,6 +142,7 @@ * @throws SecurityException if the request is denied * @see SecurityManager#checkPermission * @see ReflectPermission + * @see java.lang.invoke.MethodHandles#privateLookupIn */ public void setAccessible(boolean flag) { AccessibleObject.checkPermission(); @@ -161,35 +166,39 @@ Module callerModule = caller.getModule(); Module declaringModule = declaringClass.getModule(); - if (callerModule != declaringModule - && callerModule != Object.class.getModule()) { + if (callerModule == declaringModule) return; + if (callerModule == Object.class.getModule()) return; + if (!declaringModule.isNamed()) return; - // check exports to target module - String pn = packageName(declaringClass); - if (!declaringModule.isExported(pn, callerModule)) { - String msg = "Unable to make member of " - + declaringClass + " accessible: " - + declaringModule + " does not export " - + pn + " to " + callerModule; - Reflection.throwInaccessibleObjectException(msg); - } - - } + // package is open to caller + String pn = packageName(declaringClass); + if (declaringModule.isOpen(pn, callerModule)) + return; - if (declaringClass == Module.class - || declaringClass == AccessibleObject.class) { - int modifiers; - if (this instanceof Executable) { - modifiers = ((Executable) this).getModifiers(); - } else { - modifiers = ((Field) this).getModifiers(); - } - if (!Modifier.isPublic(modifiers)) { - String msg = "Cannot make a non-public member of " - + declaringClass + " accessible"; - Reflection.throwInaccessibleObjectException(msg); - } + // package is exported to caller and class/member is public + boolean isExported = declaringModule.isExported(pn, callerModule); + boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); + int modifiers; + if (this instanceof Executable) { + modifiers = ((Executable) this).getModifiers(); + } else { + modifiers = ((Field) this).getModifiers(); } + boolean isMemberPublic = Modifier.isPublic(modifiers); + if (isExported && isClassPublic && isMemberPublic) + return; + + // not accessible + String msg = "Unable to make "; + if (this instanceof Field) + msg += "field "; + msg += this + " accessible: " + declaringModule + " does not \""; + if (isClassPublic && isMemberPublic) + msg += "exports"; + else + msg += "opens"; + msg += " " + pn + "\" to " + callerModule; + Reflection.throwInaccessibleObjectException(msg); } /** diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/reflect/Layer.java --- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,23 +27,29 @@ import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ResolvedModule; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.internal.loader.ClassLoaderValue; import jdk.internal.loader.Loader; import jdk.internal.loader.LoaderPool; import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.Modules; import jdk.internal.module.ServicesCatalog; -import jdk.internal.module.ServicesCatalog.ServiceProvider; import sun.security.util.SecurityConstants; @@ -55,7 +61,7 @@ * Creating a layer informs the Java virtual machine about the classes that * may be loaded from modules so that the Java virtual machine knows which * module that each class is a member of. Each layer, except the {@link - * #empty() empty} layer, has a {@link #parent() parent}.

    + * #empty() empty} layer, has at least one {@link #parents() parent}.

    * *

    Creating a layer creates a {@link Module} object for each {@link * ResolvedModule} in the configuration. For each resolved module that is @@ -71,7 +77,11 @@ * mapped to a single class loader or where each module is mapped to its own * class loader. The {@link #defineModules defineModules} method is for more * advanced cases where modules are mapped to custom class loaders by means of - * a function specified to the method.

    + * a function specified to the method. Each of these methods has an instance + * and static variant. The instance methods create a layer with the receiver + * as the parent layer. The static methods are for more advanced cases where + * there can be more than one parent layer or a {@link Layer.Controller + * Controller} is needed to control modules in the layer.

    * *

    A Java virtual machine has at least one non-empty layer, the {@link * #boot() boot} layer, that is created when the Java virtual machine is @@ -80,7 +90,7 @@ * The modules in the boot layer are mapped to the bootstrap class loader and * other class loaders that are * built-in into the Java virtual machine. The boot layer will often be - * the {@link #parent() parent} when creating additional layers.

    + * the {@link #parents() parent} when creating additional layers.

    * *

    As when creating a {@code Configuration}, * {@link ModuleDescriptor#isAutomatic() automatic} modules receive @@ -123,30 +133,29 @@ // the empty Layer private static final Layer EMPTY_LAYER - = new Layer(Configuration.empty(), null, null); + = new Layer(Configuration.empty(), List.of(), null); // the configuration from which this Layer was created private final Configuration cf; - // parent layer, null in the case of the empty layer - private final Layer parent; + // parent layers, empty in the case of the empty layer + private final List parents; // maps module name to jlr.Module private final Map nameToModule; - /** * Creates a new Layer from the modules in the given configuration. */ private Layer(Configuration cf, - Layer parent, + List parents, Function clf) { this.cf = cf; - this.parent = parent; + this.parents = parents; // no need to do defensive copy Map map; - if (parent == null) { + if (parents.isEmpty()) { map = Collections.emptyMap(); } else { map = Module.defineModules(cf, clf, this); @@ -154,12 +163,230 @@ this.nameToModule = map; // no need to do defensive copy } + /** + * Controls a layer. The static methods defined by {@link Layer} to create + * module layers return a {@code Controller} that can be used to control + * modules in the layer. + * + * @apiNote Care should be taken with {@code Controller} objects, they + * should never be shared with untrusted code. + * + * @since 9 + */ + public static final class Controller { + private final Layer layer; + + Controller(Layer layer) { + this.layer = layer; + } + + /** + * Returns the layer that this object controls. + * + * @return the layer + */ + public Layer layer() { + return layer; + } + + private void ensureInLayer(Module source) { + if (!layer.modules().contains(source)) + throw new IllegalArgumentException(source + " not in layer"); + } + + + /** + * Updates module {@code source} in the layer to read module + * {@code target}. This method is a no-op if {@code source} already + * reads {@code target}. + * + * @implNote Read edges added by this method are weak + * and do not prevent {@code target} from being GC'ed when {@code source} + * is strongly reachable. + * + * @param source + * The source module + * @param target + * The target module to read + * + * @return This controller + * + * @throws IllegalArgumentException + * If {@code source} is not in the layer + * + * @see Module#addReads + */ + public Controller addReads(Module source, Module target) { + Objects.requireNonNull(source); + Objects.requireNonNull(target); + ensureInLayer(source); + Modules.addReads(source, target); + return this; + } + + /** + * Updates module {@code source} in the layer to open a package to + * module {@code target}. This method is a no-op if {@code source} + * already opens the package to at least {@code target}. + * + * @param source + * The source module + * @param pn + * The package name + * @param target + * The target module to read + * + * @return This controller + * + * @throws IllegalArgumentException + * If {@code source} is not in the layer or the package is not + * in the source module + * + * @see Module#addOpens + */ + public Controller addOpens(Module source, String pn, Module target) { + Objects.requireNonNull(source); + Objects.requireNonNull(source); + Objects.requireNonNull(target); + ensureInLayer(source); + Modules.addOpens(source, pn, target); + return this; + } + } + /** * Creates a new layer, with this layer as its parent, by defining the * modules in the given {@code Configuration} to the Java virtual machine. * This method creates one class loader and defines all modules to that - * class loader. + * class loader. The {@link ClassLoader#getParent() parent} of each class + * loader is the given parent class loader. This method works exactly as + * specified by the static {@link + * #defineModulesWithOneLoader(Configuration,List,ClassLoader) + * defineModulesWithOneLoader} method when invoked with this layer as the + * parent. In other words, if this layer is {@code thisLayer} then this + * method is equivalent to invoking: + *

     {@code
    +     *     Layer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
    +     * }
    + * + * @param cf + * The configuration for the layer + * @param parentLoader + * The parent class loader for the class loader created by this + * method; may be {@code null} for the bootstrap class loader + * + * @return The newly created layer + * + * @throws IllegalArgumentException + * If the parent of the given configuration is not the configuration + * for this layer + * @throws LayerInstantiationException + * If all modules cannot be defined to the same class loader for any + * of the reasons listed above or the layer cannot be created because + * the configuration contains a module named "{@code java.base}" or + * a module with a package name starting with "{@code java.}" + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public Layer defineModulesWithOneLoader(Configuration cf, + ClassLoader parentLoader) { + return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer(); + } + + + /** + * Creates a new layer, with this layer as its parent, by defining the + * modules in the given {@code Configuration} to the Java virtual machine. + * Each module is defined to its own {@link ClassLoader} created by this + * method. The {@link ClassLoader#getParent() parent} of each class loader + * is the given parent class loader. This method works exactly as specified + * by the static {@link + * #defineModulesWithManyLoaders(Configuration,List,ClassLoader) + * defineModulesWithManyLoaders} method when invoked with this layer as the + * parent. In other words, if this layer is {@code thisLayer} then this + * method is equivalent to invoking: + *
     {@code
    +     *     Layer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
    +     * }
    + * + * @param cf + * The configuration for the layer + * @param parentLoader + * The parent class loader for each of the class loaders created by + * this method; may be {@code null} for the bootstrap class loader + * + * @return The newly created layer + * + * @throws IllegalArgumentException + * If the parent of the given configuration is not the configuration + * for this layer + * @throws LayerInstantiationException + * If the layer cannot be created because the configuration contains + * a module named "{@code java.base}" or a module with a package + * name starting with "{@code java.}" + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public Layer defineModulesWithManyLoaders(Configuration cf, + ClassLoader parentLoader) { + return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer(); + } + + + /** + * Creates a new layer, with this layer as its parent, by defining the + * modules in the given {@code Configuration} to the Java virtual machine. + * Each module is mapped, by name, to its class loader by means of the + * given function. This method works exactly as specified by the static + * {@link #defineModules(Configuration,List,Function) defineModules} + * method when invoked with this layer as the parent. In other words, if + * this layer is {@code thisLayer} then this method is equivalent to + * invoking: + *
     {@code
    +     *     Layer.defineModules(cf, List.of(thisLayer), clf).layer();
    +     * }
    + * + * @param cf + * The configuration for the layer + * @param clf + * The function to map a module name to a class loader + * + * @return The newly created layer + * + * @throws IllegalArgumentException + * If the parent of the given configuration is not the configuration + * for this layer + * @throws LayerInstantiationException + * If creating the {@code Layer} fails for any of the reasons + * listed above, the layer cannot be created because the + * configuration contains a module named "{@code java.base}", + * a module with a package name starting with "{@code java.}" is + * mapped to a class loader other than the {@link + * ClassLoader#getPlatformClassLoader() platform class loader}, + * or the function to map a module name to a class loader returns + * {@code null} + * @throws SecurityException + * If {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + */ + public Layer defineModules(Configuration cf, + Function clf) { + return defineModules(cf, List.of(this), clf).layer(); + } + + /** + * Creates a new layer by defining the modules in the given {@code + * Configuration} to the Java virtual machine. This method creates one + * class loader and defines all modules to that class loader. * *

    The class loader created by this method implements direct * delegation when loading types from modules. When its {@link @@ -180,7 +407,7 @@ *

      * *
    • Overlapping packages: Two or more modules in the - * configuration have the same package (exported or concealed).

    • + * configuration have the same package.

      * *
    • Split delegation: The resulting class loader would * need to delegate to more than one class loader in order to load types @@ -194,19 +421,22 @@ * * @param cf * The configuration for the layer + * @param parentLayers + * The list parent layers in search order * @param parentLoader * The parent class loader for the class loader created by this * method; may be {@code null} for the bootstrap class loader * - * @return The newly created layer + * @return A controller that controls the newly created layer * * @throws IllegalArgumentException - * If the parent of the given configuration is not the configuration - * for this layer + * If the parent configurations do not match the configuration of + * the parent layers, including order * @throws LayerInstantiationException * If all modules cannot be defined to the same class loader for any * of the reasons listed above or the layer cannot be created because - * the configuration contains a module named "{@code java.base}" + * the configuration contains a module named "{@code java.base}" or + * a module with a package name starting with "{@code java.}" * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -214,29 +444,32 @@ * * @see #findLoader */ - public Layer defineModulesWithOneLoader(Configuration cf, - ClassLoader parentLoader) + public static Controller defineModulesWithOneLoader(Configuration cf, + List parentLayers, + ClassLoader parentLoader) { - checkConfiguration(cf); + List parents = new ArrayList<>(parentLayers); + checkConfiguration(cf, parents); + checkCreateClassLoaderPermission(); checkGetClassLoaderPermission(); try { Loader loader = new Loader(cf.modules(), parentLoader); - loader.initRemotePackageMap(cf, this); - return new Layer(cf, this, mn -> loader); + loader.initRemotePackageMap(cf, parents); + Layer layer = new Layer(cf, parents, mn -> loader); + return new Controller(layer); } catch (IllegalArgumentException e) { throw new LayerInstantiationException(e.getMessage()); } } - /** - * Creates a new layer, with this layer as its parent, by defining the - * modules in the given {@code Configuration} to the Java virtual machine. - * Each module is defined to its own {@link ClassLoader} created by this - * method. The {@link ClassLoader#getParent() parent} of each class loader - * is the given parent class loader. + * Creates a new layer by defining the modules in the given {@code + * Configuration} to the Java virtual machine. Each module is defined to + * its own {@link ClassLoader} created by this method. The {@link + * ClassLoader#getParent() parent} of each class loader is the given parent + * class loader. * *

      The class loaders created by this method implement direct * delegation when loading types from modules. When {@link @@ -258,18 +491,21 @@ * * @param cf * The configuration for the layer + * @param parentLayers + * The list parent layers in search order * @param parentLoader * The parent class loader for each of the class loaders created by * this method; may be {@code null} for the bootstrap class loader * - * @return The newly created layer + * @return A controller that controls the newly created layer * * @throws IllegalArgumentException - * If the parent of the given configuration is not the configuration - * for this layer + * If the parent configurations do not match the configuration of + * the parent layers, including order * @throws LayerInstantiationException * If the layer cannot be created because the configuration contains - * a module named "{@code java.base}" + * a module named "{@code java.base}" or a module with a package + * name starting with "{@code java.}" * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -277,37 +513,43 @@ * * @see #findLoader */ - public Layer defineModulesWithManyLoaders(Configuration cf, - ClassLoader parentLoader) + public static Controller defineModulesWithManyLoaders(Configuration cf, + List parentLayers, + ClassLoader parentLoader) { - checkConfiguration(cf); + List parents = new ArrayList<>(parentLayers); + checkConfiguration(cf, parents); + checkCreateClassLoaderPermission(); checkGetClassLoaderPermission(); - LoaderPool pool = new LoaderPool(cf, this, parentLoader); + LoaderPool pool = new LoaderPool(cf, parents, parentLoader); try { - return new Layer(cf, this, pool::loaderFor); + Layer layer = new Layer(cf, parents, pool::loaderFor); + return new Controller(layer); } catch (IllegalArgumentException e) { throw new LayerInstantiationException(e.getMessage()); } } - /** - * Creates a new layer, with this layer as its parent, by defining the - * modules in the given {@code Configuration} to the Java virtual machine. + * Creates a new layer by defining the modules in the given {@code + * Configuration} to the Java virtual machine. * Each module is mapped, by name, to its class loader by means of the * given function. The class loader delegation implemented by these class - * loaders must respect module readability. In addition, the caller needs - * to arrange that the class loaders are ready to load from these module - * before there are any attempts to load classes or resources. + * loaders must respect module readability. The class loaders should be + * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to + * avoid deadlocks during class loading. In addition, the entity creating + * a new layer with this method should arrange that the class loaders are + * ready to load from these module before there are any attempts to load + * classes or resources. * *

      Creating a {@code Layer} can fail for the following reasons:

      * *
        * - *
      • Two or more modules with the same package (exported or - * concealed) are mapped to the same class loader.

      • + *
      • Two or more modules with the same package are mapped to the + * same class loader.

      • * *
      • A module is mapped to a class loader that already has a * module of the same name defined to it.

      • @@ -328,26 +570,35 @@ * * @param cf * The configuration for the layer + * @param parentLayers + * The list parent layers in search order * @param clf * The function to map a module name to a class loader * - * @return The newly created layer + * @return A controller that controls the newly created layer * * @throws IllegalArgumentException - * If the parent of the given configuration is not the configuration - * for this layer + * If the parent configurations do not match the configuration of + * the parent layers, including order * @throws LayerInstantiationException * If creating the {@code Layer} fails for any of the reasons - * listed above or the layer cannot be created because the - * configuration contains a module named "{@code java.base}" + * listed above, the layer cannot be created because the + * configuration contains a module named "{@code java.base}", + * a module with a package name starting with "{@code java.}" is + * mapped to a class loader other than the {@link + * ClassLoader#getPlatformClassLoader() platform class loader}, + * or the function to map a module name to a class loader returns + * {@code null} * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager */ - public Layer defineModules(Configuration cf, - Function clf) + public static Controller defineModules(Configuration cf, + List parentLayers, + Function clf) { - checkConfiguration(cf); + List parents = new ArrayList<>(parentLayers); + checkConfiguration(cf, parents); Objects.requireNonNull(clf); checkGetClassLoaderPermission(); @@ -362,7 +613,8 @@ } try { - return new Layer(cf, this, clf); + Layer layer = new Layer(cf, parents, clf); + return new Controller(layer); } catch (IllegalArgumentException iae) { // IAE is thrown by VM when defining the module fails throw new LayerInstantiationException(iae.getMessage()); @@ -370,13 +622,26 @@ } - private void checkConfiguration(Configuration cf) { + /** + * Checks that the parent configurations match the configuration of + * the parent layers. + */ + private static void checkConfiguration(Configuration cf, + List parentLayers) + { Objects.requireNonNull(cf); - Optional oparent = cf.parent(); - if (!oparent.isPresent() || oparent.get() != this.configuration()) { - throw new IllegalArgumentException( - "Parent of configuration != configuration of this Layer"); + List parentConfigurations = cf.parents(); + if (parentLayers.size() != parentConfigurations.size()) + throw new IllegalArgumentException("wrong number of parents"); + + int index = 0; + for (Layer parent : parentLayers) { + if (parent.configuration() != parentConfigurations.get(index)) { + throw new IllegalArgumentException( + "Parent of configuration != configuration of this Layer"); + } + index++; } } @@ -463,18 +728,57 @@ /** - * Returns this layer's parent unless this is the {@linkplain #empty empty - * layer}, which has no parent. + * Returns the list of this layer's parents unless this is the + * {@linkplain #empty empty layer}, which has no parents and so an + * empty list is returned. * - * @return This layer's parent + * @return The list of this layer's parents */ - public Optional parent() { - return Optional.ofNullable(parent); + public List parents() { + return parents; } /** - * Returns a set of the modules in this layer. + * Returns an ordered stream of layers. The first element is is this layer, + * the remaining elements are the parent layers in DFS order. + * + * @implNote For now, the assumption is that the number of elements will + * be very low and so this method does not use a specialized spliterator. + */ + Stream layers() { + List allLayers = this.allLayers; + if (allLayers != null) + return allLayers.stream(); + + allLayers = new ArrayList<>(); + Set visited = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + visited.add(this); + stack.push(this); + + while (!stack.isEmpty()) { + Layer layer = stack.pop(); + allLayers.add(layer); + + // push in reverse order + for (int i = layer.parents.size() - 1; i >= 0; i--) { + Layer parent = layer.parents.get(i); + if (!visited.contains(parent)) { + visited.add(parent); + stack.push(parent); + } + } + } + + this.allLayers = allLayers = Collections.unmodifiableList(allLayers); + return allLayers.stream(); + } + + private volatile List allLayers; + + /** + * Returns the set of the modules in this layer. * * @return A possibly-empty unmodifiable set of the modules in this layer */ @@ -486,7 +790,11 @@ /** * Returns the module with the given name in this layer, or if not in this - * layer, the {@linkplain #parent parent} layer. + * layer, the {@linkplain #parents parents} layers. Finding a module in + * parent layers is equivalent to invoking {@code findModule} on each + * parent, in search order, until the module is found or all parents have + * been searched. In a tree of layers then this is equivalent to + * a depth-first search. * * @param name * The name of the module to find @@ -496,17 +804,25 @@ * parent layer */ public Optional findModule(String name) { - Module m = nameToModule.get(Objects.requireNonNull(name)); + Objects.requireNonNull(name); + Module m = nameToModule.get(name); if (m != null) return Optional.of(m); - return parent().flatMap(l -> l.findModule(name)); + + return layers() + .skip(1) // skip this layer + .map(l -> l.nameToModule) + .filter(map -> map.containsKey(name)) + .map(map -> map.get(name)) + .findAny(); } /** * Returns the {@code ClassLoader} for the module with the given name. If - * a module of the given name is not in this layer then the {@link #parent} - * layer is checked. + * a module of the given name is not in this layer then the {@link #parents + * parent} layers are searched in the manner specified by {@link + * #findModule(String) findModule}. * *

        If there is a security manager then its {@code checkPermission} * method is called with a {@code RuntimePermission("getClassLoader")} @@ -527,20 +843,32 @@ * @throws SecurityException if denied by the security manager */ public ClassLoader findLoader(String name) { - Module m = nameToModule.get(Objects.requireNonNull(name)); - if (m != null) - return m.getClassLoader(); - Optional ol = parent(); - if (ol.isPresent()) - return ol.get().findLoader(name); - throw new IllegalArgumentException("Module " + name - + " not known to this layer"); + Optional om = findModule(name); + + // can't use map(Module::getClassLoader) as class loader can be null + if (om.isPresent()) { + return om.get().getClassLoader(); + } else { + throw new IllegalArgumentException("Module " + name + + " not known to this layer"); + } } + /** + * Returns a string describing this layer. + * + * @return A possibly empty string describing this layer + */ + @Override + public String toString() { + return modules().stream() + .map(Module::getName) + .collect(Collectors.joining(", ")); + } /** * Returns the empty layer. There are no modules in the empty - * layer. It has no parent. + * layer. It has no parents. * * @return The empty layer */ @@ -572,39 +900,12 @@ if (servicesCatalog != null) return servicesCatalog; - Map> map = new HashMap<>(); - for (Module m : nameToModule.values()) { - ModuleDescriptor descriptor = m.getDescriptor(); - for (Provides provides : descriptor.provides().values()) { - String service = provides.service(); - Set providers - = map.computeIfAbsent(service, k -> new HashSet<>()); - for (String pn : provides.providers()) { - providers.add(new ServiceProvider(m, pn)); - } - } - } - - ServicesCatalog catalog = new ServicesCatalog() { - @Override - public void register(Module module) { - throw new UnsupportedOperationException(); - } - @Override - public Set findServices(String service) { - Set providers = map.get(service); - if (providers == null) { - return Collections.emptySet(); - } else { - return Collections.unmodifiableSet(providers); - } - } - }; - synchronized (this) { servicesCatalog = this.servicesCatalog; if (servicesCatalog == null) { - this.servicesCatalog = servicesCatalog = catalog; + servicesCatalog = ServicesCatalog.create(); + nameToModule.values().forEach(servicesCatalog::register); + this.servicesCatalog = servicesCatalog; } } @@ -612,4 +913,36 @@ } private volatile ServicesCatalog servicesCatalog; + + + /** + * Record that this layer has at least one module defined to the given + * class loader. + */ + void bindToLoader(ClassLoader loader) { + // CLV.computeIfAbsent(loader, (cl, clv) -> new CopyOnWriteArrayList<>()) + List list = CLV.get(loader); + if (list == null) { + list = new CopyOnWriteArrayList<>(); + List previous = CLV.putIfAbsent(loader, list); + if (previous != null) list = previous; + } + list.add(this); + } + + /** + * Returns a stream of the layers that have at least one module defined to + * the given class loader. + */ + static Stream layers(ClassLoader loader) { + List list = CLV.get(loader); + if (list != null) { + return list.stream(); + } else { + return Stream.empty(); + } + } + + // the list of layers with modules defined to a class loader + private static final ClassLoaderValue> CLV = new ClassLoaderValue<>(); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/lang/reflect/Module.java --- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,15 +27,18 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Annotation; import java.lang.module.Configuration; import java.lang.module.ModuleReference; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; -import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Version; import java.lang.module.ResolvedModule; import java.net.URI; import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -49,9 +52,17 @@ import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.BootLoader; +import jdk.internal.loader.ResourceHelper; +import jdk.internal.misc.JavaLangAccess; import jdk.internal.misc.JavaLangReflectModuleAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ServicesCatalog; +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -83,7 +94,7 @@ * @see java.lang.Class#getModule */ -public final class Module { +public final class Module implements AnnotatedElement { // the layer that contains this module, can be null private final Layer layer; @@ -113,6 +124,10 @@ // define module to VM + boolean isOpen = descriptor.isOpen(); + Version version = descriptor.version().orElse(null); + String vs = Objects.toString(version, null); + String loc = Objects.toString(uri, null); Set packages = descriptor.packages(); int n = packages.size(); String[] array = new String[n]; @@ -120,11 +135,7 @@ for (String pn : packages) { array[i++] = pn.replace('.', '/'); } - Version version = descriptor.version().orElse(null); - String vs = Objects.toString(version, null); - String loc = Objects.toString(uri, null); - - defineModule0(this, vs, loc, array); + defineModule0(this, isOpen, vs, loc, array); } @@ -240,24 +251,24 @@ // -- - // the special Module to mean reads or exported to "all unnamed modules" + // special Module to mean "all unnamed modules" private static final Module ALL_UNNAMED_MODULE = new Module(null); - // special Module to mean exported to "everyone" + // special Module to mean "everyone" private static final Module EVERYONE_MODULE = new Module(null); - // exported to all modules - private static final Set EVERYONE = Collections.singleton(EVERYONE_MODULE); + // set contains EVERYONE_MODULE, used when a package is opened or + // exported unconditionally + private static final Set EVERYONE_SET = Set.of(EVERYONE_MODULE); // -- readability -- - // the modules that this module permanently reads - // (will be final when the modules are defined in reverse topology order) + // the modules that this module reads private volatile Set reads; // additional module (2nd key) that some module (1st key) reflectively reads - private static final WeakPairMap transientReads + private static final WeakPairMap reflectivelyReads = new WeakPairMap<>(); @@ -293,13 +304,13 @@ } // check if this module reads the other module reflectively - if (transientReads.containsKeyPair(this, other)) + if (reflectivelyReads.containsKeyPair(this, other)) return true; // if other is an unnamed module then check if this module reads // all unnamed modules if (!other.isNamed() - && transientReads.containsKeyPair(this, ALL_UNNAMED_MODULE)) + && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE)) return true; return false; @@ -309,9 +320,13 @@ * If the caller's module is this module then update this module to read * the given module. * - * This method is a no-op if {@code other} is this module (all modules can - * read themselves) or this module is an unnamed module (as unnamed modules - * read all modules). + * This method is a no-op if {@code other} is this module (all modules read + * themselves), this module is an unnamed module (as unnamed modules read + * all modules), or this module already reads {@code other}. + * + * @implNote Read edges added by this method are weak and + * do not prevent {@code other} from being GC'ed when this module is + * strongly reachable. * * @param other * The other module @@ -381,30 +396,39 @@ } // add reflective read - transientReads.putIfAbsent(this, other, Boolean.TRUE); + reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE); } - // -- exports -- + // -- exported and open packages -- + + // the packages are open to other modules, can be null + // if the value contains EVERYONE_MODULE then the package is open to all + private volatile Map> openPackages; - // the packages that are permanently exported - // (will be final when the modules are defined in reverse topology order) - private volatile Map> exports; + // the packages that are exported, can be null + // if the value contains EVERYONE_MODULE then the package is exported to all + private volatile Map> exportedPackages; - // additional exports added at run-time - // this module (1st key), other module (2nd key), exported packages (value) + // additional exports or opens added at run-time + // this module (1st key), other module (2nd key) + // (package name, open?) (value) private static final WeakPairMap> - transientExports = new WeakPairMap<>(); + reflectivelyExports = new WeakPairMap<>(); /** * Returns {@code true} if this module exports the given package to at * least the given module. * - *

        This method always return {@code true} when invoked on an unnamed + *

        This method returns {@code true} if invoked to test if a package in + * this module is exported to itself. It always returns {@code true} when + * invoked on an unnamed module. A package that is {@link #isOpen open} to + * the given module is considered exported to that module at run-time and + * so this method returns {@code true} if the package is open to the given * module.

        * - *

        This method does not check if the given module reads this module

        + *

        This method does not check if the given module reads this module.

        * * @param pn * The package name @@ -413,93 +437,196 @@ * * @return {@code true} if this module exports the package to at least the * given module + * + * @see ModuleDescriptor#exports() + * @see #addExports(String,Module) */ public boolean isExported(String pn, Module other) { Objects.requireNonNull(pn); Objects.requireNonNull(other); - return implIsExported(pn, other); + return implIsExportedOrOpen(pn, other, /*open*/false); + } + + /** + * Returns {@code true} if this module has opened a package to at + * least the given module. + * + *

        This method returns {@code true} if invoked to test if a package in + * this module is open to itself. It returns {@code true} when invoked on an + * {@link ModuleDescriptor#isOpen open} module with a package in the module. + * It always returns {@code true} when invoked on an unnamed module.

        + * + *

        This method does not check if the given module reads this module.

        + * + * @param pn + * The package name + * @param other + * The other module + * + * @return {@code true} if this module has opened the package + * to at least the given module + * + * @see ModuleDescriptor#opens() + * @see #addOpens(String,Module) + * @see AccessibleObject#setAccessible(boolean) + * @see java.lang.invoke.MethodHandles#privateLookupIn + */ + public boolean isOpen(String pn, Module other) { + Objects.requireNonNull(pn); + Objects.requireNonNull(other); + return implIsExportedOrOpen(pn, other, /*open*/true); } /** * Returns {@code true} if this module exports the given package * unconditionally. * - *

        This method always return {@code true} when invoked on an unnamed - * module.

        + *

        This method always returns {@code true} when invoked on an unnamed + * module. A package that is {@link #isOpen(String) opened} unconditionally + * is considered exported unconditionally at run-time and so this method + * returns {@code true} if the package is opened unconditionally.

        * - *

        This method does not check if the given module reads this module

        + *

        This method does not check if the given module reads this module.

        * * @param pn * The package name * * @return {@code true} if this module exports the package unconditionally + * + * @see ModuleDescriptor#exports() */ public boolean isExported(String pn) { Objects.requireNonNull(pn); - return implIsExported(pn, EVERYONE_MODULE); + return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/false); } /** - * Returns {@code true} if this module exports the given package to the - * given module. If the other module is {@code EVERYONE_MODULE} then - * this method tests if the package is exported unconditionally. + * Returns {@code true} if this module has opened a package + * unconditionally. + * + *

        This method always returns {@code true} when invoked on an unnamed + * module. Additionally, it always returns {@code true} when invoked on an + * {@link ModuleDescriptor#isOpen open} module with a package in the + * module.

        + * + *

        This method does not check if the given module reads this module.

        + * + * @param pn + * The package name + * + * @return {@code true} if this module has opened the package + * unconditionally + * + * @see ModuleDescriptor#opens() */ - private boolean implIsExported(String pn, Module other) { + public boolean isOpen(String pn) { + Objects.requireNonNull(pn); + return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/true); + } + - // all packages are exported by unnamed modules + /** + * Returns {@code true} if this module exports or opens the given package + * to the given module. If the other module is {@code EVERYONE_MODULE} then + * this method tests if the package is exported or opened unconditionally. + */ + private boolean implIsExportedOrOpen(String pn, Module other, boolean open) { + // all packages in unnamed modules are open if (!isNamed()) return true; - // exported via module declaration/descriptor - if (isExportedPermanently(pn, other)) + // all packages are exported/open to self + if (other == this && containsPackage(pn)) return true; - // exported via addExports - if (isExportedReflectively(pn, other)) + // all packages in open modules are open + if (descriptor.isOpen()) + return containsPackage(pn); + + // exported/opened via module declaration/descriptor + if (isStaticallyExportedOrOpen(pn, other, open)) return true; - // not exported or not exported to other + // exported via addExports/addOpens + if (isReflectivelyExportedOrOpen(pn, other, open)) + return true; + + // not exported or open to other return false; } /** - * Returns {@code true} if this module permanently exports the given - * package to the given module. + * Returns {@code true} if this module exports or opens a package to + * the given module via its module declaration. */ - private boolean isExportedPermanently(String pn, Module other) { - Map> exports = this.exports; - if (exports != null) { - Set targets = exports.get(pn); + private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) { + // package is open to everyone or + Map> openPackages = this.openPackages; + if (openPackages != null) { + Set targets = openPackages.get(pn); + if (targets != null) { + if (targets.contains(EVERYONE_MODULE)) + return true; + if (other != EVERYONE_MODULE && targets.contains(other)) + return true; + } + } - if ((targets != null) - && (targets.contains(other) || targets.contains(EVERYONE_MODULE))) - return true; + if (!open) { + // package is exported to everyone or + Map> exportedPackages = this.exportedPackages; + if (exportedPackages != null) { + Set targets = exportedPackages.get(pn); + if (targets != null) { + if (targets.contains(EVERYONE_MODULE)) + return true; + if (other != EVERYONE_MODULE && targets.contains(other)) + return true; + } + } } + return false; } + /** - * Returns {@code true} if this module reflectively exports the given + * Returns {@code true} if this module reflectively exports or opens given * package package to the given module. */ - private boolean isExportedReflectively(String pn, Module other) { - // exported to all modules - Map exports = transientExports.get(this, EVERYONE_MODULE); - if (exports != null && exports.containsKey(pn)) - return true; + private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) { + // exported or open to all modules + Map exports = reflectivelyExports.get(this, EVERYONE_MODULE); + if (exports != null) { + Boolean b = exports.get(pn); + if (b != null) { + boolean isOpen = b.booleanValue(); + if (!open || isOpen) return true; + } + } if (other != EVERYONE_MODULE) { - // exported to other - exports = transientExports.get(this, other); - if (exports != null && exports.containsKey(pn)) - return true; + // exported or open to other + exports = reflectivelyExports.get(this, other); + if (exports != null) { + Boolean b = exports.get(pn); + if (b != null) { + boolean isOpen = b.booleanValue(); + if (!open || isOpen) return true; + } + } - // other is an unnamed module && exported to all unnamed + // other is an unnamed module && exported or open to all unnamed if (!other.isNamed()) { - exports = transientExports.get(this, ALL_UNNAMED_MODULE); - if (exports != null && exports.containsKey(pn)) - return true; + exports = reflectivelyExports.get(this, ALL_UNNAMED_MODULE); + if (exports != null) { + Boolean b = exports.get(pn); + if (b != null) { + boolean isOpen = b.booleanValue(); + if (!open || isOpen) return true; + } + } } } @@ -510,11 +637,11 @@ /** * If the caller's module is this module then update this module to export - * package {@code pn} to the given module. + * the given package to the given module. * - *

        This method has no effect if the package is already exported to the - * given module. It also has no effect if invoked on an unnamed module (as - * unnamed modules export all packages).

        + *

        This method has no effect if the package is already exported (or + * open) to the given module. It also has no effect if + * invoked on an {@link ModuleDescriptor#isOpen open} module.

        * * @param pn * The package name @@ -528,6 +655,8 @@ * package {@code pn} is not a package in this module * @throws IllegalStateException * If this is a named module and the caller is not this module + * + * @see #isExported(String,Module) */ @CallerSensitive public Module addExports(String pn, Module other) { @@ -535,18 +664,66 @@ throw new IllegalArgumentException("package is null"); Objects.requireNonNull(other); - if (isNamed()) { + if (isNamed() && !descriptor.isOpen()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { throw new IllegalStateException(caller + " != " + this); } - implAddExports(pn, other, true); + implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true); } return this; } /** + * If the caller's module is this module then update this module to + * open the given package to the given module. + * Opening a package with this method allows all types in the package, + * and all their members, not just public types and their public members, + * to be reflected on by the given module when using APIs that support + * private access or a way to bypass or suppress default Java language + * access control checks. + * + *

        This method has no effect if the package is already open + * to the given module. It also has no effect if invoked on an {@link + * ModuleDescriptor#isOpen open} module.

        + * + * @param pn + * The package name + * @param other + * The module + * + * @return this module + * + * @throws IllegalArgumentException + * If {@code pn} is {@code null}, or this is a named module and the + * package {@code pn} is not a package in this module + * @throws IllegalStateException + * If this is a named module and the caller is not this module + * + * @see #isOpen(String,Module) + * @see AccessibleObject#setAccessible(boolean) + * @see java.lang.invoke.MethodHandles#privateLookupIn + */ + @CallerSensitive + public Module addOpens(String pn, Module other) { + if (pn == null) + throw new IllegalArgumentException("package is null"); + Objects.requireNonNull(other); + + if (isNamed() && !descriptor.isOpen()) { + Module caller = Reflection.getCallerClass().getModule(); + if (caller != this) { + throw new IllegalStateException(caller + " != " + this); + } + implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true); + } + + return this; + } + + + /** * Updates the exports so that package {@code pn} is exported to module * {@code other} but without notifying the VM. * @@ -555,7 +732,7 @@ void implAddExportsNoSync(String pn, Module other) { if (other == null) other = EVERYONE_MODULE; - implAddExports(pn.replace('/', '.'), other, false); + implAddExportsOrOpens(pn.replace('/', '.'), other, false, false); } /** @@ -565,25 +742,36 @@ * @apiNote This method is for white-box testing. */ void implAddExports(String pn, Module other) { - implAddExports(pn, other, true); + implAddExportsOrOpens(pn, other, false, true); } /** - * Updates the exports so that package {@code pn} is exported to module - * {@code other}. + * Updates the module to open package {@code pn} to module {@code other}. + * + * @apiNote This method is for white-box tests and jtreg + */ + void implAddOpens(String pn, Module other) { + implAddExportsOrOpens(pn, other, true, true); + } + + /** + * Updates a module to export or open a module to another module. * * If {@code syncVM} is {@code true} then the VM is notified. */ - private void implAddExports(String pn, Module other, boolean syncVM) { + private void implAddExportsOrOpens(String pn, + Module other, + boolean open, + boolean syncVM) { Objects.requireNonNull(other); Objects.requireNonNull(pn); - // unnamed modules export all packages - if (!isNamed()) + // all packages are open in unnamed and open modules + if (!isNamed() || descriptor.isOpen()) return; - // nothing to do if already exported to other - if (implIsExported(pn, other)) + // nothing to do if already exported/open to other + if (implIsExportedOrOpen(pn, other, open)) return; // can only export a package in the module @@ -604,18 +792,23 @@ } } - // add package name to transientExports if absent - transientExports + // add package name to reflectivelyExports if absent + Map map = reflectivelyExports .computeIfAbsent(this, other, - (_this, _other) -> new ConcurrentHashMap<>()) - .putIfAbsent(pn, Boolean.TRUE); + (m1, m2) -> new ConcurrentHashMap<>()); + + if (open) { + map.put(pn, Boolean.TRUE); // may need to promote from FALSE to TRUE + } else { + map.putIfAbsent(pn, Boolean.FALSE); + } } // -- services -- // additional service type (2nd key) that some module (1st key) uses - private static final WeakPairMap, Boolean> transientUses + private static final WeakPairMap, Boolean> reflectivelyUses = new WeakPairMap<>(); /** @@ -624,13 +817,13 @@ * for use by frameworks that invoke {@link java.util.ServiceLoader * ServiceLoader} on behalf of other modules or where the framework is * passed a reference to the service type by other code. This method is - * a no-op when invoked on an unnamed module. + * a no-op when invoked on an unnamed module or an automatic module. * *

        This method does not cause {@link * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be * re-run.

        * - * @param st + * @param service * The service type * * @return this module @@ -642,39 +835,45 @@ * @see ModuleDescriptor#uses() */ @CallerSensitive - public Module addUses(Class st) { - Objects.requireNonNull(st); + public Module addUses(Class service) { + Objects.requireNonNull(service); - if (isNamed()) { - + if (isNamed() && !descriptor.isAutomatic()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { throw new IllegalStateException(caller + " != " + this); } - - if (!canUse(st)) { - transientUses.putIfAbsent(this, st, Boolean.TRUE); - } - + implAddUses(service); } return this; } /** + * Update this module to add a service dependence on the given service + * type. + */ + void implAddUses(Class service) { + if (!canUse(service)) { + reflectivelyUses.putIfAbsent(this, service, Boolean.TRUE); + } + } + + + /** * Indicates if this module has a service dependence on the given service * type. This method always returns {@code true} when invoked on an unnamed - * module. + * module or an automatic module. * - * @param st + * @param service * The service type * * @return {@code true} if this module uses service type {@code st} * * @see #addUses(Class) */ - public boolean canUse(Class st) { - Objects.requireNonNull(st); + public boolean canUse(Class service) { + Objects.requireNonNull(service); if (!isNamed()) return true; @@ -683,11 +882,11 @@ return true; // uses was declared - if (descriptor.uses().contains(st.getName())) + if (descriptor.uses().contains(service.getName())) return true; // uses added via addUses - return transientUses.containsKeyPair(this, st); + return reflectivelyUses.containsKeyPair(this, service); } @@ -780,8 +979,12 @@ * If {@code syncVM} is {@code true} then the VM is notified. */ private void implAddPackage(String pn, boolean syncVM) { - if (pn.length() == 0) - throw new IllegalArgumentException(" package not allowed"); + if (!isNamed()) + throw new InternalError("adding package to unnamed module?"); + if (descriptor.isOpen()) + throw new InternalError("adding package to open module?"); + if (pn.isEmpty()) + throw new InternalError("adding package to module?"); if (descriptor.packages().contains(pn)) { // already in module @@ -822,28 +1025,7 @@ // -- creating Module objects -- /** - * Find the runtime Module corresponding to the given ResolvedModule - * in the given parent Layer (or its parents). - */ - private static Module find(ResolvedModule resolvedModule, Layer layer) { - Configuration cf = resolvedModule.configuration(); - String dn = resolvedModule.name(); - - Module m = null; - while (layer != null) { - if (layer.configuration() == cf) { - Optional om = layer.findModule(dn); - m = om.get(); - assert m.getLayer() == layer; - break; - } - layer = layer.parent().orElse(null); - } - return m; - } - - /** - * Defines each of the module in the given configuration to the runtime. + * Defines all module in a configuration to the runtime. * * @return a map of module name to runtime {@code Module} * @@ -854,26 +1036,40 @@ Function clf, Layer layer) { - Map modules = new HashMap<>(); - Map loaders = new HashMap<>(); + Map nameToModule = new HashMap<>(); + Map moduleToLoader = new HashMap<>(); + + boolean isBootLayer = (Layer.boot() == null); + Set loaders = new HashSet<>(); + + // map each module to a class loader + for (ResolvedModule resolvedModule : cf.modules()) { + String name = resolvedModule.name(); + ClassLoader loader = clf.apply(name); + if (loader != null) { + moduleToLoader.put(name, loader); + loaders.add(loader); + } else if (!isBootLayer) { + throw new IllegalArgumentException("loader can't be 'null'"); + } + } // define each module in the configuration to the VM for (ResolvedModule resolvedModule : cf.modules()) { ModuleReference mref = resolvedModule.reference(); ModuleDescriptor descriptor = mref.descriptor(); String name = descriptor.name(); - ClassLoader loader = clf.apply(name); URI uri = mref.location().orElse(null); - + ClassLoader loader = moduleToLoader.get(resolvedModule.name()); Module m; - if (loader == null && name.equals("java.base") && Layer.boot() == null) { + if (loader == null && isBootLayer && name.equals("java.base")) { + // java.base is already defined to the VM m = Object.class.getModule(); } else { m = new Module(layer, loader, descriptor, uri); } - - modules.put(name, m); - loaders.put(name, loader); + nameToModule.put(name, m); + moduleToLoader.put(name, loader); } // setup readability and exports @@ -882,20 +1078,24 @@ ModuleDescriptor descriptor = mref.descriptor(); String mn = descriptor.name(); - Module m = modules.get(mn); + Module m = nameToModule.get(mn); assert m != null; // reads Set reads = new HashSet<>(); - for (ResolvedModule d : resolvedModule.reads()) { - Module m2; - if (d.configuration() == cf) { - String dn = d.reference().descriptor().name(); - m2 = modules.get(dn); - assert m2 != null; + for (ResolvedModule other : resolvedModule.reads()) { + Module m2 = null; + if (other.configuration() == cf) { + String dn = other.reference().descriptor().name(); + m2 = nameToModule.get(dn); } else { - m2 = find(d, layer.parent().orElse(null)); + for (Layer parent: layer.parents()) { + m2 = findModule(parent, other); + if (m2 != null) + break; + } } + assert m2 != null; reads.add(m2); @@ -904,64 +1104,273 @@ } m.reads = reads; - // automatic modules reads all unnamed modules + // automatic modules read all unnamed modules if (descriptor.isAutomatic()) { m.implAddReads(ALL_UNNAMED_MODULE, true); } - // exports - Map> exports = new HashMap<>(); - for (Exports export : descriptor.exports()) { - String source = export.source(); - String sourceInternalForm = source.replace('.', '/'); - - if (export.isQualified()) { + // exports and opens + initExportsAndOpens(descriptor, nameToModule, m); + } - // qualified export - Set targets = new HashSet<>(); - for (String target : export.targets()) { - // only export to modules that are in this configuration - Module m2 = modules.get(target); - if (m2 != null) { - targets.add(m2); - addExports0(m, sourceInternalForm, m2); - } + // register the modules in the boot layer + if (isBootLayer) { + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + if (!descriptor.provides().isEmpty()) { + String name = descriptor.name(); + Module m = nameToModule.get(name); + ClassLoader loader = moduleToLoader.get(name); + ServicesCatalog catalog; + if (loader == null) { + catalog = BootLoader.getServicesCatalog(); + } else { + catalog = ServicesCatalog.getServicesCatalog(loader); } - if (!targets.isEmpty()) { - exports.put(source, targets); - } - - } else { - - // unqualified export - exports.put(source, EVERYONE); - addExportsToAll0(m, sourceInternalForm); + catalog.register(m); } } - m.exports = exports; + } + + // record that there is a layer with modules defined to the class loader + for (ClassLoader loader : loaders) { + layer.bindToLoader(loader); } - // register the modules in the service catalog if they provide services - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleReference mref = resolvedModule.reference(); - ModuleDescriptor descriptor = mref.descriptor(); - Map services = descriptor.provides(); - if (!services.isEmpty()) { - String name = descriptor.name(); - Module m = modules.get(name); - ClassLoader loader = loaders.get(name); - ServicesCatalog catalog; - if (loader == null) { - catalog = BootLoader.getServicesCatalog(); - } else { - catalog = SharedSecrets.getJavaLangAccess() - .createOrGetServicesCatalog(loader); + return nameToModule; + } + + + /** + * Find the runtime Module corresponding to the given ResolvedModule + * in the given parent layer (or its parents). + */ + private static Module findModule(Layer parent, ResolvedModule resolvedModule) { + Configuration cf = resolvedModule.configuration(); + String dn = resolvedModule.name(); + return parent.layers() + .filter(l -> l.configuration() == cf) + .findAny() + .map(layer -> { + Optional om = layer.findModule(dn); + assert om.isPresent() : dn + " not found in layer"; + Module m = om.get(); + assert m.getLayer() == layer : m + " not in expected layer"; + return m; + }) + .orElse(null); + } + + /** + * Initialize the maps of exported and open packages for module m. + */ + private static void initExportsAndOpens(ModuleDescriptor descriptor, + Map nameToModule, + Module m) + { + // The VM doesn't know about open modules so need to export all packages + if (descriptor.isOpen()) { + assert descriptor.opens().isEmpty(); + for (String source : descriptor.packages()) { + String sourceInternalForm = source.replace('.', '/'); + addExportsToAll0(m, sourceInternalForm); + } + return; + } + + Map> openPackages = new HashMap<>(); + Map> exportedPackages = new HashMap<>(); + + // process the open packages first + for (Opens opens : descriptor.opens()) { + String source = opens.source(); + String sourceInternalForm = source.replace('.', '/'); + + if (opens.isQualified()) { + // qualified opens + Set targets = new HashSet<>(); + for (String target : opens.targets()) { + // only open to modules that are in this configuration + Module m2 = nameToModule.get(target); + if (m2 != null) { + addExports0(m, sourceInternalForm, m2); + targets.add(m2); + } } - catalog.register(m); + if (!targets.isEmpty()) { + openPackages.put(source, targets); + } + } else { + // unqualified opens + addExportsToAll0(m, sourceInternalForm); + openPackages.put(source, EVERYONE_SET); } } - return modules; + // next the exports, skipping exports when the package is open + for (Exports exports : descriptor.exports()) { + String source = exports.source(); + String sourceInternalForm = source.replace('.', '/'); + + // skip export if package is already open to everyone + Set openToTargets = openPackages.get(source); + if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE)) + continue; + + if (exports.isQualified()) { + // qualified exports + Set targets = new HashSet<>(); + for (String target : exports.targets()) { + // only export to modules that are in this configuration + Module m2 = nameToModule.get(target); + if (m2 != null) { + // skip qualified export if already open to m2 + if (openToTargets == null || !openToTargets.contains(m2)) { + addExports0(m, sourceInternalForm, m2); + targets.add(m2); + } + } + } + if (!targets.isEmpty()) { + exportedPackages.put(source, targets); + } + + } else { + // unqualified exports + addExportsToAll0(m, sourceInternalForm); + exportedPackages.put(source, EVERYONE_SET); + } + } + + if (!openPackages.isEmpty()) + m.openPackages = openPackages; + if (!exportedPackages.isEmpty()) + m.exportedPackages = exportedPackages; + } + + + // -- annotations -- + + /** + * {@inheritDoc} + * This method returns {@code null} when invoked on an unnamed module. + */ + @Override + public T getAnnotation(Class annotationClass) { + return moduleInfoClass().getDeclaredAnnotation(annotationClass); + } + + /** + * {@inheritDoc} + * This method returns an empty array when invoked on an unnamed module. + */ + @Override + public Annotation[] getAnnotations() { + return moduleInfoClass().getAnnotations(); + } + + /** + * {@inheritDoc} + * This method returns an empty array when invoked on an unnamed module. + */ + @Override + public Annotation[] getDeclaredAnnotations() { + return moduleInfoClass().getDeclaredAnnotations(); + } + + // cached class file with annotations + private volatile Class moduleInfoClass; + + private Class moduleInfoClass() { + Class clazz = this.moduleInfoClass; + if (clazz != null) + return clazz; + + synchronized (this) { + clazz = this.moduleInfoClass; + if (clazz == null) { + if (isNamed()) { + PrivilegedAction> pa = this::loadModuleInfoClass; + clazz = AccessController.doPrivileged(pa); + } + if (clazz == null) { + class DummyModuleInfo { } + clazz = DummyModuleInfo.class; + } + this.moduleInfoClass = clazz; + } + return clazz; + } + } + + private Class loadModuleInfoClass() { + Class clazz = null; + try (InputStream in = getResourceAsStream("module-info.class")) { + if (in != null) + clazz = loadModuleInfoClass(in); + } catch (Exception ignore) { } + return clazz; + } + + /** + * Loads module-info.class as a package-private interface in a class loader + * that is a child of this module's class loader. + */ + private Class loadModuleInfoClass(InputStream in) throws IOException { + final String MODULE_INFO = "module-info"; + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); + + ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) { + @Override + public void visit(int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { + cw.visit(version, + Opcodes.ACC_INTERFACE + + Opcodes.ACC_ABSTRACT + + Opcodes.ACC_SYNTHETIC, + MODULE_INFO, + null, + "java/lang/Object", + null); + } + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + // keep annotations + return super.visitAnnotation(desc, visible); + } + @Override + public void visitAttribute(Attribute attr) { + // drop non-annotation attributes + } + }; + + ClassReader cr = new ClassReader(in); + cr.accept(cv, 0); + byte[] bytes = cw.toByteArray(); + + ClassLoader cl = new ClassLoader(loader) { + @Override + protected Class findClass(String cn)throws ClassNotFoundException { + if (cn.equals(MODULE_INFO)) { + return super.defineClass(cn, bytes, 0, bytes.length); + } else { + throw new ClassNotFoundException(cn); + } + } + }; + + try { + return cl.loadClass(MODULE_INFO); + } catch (ClassNotFoundException e) { + throw new InternalError(e); + } } @@ -969,16 +1378,35 @@ /** - * Returns an input stream for reading a resource in this module. Returns - * {@code null} if the resource is not in this module or access to the - * resource is denied by the security manager. - * The {@code name} is a {@code '/'}-separated path name that identifies - * the resource. + * Returns an input stream for reading a resource in this module. The + * {@code name} parameter is a {@code '/'}-separated path name that + * identifies the resource. + * + *

        A resource in a named modules may be encapsulated so that + * it cannot be located by code in other modules. Whether a resource can be + * located or not is determined as follows: + * + *

          + *
        • The package name of the resource is derived from the + * subsequence of characters that precedes the last {@code '/'} and then + * replacing each {@code '/'} character in the subsequence with + * {@code '.'}. For example, the package name derived for a resource + * named "{@code a/b/c/foo.properties}" is "{@code a.b.c}".
        • * - *

          If this module is an unnamed module, and the {@code ClassLoader} for - * this module is not {@code null}, then this method is equivalent to - * invoking the {@link ClassLoader#getResourceAsStream(String) - * getResourceAsStream} method on the class loader for this module. + *

        • If the package name is a package in the module then the package + * must be {@link #isOpen open} the module of the caller of this method. + * If the package is not in the module then the resource is not + * encapsulated. Resources in the unnamed package or "{@code META-INF}", + * for example, are never encapsulated because they can never be + * packages in a named module.
        • + * + *
        • As a special case, resources ending with "{@code .class}" are + * never encapsulated.
        • + *
        + * + *

        This method returns {@code null} if the resource is not in this + * module, the resource is encapsulated and cannot be located by the caller, + * or access to the resource is denied by the security manager. * * @param name * The resource name @@ -990,36 +1418,35 @@ * * @see java.lang.module.ModuleReader#open(String) */ + @CallerSensitive public InputStream getResourceAsStream(String name) throws IOException { Objects.requireNonNull(name); - URL url = null; - - if (isNamed()) { - String mn = this.name; - - // special-case built-in class loaders to avoid URL connection - if (loader == null) { - return BootLoader.findResourceAsStream(mn, name); - } else if (loader instanceof BuiltinClassLoader) { - return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name); + if (isNamed() && !ResourceHelper.isSimpleResource(name)) { + Module caller = Reflection.getCallerClass().getModule(); + if (caller != this && caller != Object.class.getModule()) { + // ignore packages added for proxies via addPackage + Set packages = getDescriptor().packages(); + String pn = ResourceHelper.getPackageName(name); + if (packages.contains(pn) && !isOpen(pn, caller)) { + // resource is in package not open to caller + return null; + } } - - // use SharedSecrets to invoke protected method - url = SharedSecrets.getJavaLangAccess().findResource(loader, mn, name); - - } else { - - // unnamed module - if (loader == null) { - url = BootLoader.findResource(name); - } else { - return loader.getResourceAsStream(name); - } - } - // fallthrough to URL case + String mn = this.name; + + // special-case built-in class loaders to avoid URL connection + if (loader == null) { + return BootLoader.findResourceAsStream(mn, name); + } else if (loader instanceof BuiltinClassLoader) { + return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name); + } + + // locate resource in module + JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + URL url = jla.findResource(loader, mn, name); if (url != null) { try { return url.openStream(); @@ -1053,6 +1480,7 @@ // JVM_DefineModule private static native void defineModule0(Module module, + boolean isOpen, String version, String location, String[] pns); @@ -1098,15 +1526,31 @@ } @Override public void addExports(Module m, String pn, Module other) { - m.implAddExports(pn, other, true); + m.implAddExportsOrOpens(pn, other, false, true); + } + @Override + public void addOpens(Module m, String pn, Module other) { + m.implAddExportsOrOpens(pn, other, true, true); } @Override public void addExportsToAll(Module m, String pn) { - m.implAddExports(pn, Module.EVERYONE_MODULE, true); + m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true); + } + @Override + public void addOpensToAll(Module m, String pn) { + m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true); } @Override public void addExportsToAllUnnamed(Module m, String pn) { - m.implAddExports(pn, Module.ALL_UNNAMED_MODULE, true); + m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true); + } + @Override + public void addOpensToAllUnnamed(Module m, String pn) { + m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, true, true); + } + @Override + public void addUses(Module m, Class service) { + m.implAddUses(service); } @Override public void addPackage(Module m, String pn) { @@ -1116,6 +1560,14 @@ public ServicesCatalog getServicesCatalog(Layer layer) { return layer.getServicesCatalog(); } + @Override + public Stream layers(Layer layer) { + return layer.layers(); + } + @Override + public Stream layers(ClassLoader loader) { + return Layer.layers(loader); + } }); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/util/ResourceBundle.java --- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java Thu Dec 01 08:57:53 2016 +0000 @@ -42,6 +42,7 @@ import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; @@ -62,13 +63,14 @@ import java.util.spi.ResourceBundleControlProvider; import java.util.spi.ResourceBundleProvider; +import jdk.internal.loader.BootLoader; import jdk.internal.misc.JavaUtilResourceBundleAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import sun.security.action.GetPropertyAction; import sun.util.locale.BaseLocale; import sun.util.locale.LocaleObjectCache; -import sun.util.locale.provider.ResourceBundleProviderSupport; import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; @@ -247,7 +249,8 @@ * used to load resource bundles. If no service provider is available, or if * none of the service providers returns a resource bundle and the caller module * doesn't have its own service provider, the {@code getBundle} factory method - * searches for resource bundles local to the caller module. The resource bundle + * searches for resource bundles that are local in the caller module and that + * are visible to the class loader of the caller module. The resource bundle * formats for local module searching are "java.class" and "java.properties". * *

        ResourceBundle.Control

        @@ -372,6 +375,18 @@ public void setName(ResourceBundle bundle, String name) { bundle.name = name; } + + @Override + public ResourceBundle getBundle(String baseName, Locale locale, Module module) { + // use the given module as the caller to bypass the access check + return getBundleImpl(module, module, getLoader(module), + baseName, locale, Control.INSTANCE); + } + + @Override + public ResourceBundle newResourceBundle(Class bundleClass) { + return ResourceBundleProviderHelper.newResourceBundle(bundleClass); + } }); } @@ -999,6 +1014,14 @@ * getBundle(baseName, Locale.getDefault(), module) * * + *

        Resource bundles in named modules may be encapsulated. When + * the resource bundle is loaded from a provider, the caller module + * must have an appropriate uses clause in its module descriptor + * to declare that the module uses implementations of {@code "baseName"Provider}. + * When the resource bundle is loaded from the specified module, it is + * subject to the encapsulation rules specified by + * {@link Module#getResourceAsStream Module.getResourceAsStream}. + * * @param baseName the base name of the resource bundle, * a fully qualified class name * @param module the module for which the resource bundle is searched @@ -1024,10 +1047,19 @@ * Gets a resource bundle using the specified base name and locale * on behalf of the specified module. * + *

        Resource bundles in named modules may be encapsulated. When + * the resource bundle is loaded from a provider, the caller module + * must have an appropriate uses clause in its module descriptor + * to declare that the module uses implementations of {@code "baseName"Provider}. + * When the resource bundle is loaded from the specified module, it is + * subject to the encapsulation rules specified by + * {@link Module#getResourceAsStream Module.getResourceAsStream}. + * *

        * If the given {@code module} is a named module, this method will * load the service providers for {@link java.util.spi.ResourceBundleProvider} - * and also resource bundles local in the given module (refer to the + * and also resource bundles that are local in the given module or that + * are visible to the class loader of the given module (refer to the * Resource Bundles in Named Modules section * for details). * @@ -1035,9 +1067,8 @@ * If the given {@code module} is an unnamed module, then this method is * equivalent to calling {@link #getBundle(String, Locale, ClassLoader) * getBundle(baseName, targetLocale, module.getClassLoader()} to load - * resource bundles that are in unnamed modules visible to the - * class loader of the given unnamed module. It will not find resource - * bundles from named modules. + * resource bundles that are visible to the class loader of the given + * unnamed module. * * @param baseName the base name of the resource bundle, * a fully qualified class name @@ -1126,7 +1157,8 @@ * Resource bundles in a named module are private to that module. If * the caller is in a named module, this method will find resource bundles * from the service providers of {@link java.util.spi.ResourceBundleProvider} - * and also find resource bundles private to the caller's module. + * and also find resource bundles that are in the caller's module or + * that are visible to the given class loader. * If the caller is in a named module and the given {@code loader} is * different than the caller's class loader, or if the caller is not in * a named module, this method will not find resource bundles from named @@ -1587,13 +1619,20 @@ // get resource bundles for a named module only // if loader is the module's class loader if (loader == ml || (ml == null && loader == RBClassLoader.INSTANCE)) { - return getBundleImpl(baseName, locale, loader, module, control); + return getBundleImpl(module, module, loader, baseName, locale, control); } } // find resource bundles from unnamed module - Module module = loader != null ? loader.getUnnamedModule() - : ClassLoader.getSystemClassLoader().getUnnamedModule(); - return getBundleImpl(baseName, locale, loader, module, control); + Module unnamedModule = loader != null + ? loader.getUnnamedModule() + : ClassLoader.getSystemClassLoader().getUnnamedModule(); + + if (caller == null) { + throw new InternalError("null caller"); + } + + Module callerModule = caller.getModule(); + return getBundleImpl(callerModule, unnamedModule, loader, baseName, locale, control); } private static ResourceBundle getBundleFromModule(Class caller, @@ -1602,19 +1641,21 @@ Locale locale, Control control) { Objects.requireNonNull(module); - if (caller.getModule() != module) { + Module callerModule = caller.getModule(); + if (callerModule != module) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(GET_CLASSLOADER_PERMISSION); } } - return getBundleImpl(baseName, locale, getLoader(module), module, control); + return getBundleImpl(callerModule, module, getLoader(module), baseName, locale, control); } - private static ResourceBundle getBundleImpl(String baseName, + private static ResourceBundle getBundleImpl(Module callerModule, + Module module, + ClassLoader loader, + String baseName, Locale locale, - ClassLoader loader, - Module module, Control control) { if (locale == null || control == null) { throw new NullPointerException(); @@ -1661,7 +1702,8 @@ throw new IllegalArgumentException("Invalid Control: getCandidateLocales"); } - bundle = findBundle(cacheKey, module, candidateLocales, formats, 0, control, baseBundle); + bundle = findBundle(callerModule, module, cacheKey, + candidateLocales, formats, 0, control, baseBundle); // If the loaded bundle is the base bundle and exactly for the // requested locale or the only candidate locale, then take the @@ -1710,8 +1752,9 @@ return valid; } - private static ResourceBundle findBundle(CacheKey cacheKey, + private static ResourceBundle findBundle(Module callerModule, Module module, + CacheKey cacheKey, List candidateLocales, List formats, int index, @@ -1720,7 +1763,8 @@ Locale targetLocale = candidateLocales.get(index); ResourceBundle parent = null; if (index != candidateLocales.size() - 1) { - parent = findBundle(cacheKey, module, candidateLocales, formats, index + 1, + parent = findBundle(callerModule, module, cacheKey, + candidateLocales, formats, index + 1, control, baseBundle); } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) { return baseBundle; @@ -1764,10 +1808,10 @@ if (bundle != NONEXISTENT_BUNDLE) { CacheKey constKey = (CacheKey) cacheKey.clone(); - + trace("findBundle: %d %s %s formats: %s%n", index, candidateLocales, cacheKey, formats); try { if (module.isNamed()) { - bundle = loadBundle(cacheKey, formats, control, module); + bundle = loadBundle(cacheKey, formats, control, module, callerModule); } else { bundle = loadBundle(cacheKey, formats, control, expiredBundle); } @@ -1794,39 +1838,60 @@ private static final String UNKNOWN_FORMAT = ""; + /* * Loads a ResourceBundle in named modules */ private static ResourceBundle loadBundle(CacheKey cacheKey, List formats, Control control, - Module module) { + Module module, + Module callerModule) { String baseName = cacheKey.getName(); Locale targetLocale = cacheKey.getLocale(); ResourceBundle bundle = null; if (cacheKey.hasProviders()) { - bundle = loadBundleFromProviders(baseName, targetLocale, - cacheKey.getProviders(), cacheKey); + if (callerModule == module) { + bundle = loadBundleFromProviders(baseName, + targetLocale, + cacheKey.getProviders(), + cacheKey); + } else { + // load from provider if the caller module has access to the + // service type and also declares `uses` + ClassLoader loader = getLoader(module); + Class svc = + getResourceBundleProviderType(baseName, loader); + if (svc != null + && Reflection.verifyModuleAccess(callerModule, svc) + && callerModule.canUse(svc)) { + bundle = loadBundleFromProviders(baseName, + targetLocale, + cacheKey.getProviders(), + cacheKey); + } + } + if (bundle != null) { cacheKey.setFormat(UNKNOWN_FORMAT); } } + // If none of providers returned a bundle and the caller has no provider, - // look up module-local bundles. + // look up module-local bundles or from the class path if (bundle == null && !cacheKey.callerHasProvider()) { - String bundleName = control.toBundleName(baseName, targetLocale); for (String format : formats) { try { switch (format) { case "java.class": - PrivilegedAction pa = () - -> ResourceBundleProviderSupport - .loadResourceBundle(module, bundleName); - bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION); + bundle = ResourceBundleProviderHelper + .loadResourceBundle(callerModule, module, baseName, targetLocale); + break; case "java.properties": - bundle = ResourceBundleProviderSupport.loadPropertyResourceBundle(module, bundleName); + bundle = ResourceBundleProviderHelper + .loadPropertyResourceBundle(callerModule, module, baseName, targetLocale); break; default: throw new InternalError("unexpected format: " + format); @@ -1844,29 +1909,46 @@ return bundle; } + /** + * Returns a ServiceLoader that will find providers that are bound to + * a given named module. + */ private static ServiceLoader getServiceLoader(Module module, - String baseName) { + String baseName) + { if (!module.isNamed()) { return null; } - PrivilegedAction pa = module::getClassLoader; - ClassLoader loader = AccessController.doPrivileged(pa); - return getServiceLoader(module, loader, baseName); + + ClassLoader loader = getLoader(module); + Class service = + getResourceBundleProviderType(baseName, loader); + if (service != null && Reflection.verifyModuleAccess(module, service)) { + try { + // locate providers that are visible to the class loader + // ServiceConfigurationError will be thrown if the module + // does not declare `uses` the service type + return ServiceLoader.load(service, loader, module); + } catch (ServiceConfigurationError e) { + // "uses" not declared + return null; + } + } + return null; } - /** - * Returns a ServiceLoader that will find providers that are bound to - * a given module that may be named or unnamed. - */ - private static ServiceLoader getServiceLoader(Module module, - ClassLoader loader, - String baseName) + /** + * Returns the service type of the given baseName that is visible + * to the given class loader + */ + private static Class + getResourceBundleProviderType(String baseName, ClassLoader loader) { // Look up + "Provider" String providerName = baseName + "Provider"; // Use the class loader of the getBundle caller so that the caller's // visibility of the provider type is checked. - Class service = AccessController.doPrivileged( + return AccessController.doPrivileged( new PrivilegedAction<>() { @Override public Class run() { @@ -1881,16 +1963,6 @@ return null; } }); - - if (service != null && Reflection.verifyModuleAccess(module, service)) { - try { - return ServiceLoader.load(service, loader, module); - } catch (ServiceConfigurationError e) { - // "uses" not declared: load bundle local in the module - return null; - } - } - return null; } /** @@ -1914,6 +1986,7 @@ cacheKey.callerHasProvider = Boolean.TRUE; } ResourceBundle bundle = provider.getBundle(baseName, locale); + trace("provider %s %s locale: %s bundle: %s%n", provider, baseName, locale, bundle); if (bundle != null) { return bundle; } @@ -3016,6 +3089,14 @@ * indicates that this method is being called because the previously * loaded resource bundle has expired. * + * @implSpec + * + * Resource bundles in named modules are subject to the encapsulation + * rules specified by {@link Module#getResourceAsStream Module.getResourceAsStream}. + * A resource bundle in a named module visible to the given class loader + * is accessible when the package of the resource file corresponding + * to the resource bundle is open unconditionally. + * *

        The default implementation instantiates a * ResourceBundle as follows. * @@ -3026,12 +3107,15 @@ * locale)}. * *

      • If format is "java.class", the - * {@link Class} specified by the bundle name is loaded by calling - * {@link ClassLoader#loadClass(String)}. Then, a - * ResourceBundle is instantiated by calling {@link - * Class#newInstance()}. Note that the reload flag is - * ignored for loading class-based resource bundles in this default - * implementation.
      • + * {@link Class} specified by the bundle name is loaded with the + * given class loader. If the {@code Class} is found and accessible + * then the ResourceBundle is instantiated. The + * resource bundle is accessible if the package of the bundle class file + * is open unconditionally; otherwise, {@code IllegalAccessException} + * will be thrown. + * Note that the reload flag is ignored for loading + * class-based resource bundles in this default implementation. + * * *
      • If format is "java.properties", * {@link #toResourceName(String, String) toResourceName(bundlename, @@ -3105,7 +3189,6 @@ /* * Legacy mechanism to locate resource bundle in unnamed module only * that is visible to the given loader and accessible to the given caller. - * This only finds resources on the class path but not in named modules. */ String bundleName = toBundleName(baseName, locale); ResourceBundle bundle = null; @@ -3117,18 +3200,15 @@ if (ResourceBundle.class.isAssignableFrom(c)) { @SuppressWarnings("unchecked") Class bundleClass = (Class)c; + Module m = bundleClass.getModule(); - // This doesn't allow unnamed modules to find bundles in - // named modules other than via the service loader mechanism. - // Otherwise, this will make the newBundle method to be - // caller-sensitive in order to verify access check. - // So migrating resource bundles to named module can't - // just export the package (in general, legacy resource - // bundles have split package if they are packaged separate - // from the consumer.) - if (bundleClass.getModule().isNamed()) { - throw new IllegalAccessException("unnamed modules can't load " + bundleName - + " in named module " + bundleClass.getModule().getName()); + // To access a resource bundle in a named module, + // either class-based or properties-based, the resource + // bundle must be opened unconditionally, + // same rule as accessing a resource file. + if (m.isNamed() && !m.isOpen(bundleClass.getPackageName())) { + throw new IllegalAccessException("unnamed module can't load " + + bundleClass.getName() + " in " + m.toString()); } try { // bundle in a unnamed module @@ -3502,4 +3582,173 @@ return null; } } + + private static class ResourceBundleProviderHelper { + /** + * Returns a new ResourceBundle instance of the given bundleClass + */ + static ResourceBundle newResourceBundle(Class bundleClass) { + try { + @SuppressWarnings("unchecked") + Constructor ctor = + bundleClass.getConstructor(); + if (!Modifier.isPublic(ctor.getModifiers())) { + return null; + } + // java.base may not be able to read the bundleClass's module. + PrivilegedAction pa = () -> { ctor.setAccessible(true); return null;}; + AccessController.doPrivileged(pa); + try { + return ctor.newInstance((Object[]) null); + } catch (InvocationTargetException e) { + uncheckedThrow(e); + } catch (InstantiationException | IllegalAccessException e) { + throw new InternalError(e); + } + } catch (NoSuchMethodException e) { + throw new InternalError(e); + } + return null; + } + + /** + * Loads a {@code ResourceBundle} of the given {@code bundleName} local to + * the given {@code module}. If not found, search the bundle class + * that is visible from the module's class loader. + * + * The caller module is used for access check only. + */ + static ResourceBundle loadResourceBundle(Module callerModule, + Module module, + String baseName, + Locale locale) + { + String bundleName = Control.INSTANCE.toBundleName(baseName, locale); + try { + PrivilegedAction> pa = () -> Class.forName(module, bundleName); + Class c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION); + trace("local in %s %s caller %s: %s%n", module, bundleName, callerModule, c); + + if (c == null) { + // if not found from the given module, locate resource bundle + // that is visible to the module's class loader + ClassLoader loader = getLoader(module); + if (loader != null) { + c = Class.forName(bundleName, false, loader); + } else { + c = BootLoader.loadClassOrNull(bundleName); + } + trace("loader for %s %s caller %s: %s%n", module, bundleName, callerModule, c); + } + + if (c != null && ResourceBundle.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class bundleClass = (Class) c; + Module m = bundleClass.getModule(); + if (!isAccessible(callerModule, m, bundleClass.getPackageName())) { + trace(" %s does not have access to %s/%s%n", callerModule, + m.getName(), bundleClass.getPackageName()); + return null; + } + + return newResourceBundle(bundleClass); + } + } catch (ClassNotFoundException e) {} + return null; + } + + /** + * Tests if resources of the given package name from the given module are + * open to the caller module. + */ + static boolean isAccessible(Module callerModule, Module module, String pn) { + if (!module.isNamed() || callerModule == module) + return true; + + return module.isOpen(pn, callerModule); + } + + /** + * Loads properties of the given {@code bundleName} local in the given + * {@code module}. If the .properties is not found or not open + * to the caller module to access, it will find the resource that + * is visible to the module's class loader. + * + * The caller module is used for access check only. + */ + static ResourceBundle loadPropertyResourceBundle(Module callerModule, + Module module, + String baseName, + Locale locale) + throws IOException + { + String bundleName = Control.INSTANCE.toBundleName(baseName, locale); + + PrivilegedAction pa = () -> { + try { + String resourceName = Control.INSTANCE + .toResourceName0(bundleName, "properties"); + if (resourceName == null) { + return null; + } + trace("local in %s %s caller %s%n", module, resourceName, callerModule); + + // if the package is in the given module but not opened + // locate it from the given module first. + String pn = toPackageName(bundleName); + trace(" %s/%s is accessible to %s : %s%n", + module.getName(), pn, callerModule, + isAccessible(callerModule, module, pn)); + if (isAccessible(callerModule, module, pn)) { + InputStream in = module.getResourceAsStream(resourceName); + if (in != null) { + return in; + } + } + + ClassLoader loader = module.getClassLoader(); + trace("loader for %s %s caller %s%n", module, resourceName, callerModule); + + try { + if (loader != null) { + return loader.getResourceAsStream(resourceName); + } else { + URL url = BootLoader.findResource(resourceName); + if (url != null) { + return url.openStream(); + } + } + } catch (Exception e) {} + return null; + + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + + try (InputStream stream = AccessController.doPrivileged(pa)) { + if (stream != null) { + return new PropertyResourceBundle(stream); + } else { + return null; + } + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + private static String toPackageName(String bundleName) { + int i = bundleName.lastIndexOf('.'); + return i != -1 ? bundleName.substring(0, i) : ""; + } + + } + + private static final boolean TRACE_ON = Boolean.valueOf( + GetPropertyAction.privilegedGetProperty("resource.bundle.debug", "false")); + + private static void trace(String format, Object... params) { + if (TRACE_ON) + System.out.format(format, params); + } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/util/ServiceLoader.java --- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,23 +32,28 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Layer; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Module; import java.net.URL; import java.net.URLConnection; +import java.security.AccessControlContext; import java.security.AccessController; -import java.security.AccessControlContext; import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import jdk.internal.loader.BootLoader; -import jdk.internal.loader.Loader; -import jdk.internal.loader.LoaderPool; import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.JavaLangReflectModuleAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.VM; import jdk.internal.module.ServicesCatalog; import jdk.internal.module.ServicesCatalog.ServiceProvider; - import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -76,21 +81,49 @@ * request together with code that can create the actual provider on demand. * The details of provider classes tend to be highly service-specific; no * single class or interface could possibly unify them, so no such type is - * defined here. A requirement enforced by this facility is that each provider - * class must have a {@code public} zero-argument constructor. + * defined here. + * + *

        Providers deployed as explicit modules on the module path are + * instantiated by a provider factory or directly via the provider's + * constructor. In the module declaration then the class name specified in the + * provides clause is a provider factory if it is public and defines a + * public static no-args method named "{@code provider}". The return type of + * the method must be assignable to the service type. If the class is + * not a provider factory then it is public with a public zero-argument + * constructor. The requirement that the provider factory or provider class + * be public helps to document the intent that the provider will be + * instantiated by the service-provider loading facility. + * + *

        As an example, suppose a module declares the following: + * + *

        {@code
        + *     provides com.example.CodecSet with com.example.impl.StandardCodecs;
        + *     provides com.example.CodecSet with com.example.impl.ExtendedCodecsFactory;
        + * }
        + * + *

        where {@code com.example.CodecSet} is the service type, {@code + * com.example.impl.StandardCodecs} is a provider class that is public with a + * public no-args constructor, {@code com.example.impl.ExtendedCodecsFactory} + * is a public class that defines a public static no-args method named + * "{@code provider}" with a return type that is {@code CodecSet} or a subtype + * of. For this example then {@code StandardCodecs}'s no-arg constructor will + * be used to instantiate {@code StandardCodecs}. {@code ExtendedCodecsFactory} + * will be treated as a provider factory and {@code + * ExtendedCodecsFactory.provider()} will be invoked to obtain the provider. + * + *

        Providers deployed on the class path or as {@link + * java.lang.module.ModuleDescriptor#isAutomatic automatic-modules} on the + * module path must have a public zero-argument constructor. * *

        An application or library using this loading facility and developed - * and deployed as a named module must have an appropriate uses clause - * in its module descriptor to declare that the module uses + * and deployed as an explicit module must have an appropriate uses + * clause in its module descriptor to declare that the module uses * implementations of the service. A corresponding requirement is that a * provider deployed as a named module must have an appropriate * provides clause in its module descriptor to declare that the module * provides an implementation of the service. The uses and - * provides allow consumers of a service to be linked to - * providers of the service. In the case of {@code load} methods that locate - * service providers using a class loader, then provider modules defined to - * that class loader, or a class loader reachable using {@link - * ClassLoader#getParent() parent} delegation, will be located. + * provides allow consumers of a service to be linked to modules + * containing providers of the service. * *

        A service provider that is packaged as a JAR file for the class path is * identified by placing a provider-configuration file in the resource @@ -114,27 +147,116 @@ * *

        Providers are located and instantiated lazily, that is, on demand. A * service loader maintains a cache of the providers that have been loaded so - * far. Each invocation of the {@link #iterator iterator} method returns an - * iterator that first yields all of the elements of the cache, in - * instantiation order, and then lazily locates and instantiates any remaining - * providers, adding each one to the cache in turn. The cache can be cleared + * far. Each invocation of the {@link #iterator iterator} method returns an + * iterator that first yields all of the elements cached from previous + * iteration, in instantiation order, and then lazily locates and instantiates + * any remaining providers, adding each one to the cache in turn. Similarly, + * each invocation of the {@link #stream stream} method returns a stream that + * first processes all providers loaded by previous stream operations, in load + * order, and then lazily locates any remaining providers. Caches are cleared * via the {@link #reload reload} method. * + *

        Locating providers

        + * + *

        The {@code load} methods locate providers using a class loader or module + * {@link Layer layer}. When locating providers using a class loader then + * providers in both named and unnamed modules may be located. When locating + * providers using a module layer then only providers in named modules in + * the layer (or parent layers) are located. + * + *

        When locating providers using a class loader then any providers in named + * modules defined to the class loader, or any class loader that is reachable + * via parent delegation, are located. Additionally, providers in module layers + * other than the {@link Layer#boot() boot} layer, where the module layer + * contains modules defined to the class loader, or any class loader reachable + * via parent delegation, are also located. For example, suppose there is a + * module layer where each module is defined to its own class loader (see {@link + * Layer#defineModulesWithManyLoaders defineModulesWithManyLoaders}). If the + * {@code load} method is invoked to locate providers using any of these class + * loaders for this layer then it will locate all of the providers in that + * layer, irrespective of their defining class loader. + * + *

        In the case of unnamed modules then the service configuration files are + * located using the class loader's {@link ClassLoader#getResources(String) + * ClassLoader.getResources(String)} method. Any providers listed should be + * visible via the class loader specified to the {@code load} method. If a + * provider in a named module is listed then it is ignored - this is to avoid + * duplicates that would otherwise arise when a module has both a + * provides clause and a service configuration file in {@code + * META-INF/services} that lists the same provider. + * + *

        Ordering

        + * + *

        Service loaders created to locate providers using a {@code ClassLoader} + * locate providers as follows: + *

          + *
        • Providers in named modules are located before providers on the + * class path (or more generally, unnamed modules).
        • + * + *
        • When locating providers in named modules then the service loader + * will locate providers in modules defined to the class loader, then its + * parent class loader, its parent parent, and so on to the bootstrap class + * loader. If a {@code ClassLoader}, or any class loader in the parent + * delegation chain, defines modules in a custom module {@link Layer} then + * all providers in that layer are located, irrespective of their class + * loader. The ordering of modules defined to the same class loader, or the + * ordering of modules in a layer, is not defined.
        • + * + *
        • If a named module declares more than one provider then the providers + * are located in the order that they appear in the {@code provides} table of + * the {@code Module} class file attribute ({@code module-info.class}).
        • + * + *
        • When locating providers in unnamed modules then the ordering is + * based on the order that the class loader's {@link + * ClassLoader#getResources(String) ClassLoader.getResources(String)} + * method finds the service configuration files.
        • + *
        + * + *

        Service loaders created to locate providers in a module {@link Layer} + * will first locate providers in the layer, before locating providers in + * parent layers. Traversal of parent layers is depth-first with each layer + * visited at most once. For example, suppose L0 is the boot layer, L1 and + * L2 are custom layers with L0 as their parent. Now suppose that L3 is + * created with L1 and L2 as the parents (in that order). Using a service + * loader to locate providers with L3 as the content will locate providers + * in the following order: L3, L1, L0, L2. The ordering of modules in a layer + * is not defined. + * + *

        Selection and filtering

        + * + *

        Selecting a provider or filtering providers will usually involve invoking + * a provider method. Where selection or filtering based on the provider class is + * needed then it can be done using a {@link #stream() stream}. For example, the + * following collects the providers that have a specific annotation: + *

        {@code
        + *     Set providers = ServiceLoader.load(CodecSet.class)
        + *            .stream()
        + *            .filter(p -> p.type().isAnnotationPresent(Managed.class))
        + *            .map(Provider::get)
        + *            .collect(Collectors.toSet());
        + * }
        + * + *

        Security

        + * *

        Service loaders always execute in the security context of the caller - * of the iterator methods and may also be restricted by the security + * of the iterator or stream methods and may also be restricted by the security * context of the caller that created the service loader. * Trusted system code should typically invoke the methods in this class, and * the methods of the iterators which they return, from within a privileged * security context. * + *

        Concurrency

        + * *

        Instances of this class are not safe for use by multiple concurrent * threads. * - *

        Unless otherwise specified, passing a null argument to any + *

        Null handling

        + * + *

        Unless otherwise specified, passing a {@code null} argument to any * method in this class will cause a {@link NullPointerException} to be thrown. * - *

        Example - * Suppose we have a service type com.example.CodecSet which is + *

        Example

        + *

        Suppose we have a service type com.example.CodecSet which is * intended to represent sets of encoder/decoder pairs for some protocol. In * this case it is an abstract class with two abstract methods: * @@ -218,11 +340,12 @@ public final class ServiceLoader implements Iterable { - private static final String PREFIX = "META-INF/services/"; - // The class or interface representing the service being loaded private final Class service; + // The class of the service type + private final String serviceName; + // The module Layer used to locate providers; null when locating // providers using a class loader private final Layer layer; @@ -234,75 +357,86 @@ // The access control context taken when the ServiceLoader is created private final AccessControlContext acc; - // Cached providers, in instantiation order - private List providers = new ArrayList<>(); + // The lazy-lookup iterator for iterator operations + private Iterator> lookupIterator1; + private final List instantiatedProviders = new ArrayList<>(); - // The class names of the cached providers, only used when locating - // service providers via a class loader - private Set providerNames = new HashSet<>(); + // The lazy-lookup iterator for stream operations + private Iterator> lookupIterator2; + private final List> loadedProviders = new ArrayList<>(); + private boolean loadedAllProviders; // true when all providers loaded // Incremented when reload is called private int reloadCount; - // the service iterator when locating services via a module layer - private LayerLookupIterator layerLookupIterator; - - // The module services iterator when locating services in modules - // defined to a class loader - private ModuleServicesIterator moduleServicesIterator; - - // The current lazy-lookup iterator for locating legacy provider on the - // class path via a class loader - private LazyClassPathIterator lazyClassPathIterator; - + private static JavaLangAccess LANG_ACCESS; + private static JavaLangReflectModuleAccess JLRM_ACCESS; + static { + LANG_ACCESS = SharedSecrets.getJavaLangAccess(); + JLRM_ACCESS = SharedSecrets.getJavaLangReflectModuleAccess(); + } /** - * Clear this loader's provider cache so that all providers will be - * reloaded. + * Represents a service provider located by {@code ServiceLoader}. + * + *

        When using a loader's {@link ServiceLoader#stream() stream()} method + * then the elements are of type {@code Provider}. This allows processing + * to select or filter on the provider class without instantiating the + * provider.

        * - *

        After invoking this method, subsequent invocations of the {@link - * #iterator() iterator} method will lazily look up and instantiate - * providers from scratch, just as is done by a newly-created loader. - * - *

        This method is intended for use in situations in which new providers - * can be installed into a running Java virtual machine. + * @param The service type + * @since 9 */ - public void reload() { - providers.clear(); + public static interface Provider extends Supplier { + /** + * Returns the provider type. There is no guarantee that this type is + * accessible or that it has a public no-args constructor. The {@link + * #get() get()} method should be used to obtain the provider instance. + * + *

        When a module declares that the provider class is created by a + * provider factory then this method returns the return type of its + * public static "{@code provider()}" method. + * + * @return The provider type + */ + Class type(); - assert layer == null || loader == null; - if (layer != null) { - layerLookupIterator = new LayerLookupIterator(); - } else { - providerNames.clear(); - moduleServicesIterator = new ModuleServicesIterator(); - lazyClassPathIterator = new LazyClassPathIterator(); - } - - reloadCount++; + /** + * Returns an instance of the provider. + * + * @return An instance of the provider. + * + * @throws ServiceConfigurationError + * If the service provider cannot be instantiated, or in the + * case of a provider factory, the public static + * "{@code provider()}" method returns {@code null} or throws + * an error or exception. The {@code ServiceConfigurationError} + * will carry an appropriate cause where possible. + */ + @Override S get(); } - /** * Initializes a new instance of this class for locating service providers * in a module Layer. * * @throws ServiceConfigurationError - * If {@code svc} is not accessible to {@code caller} or that the - * caller's module does not declare that it uses the service type. + * If {@code svc} is not accessible to {@code caller} or the caller + * module does not use the service type. */ private ServiceLoader(Class caller, Layer layer, Class svc) { - - checkModule(caller.getModule(), svc); + Objects.requireNonNull(caller); + Objects.requireNonNull(layer); + Objects.requireNonNull(svc); + checkCaller(caller, svc); this.service = svc; + this.serviceName = svc.getName(); this.layer = layer; this.loader = null; this.acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; - - reload(); } /** @@ -310,23 +444,23 @@ * via a class loader. * * @throws ServiceConfigurationError - * If {@code svc} is not accessible to {@code caller} or that the - * caller's module does not declare that it uses the service type. + * If {@code svc} is not accessible to {@code caller} or the caller + * module does not use the service type. */ - private ServiceLoader(Module callerModule, Class svc, ClassLoader cl) { - if (VM.isBooted()) { + private ServiceLoader(Class caller, Class svc, ClassLoader cl) { + Objects.requireNonNull(svc); - checkModule(callerModule, svc); - + if (VM.isBooted()) { + checkCaller(caller, svc); if (cl == null) { cl = ClassLoader.getSystemClassLoader(); } - } else { // if we get here then it means that ServiceLoader is being used // before the VM initialization has completed. At this point then // only code in the java.base should be executing. + Module callerModule = caller.getModule(); Module base = Object.class.getModule(); Module svcModule = svc.getModule(); if (callerModule != base || svcModule != base) { @@ -338,39 +472,55 @@ } this.service = svc; + this.serviceName = svc.getName(); this.layer = null; this.loader = cl; this.acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; - - reload(); } - private ServiceLoader(Class caller, Class svc, ClassLoader cl) { - this(caller.getModule(), svc, cl); + /** + * Initializes a new instance of this class for locating service providers + * via a class loader. + * + * @apiNote For use by ResourceBundle + * + * @throws ServiceConfigurationError + * If the caller module does not use the service type. + */ + private ServiceLoader(Module callerModule, Class svc, ClassLoader cl) { + if (!callerModule.canUse(svc)) { + fail(svc, callerModule + " does not declare `uses`"); + } + + this.service = Objects.requireNonNull(svc); + this.serviceName = svc.getName(); + this.layer = null; + this.loader = cl; + this.acc = (System.getSecurityManager() != null) + ? AccessController.getContext() + : null; } - - /** * Checks that the given service type is accessible to types in the given - * module, and check that the module declare that it uses the service type. + * module, and check that the module declare that it uses the service type. ?? */ - private static void checkModule(Module module, Class svc) { + private static void checkCaller(Class caller, Class svc) { + Module callerModule = caller.getModule(); - // Check that the service type is in a package that is - // exported to the caller. - if (!Reflection.verifyModuleAccess(module, svc)) { - fail(svc, "not accessible to " + module); + // Check access to the service type + int mods = svc.getModifiers(); + if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) { + fail(svc, "service type not accessible to " + callerModule); } // If the caller is in a named module then it should "uses" the // service type - if (!module.canUse(svc)) { - fail(svc, "use not declared in " + module); + if (!callerModule.canUse(svc)) { + fail(svc, callerModule + " does not declare `uses`"); } - } private static void fail(Class service, String msg, Throwable cause) @@ -392,310 +542,422 @@ fail(service, u + ":" + line + ": " + msg); } - // Parse a single line from the given configuration file, adding the name - // on the line to the names list. - // - private int parseLine(Class service, URL u, BufferedReader r, int lc, - List names) - throws IOException, ServiceConfigurationError - { - String ln = r.readLine(); - if (ln == null) { - return -1; - } - int ci = ln.indexOf('#'); - if (ci >= 0) ln = ln.substring(0, ci); - ln = ln.trim(); - int n = ln.length(); - if (n != 0) { - if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) - fail(service, u, lc, "Illegal configuration-file syntax"); - int cp = ln.codePointAt(0); - if (!Character.isJavaIdentifierStart(cp)) - fail(service, u, lc, "Illegal provider-class name: " + ln); - for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { - cp = ln.codePointAt(i); - if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) - fail(service, u, lc, "Illegal provider-class name: " + ln); - } - if (!providerNames.contains(ln) && !names.contains(ln)) - names.add(ln); - } - return lc + 1; - } - /** - * Parse the content of the given URL as a provider-configuration file. - * - * @param service - * The service type for which providers are being sought; - * used to construct error detail strings - * - * @param u - * The URL naming the configuration file to be parsed - * - * @return A (possibly empty) iterator that will yield the provider-class - * names in the given configuration file that are not yet members - * of the returned set + * Uses Class.forName to load a provider class in a module. * * @throws ServiceConfigurationError - * If an I/O error occurs while reading from the given URL, or - * if a configuration-file format error is detected - * + * If the class cannot be loaded */ - private Iterator parse(Class service, URL u) - throws ServiceConfigurationError - { - ArrayList names = new ArrayList<>(); - try { - URLConnection uc = u.openConnection(); - uc.setUseCaches(false); - try (InputStream in = uc.getInputStream(); - BufferedReader r - = new BufferedReader(new InputStreamReader(in, "utf-8"))) - { - int lc = 1; - while ((lc = parseLine(service, u, r, lc, names)) >= 0); + private Class loadProviderInModule(Module module, String cn) { + Class clazz = null; + if (acc == null) { + try { + clazz = Class.forName(module, cn); + } catch (LinkageError e) { + fail(service, "Unable to load " + cn, e); } - } catch (IOException x) { - fail(service, "Error accessing configuration file", x); + } else { + PrivilegedExceptionAction> pa = () -> Class.forName(module, cn); + try { + clazz = AccessController.doPrivileged(pa); + } catch (PrivilegedActionException pae) { + Throwable x = pae.getCause(); + fail(service, "Unable to load " + cn, x); + return null; + } } - return names.iterator(); + if (clazz == null) + fail(service, "Provider " + cn + " not found"); + return clazz; } /** - * Returns the {@code Constructor} to instantiate the service provider. - * The constructor has its accessible flag set so that the access check - * is suppressed when instantiating the provider. This is necessary - * because newInstance is a caller sensitive method and ServiceLoader - * is instantiating the service provider on behalf of the service - * consumer. + * A Provider implementation that supports invoking, with reduced + * permissions, the static factory to obtain the provider or the + * provider's no-arg constructor. */ - private static Constructor checkAndGetConstructor(Class c) - throws NoSuchMethodException, IllegalAccessException - { - Constructor ctor = c.getConstructor(); + private final static class ProviderImpl implements Provider { + final Class service; + final AccessControlContext acc; + + final Method factoryMethod; // factory method or null + final Class type; + final Constructor ctor; // public no-args constructor or null + + /** + * Creates a Provider. + * + * @param service + * The service type + * @param clazz + * The provider (or provider factory) class + * @param acc + * The access control context when running with security manager + * + * @throws ServiceConfigurationError + * If the class is not public; If the class defines a public + * static provider() method with a return type that is assignable + * to the service type or the class is not a provider class with + * a public no-args constructor. + */ + @SuppressWarnings("unchecked") + ProviderImpl(Class service, Class clazz, AccessControlContext acc) { + this.service = (Class) service; + this.acc = acc; - // check class and no-arg constructor are public - int modifiers = ctor.getModifiers(); - if (!Modifier.isPublic(Reflection.getClassAccessFlags(c) & modifiers)) { - String cn = c.getName(); - throw new IllegalAccessException(cn + " is not public"); + int mods = clazz.getModifiers(); + if (!Modifier.isPublic(mods)) { + fail(service, clazz + " is not public"); + } + + // if the class is in an explicit module then see if it is + // a provider factory class + Method factoryMethod = null; + if (inExplicitModule(clazz)) { + factoryMethod = findStaticProviderMethod(clazz); + if (factoryMethod != null) { + Class returnType = factoryMethod.getReturnType(); + if (!service.isAssignableFrom(returnType)) { + fail(service, factoryMethod + " return type not a subtype"); + } + } + } + this.factoryMethod = factoryMethod; + + if (factoryMethod == null) { + // no factory method so must have a public no-args constructor + if (!service.isAssignableFrom(clazz)) { + fail(service, clazz.getName() + " not a subtype"); + } + this.type = (Class) clazz; + this.ctor = (Constructor) getConstructor(clazz); + } else { + this.type = (Class) factoryMethod.getReturnType(); + this.ctor = null; + } } - // return Constructor to create the service implementation - PrivilegedAction action = new PrivilegedAction() { - public Void run() { ctor.setAccessible(true); return null; } - }; - AccessController.doPrivileged(action); - return ctor; - } - - /** - * Uses Class.forName to load a class in a module. - */ - private static Class loadClassInModule(Module module, String cn) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - return Class.forName(module, cn); - } else { - PrivilegedAction> pa = () -> Class.forName(module, cn); - return AccessController.doPrivileged(pa); + @Override + public Class type() { + return type; } - } - /** - * An Iterator that runs the next and hasNext methods with permissions - * restricted by the {@code AccessControlContext} obtained when the - * ServiceLoader was created. - */ - private abstract class RestrictedIterator - implements Iterator - { - /** - * Returns {@code true} if the iteration has more elements. - */ - abstract boolean hasNextService(); - - /** - * Returns the next element in the iteration - */ - abstract S nextService(); - - public final boolean hasNext() { - if (acc == null) { - return hasNextService(); + @Override + public S get() { + if (factoryMethod != null) { + return invokeFactoryMethod(); } else { - PrivilegedAction action = new PrivilegedAction() { - public Boolean run() { return hasNextService(); } - }; - return AccessController.doPrivileged(action, acc); + return newInstance(); } } - public final S next() { + /** + * Returns {@code true} if the provider is in an explicit module + */ + private boolean inExplicitModule(Class clazz) { + Module module = clazz.getModule(); + return module.isNamed() && !module.getDescriptor().isAutomatic(); + } + + /** + * Returns the public static provider method if found. + * + * @throws ServiceConfigurationError if there is an error finding the + * provider method + */ + private Method findStaticProviderMethod(Class clazz) { + Method method = null; + try { + method = LANG_ACCESS.getMethodOrNull(clazz, "provider"); + } catch (Throwable x) { + fail(service, "Unable to get public provider() method", x); + } + if (method != null) { + int mods = method.getModifiers(); + if (Modifier.isStatic(mods)) { + assert Modifier.isPublic(mods); + Method m = method; + PrivilegedAction pa = () -> { + m.setAccessible(true); + return null; + }; + AccessController.doPrivileged(pa); + return method; + } + } + return null; + } + + /** + * Returns the public no-arg constructor of a class. + * + * @throws ServiceConfigurationError if the class does not have + * public no-arg constructor + */ + private Constructor getConstructor(Class clazz) { + PrivilegedExceptionAction> pa + = new PrivilegedExceptionAction<>() { + @Override + public Constructor run() throws Exception { + Constructor ctor = clazz.getConstructor(); + if (inExplicitModule(clazz)) + ctor.setAccessible(true); + return ctor; + } + }; + Constructor ctor = null; + try { + ctor = AccessController.doPrivileged(pa); + } catch (Throwable x) { + if (x instanceof PrivilegedActionException) + x = x.getCause(); + String cn = clazz.getName(); + fail(service, cn + " Unable to get public no-arg constructor", x); + } + return ctor; + } + + /** + * Invokes the provider's "provider" method to instantiate a provider. + * When running with a security manager then the method runs with + * permissions that are restricted by the security context of whatever + * created this loader. + */ + private S invokeFactoryMethod() { + Object result = null; + Throwable exc = null; if (acc == null) { - return nextService(); + try { + result = factoryMethod.invoke(null); + } catch (Throwable x) { + exc = x; + } } else { - PrivilegedAction action = new PrivilegedAction() { - public S run() { return nextService(); } + PrivilegedExceptionAction pa = new PrivilegedExceptionAction<>() { + @Override + public Object run() throws Exception { + return factoryMethod.invoke(null); + } }; - return AccessController.doPrivileged(action, acc); + // invoke factory method with permissions restricted by acc + try { + result = AccessController.doPrivileged(pa, acc); + } catch (PrivilegedActionException pae) { + exc = pae.getCause(); + } + } + if (exc != null) { + if (exc instanceof InvocationTargetException) + exc = exc.getCause(); + fail(service, factoryMethod + " failed", exc); + } + if (result == null) { + fail(service, factoryMethod + " returned null"); } + @SuppressWarnings("unchecked") + S p = (S) result; + return p; + } + + /** + * Invokes Constructor::newInstance to instantiate a provider. When running + * with a security manager then the constructor runs with permissions that + * are restricted by the security context of whatever created this loader. + */ + private S newInstance() { + S p = null; + Throwable exc = null; + if (acc == null) { + try { + p = ctor.newInstance(); + } catch (Throwable x) { + exc = x; + } + } else { + PrivilegedExceptionAction pa = new PrivilegedExceptionAction<>() { + @Override + public S run() throws Exception { + return ctor.newInstance(); + } + }; + // invoke constructor with permissions restricted by acc + try { + p = AccessController.doPrivileged(pa, acc); + } catch (PrivilegedActionException pae) { + exc = pae.getCause(); + } + } + if (exc != null) { + if (exc instanceof InvocationTargetException) + exc = exc.getCause(); + String cn = ctor.getDeclaringClass().getName(); + fail(service, + "Provider " + cn + " could not be instantiated", exc); + } + return p; + } + + // For now, equals/hashCode uses the access control context to ensure + // that two Providers created with different contexts are not equal + // when running with a security manager. + + @Override + public int hashCode() { + return Objects.hash(type, acc); + } + + @Override + public boolean equals(Object ob) { + if (!(ob instanceof ProviderImpl)) + return false; + @SuppressWarnings("unchecked") + ProviderImpl that = (ProviderImpl)ob; + return this.type == that.type + && Objects.equals(this.acc, that.acc); } } /** * Implements lazy service provider lookup of service providers that - * are provided by modules in a module Layer. + * are provided by modules in a module Layer (or parent layers) */ - private class LayerLookupIterator - extends RestrictedIterator + private final class LayerLookupIterator + implements Iterator> { - final String serviceName; - Layer currentLayer; + Deque stack = new ArrayDeque<>(); + Set visited = new HashSet<>(); Iterator iterator; - ServiceProvider nextProvider; + ServiceProvider next; // next provider to load LayerLookupIterator() { - serviceName = service.getName(); - currentLayer = layer; - - // need to get us started - iterator = providers(currentLayer, serviceName); + visited.add(layer); + stack.push(layer); } - Iterator providers(Layer layer, String service) { - ServicesCatalog catalog = SharedSecrets - .getJavaLangReflectModuleAccess() - .getServicesCatalog(layer); - + private Iterator providers(Layer layer) { + ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer); return catalog.findServices(serviceName).iterator(); } @Override - boolean hasNextService() { - + public boolean hasNext() { // already have the next provider cached - if (nextProvider != null) + if (next != null) return true; while (true) { - // next provider + // next provider (or provider factory) if (iterator != null && iterator.hasNext()) { - nextProvider = iterator.next(); + next = iterator.next(); return true; } - // next layer - Layer parent = currentLayer.parent().orElse(null); - if (parent == null) + // next layer (DFS order) + if (stack.isEmpty()) return false; - currentLayer = parent; - iterator = providers(currentLayer, serviceName); + Layer layer = stack.pop(); + List parents = layer.parents(); + for (int i = parents.size() - 1; i >= 0; i--) { + Layer parent = parents.get(i); + if (!visited.contains(parent)) { + visited.add(parent); + stack.push(parent); + } + } + iterator = providers(layer); } } @Override - S nextService() { - if (!hasNextService()) + public Provider next() { + if (!hasNext()) throw new NoSuchElementException(); - ServiceProvider provider = nextProvider; - nextProvider = null; + // take next provider + ServiceProvider provider = next; + next = null; + // attempt to load provider Module module = provider.module(); String cn = provider.providerName(); - - // attempt to load the provider - Class c = loadClassInModule(module, cn); - if (c == null) - fail(service, "Provider " + cn + " not found"); - if (!service.isAssignableFrom(c)) - fail(service, "Provider " + cn + " not a subtype"); - - // instantiate the provider - S p = null; - try { - Constructor ctor = checkAndGetConstructor(c); - p = service.cast(ctor.newInstance()); - } catch (Throwable x) { - if (x instanceof InvocationTargetException) - x = x.getCause(); - fail(service, - "Provider " + cn + " could not be instantiated", x); - } - - // add to cached provider list - providers.add(p); - - return p; + Class clazz = loadProviderInModule(module, cn); + return new ProviderImpl(service, clazz, acc); } } /** * Implements lazy service provider lookup of service providers that - * are provided by modules defined to a class loader. + * are provided by modules defined to a class loader or to modules in + * layers with a module defined to the class loader. */ - private class ModuleServicesIterator - extends RestrictedIterator + private final class ModuleServicesLookupIterator + implements Iterator> { - final JavaLangAccess langAccess = SharedSecrets.getJavaLangAccess(); - ClassLoader currentLoader; Iterator iterator; - ServiceProvider nextProvider; + ServiceProvider next; // next provider to load - ModuleServicesIterator() { + ModuleServicesLookupIterator() { this.currentLoader = loader; this.iterator = iteratorFor(loader); } /** + * Returns iterator to iterate over the implementations of {@code + * service} in the given layer. + */ + private List providers(Layer layer) { + ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer); + return catalog.findServices(serviceName); + } + + /** * Returns an iterator to iterate over the implementations of {@code - * service} in modules defined to the given class loader. + * service} in modules defined to the given class loader or in custom + * layers with a module defined to this class loader. */ private Iterator iteratorFor(ClassLoader loader) { - // if the class loader is in a loader pool then return an Iterator - // that iterates over all service providers in the pool that provide - // an implementation of the service - if (currentLoader instanceof Loader) { - LoaderPool pool = ((Loader) loader).pool(); - if (pool != null) { - return pool.loaders() - .map(l -> langAccess.getServicesCatalog(l)) - .filter(sc -> sc != null) - .map(sc -> sc.findServices(service.getName())) - .flatMap(Set::stream) - .iterator(); - } + // modules defined to this class loader + ServicesCatalog catalog; + if (loader == null) { + catalog = BootLoader.getServicesCatalog(); + } else { + catalog = ServicesCatalog.getServicesCatalogOrNull(loader); + } + Stream stream1; + if (catalog == null) { + stream1 = Stream.empty(); + } else { + stream1 = catalog.findServices(serviceName).stream(); } - ServicesCatalog catalog; - if (currentLoader == null) { - catalog = BootLoader.getServicesCatalog(); + // modules in custom layers that define modules to the class loader + Stream stream2; + if (loader == null) { + stream2 = Stream.empty(); } else { - catalog = langAccess.getServicesCatalog(currentLoader); + Layer bootLayer = Layer.boot(); + stream2 = JLRM_ACCESS.layers(loader) + .filter(l -> (l != bootLayer)) + .map(l -> providers(l)) + .flatMap(List::stream); } - if (catalog == null) { - return Collections.emptyIterator(); - } else { - return catalog.findServices(service.getName()).iterator(); - } + + return Stream.concat(stream1, stream2).iterator(); } @Override - boolean hasNextService() { + public boolean hasNext() { // already have the next provider cached - if (nextProvider != null) + if (next != null) return true; while (true) { if (iterator.hasNext()) { - nextProvider = iterator.next(); + next = iterator.next(); return true; } @@ -710,138 +972,220 @@ } @Override - S nextService() { - if (!hasNextService()) + public Provider next() { + if (!hasNext()) throw new NoSuchElementException(); - ServiceProvider provider = nextProvider; - nextProvider = null; + // take next provider + ServiceProvider provider = next; + next = null; - // attempt to load the provider + // attempt to load provider Module module = provider.module(); String cn = provider.providerName(); - - Class c = loadClassInModule(module, cn); - if (c == null) { - fail(service, - "Provider " + cn + " not found in " + module.getName()); - } - if (!service.isAssignableFrom(c)) { - fail(service, "Provider " + cn + " not a subtype"); - } - - // instantiate the provider - S p = null; - try { - Constructor ctor = checkAndGetConstructor(c); - p = service.cast(ctor.newInstance()); - } catch (Throwable x) { - if (x instanceof InvocationTargetException) - x = x.getCause(); - fail(service, - "Provider " + cn + " could not be instantiated", x); - } - - // add to provider list - providers.add(p); - - // record the class name of the service provider, this is - // needed for cases where there a module has both a "uses" - // and a services configuration file listing the same - // provider - providerNames.add(cn); - - return p; + Class clazz = loadProviderInModule(module, cn); + return new ProviderImpl(service, clazz, acc); } } /** - * Implements lazy service provider lookup where the service providers - * are configured via service configuration files. + * Implements lazy service provider lookup where the service providers are + * configured via service configuration files. Service providers in named + * modules are silently ignored by this lookup iterator. */ - private class LazyClassPathIterator - extends RestrictedIterator + private final class LazyClassPathLookupIterator + implements Iterator> { + static final String PREFIX = "META-INF/services/"; + Enumeration configs; Iterator pending; - String nextName; + Class nextClass; + String nextErrorMessage; // when hasNext fails with CNFE + + LazyClassPathLookupIterator() { } - @Override - boolean hasNextService() { - if (nextName != null) { + /** + * Parse a single line from the given configuration file, adding the + * name on the line to the names list. + */ + private int parseLine(URL u, BufferedReader r, int lc, Set names) + throws IOException + { + String ln = r.readLine(); + if (ln == null) { + return -1; + } + int ci = ln.indexOf('#'); + if (ci >= 0) ln = ln.substring(0, ci); + ln = ln.trim(); + int n = ln.length(); + if (n != 0) { + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) + fail(service, u, lc, "Illegal configuration-file syntax"); + int cp = ln.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) + fail(service, u, lc, "Illegal provider-class name: " + ln); + int start = Character.charCount(cp); + for (int i = start; i < n; i += Character.charCount(cp)) { + cp = ln.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) + fail(service, u, lc, "Illegal provider-class name: " + ln); + } + names.add(ln); + } + return lc + 1; + } + + /** + * Parse the content of the given URL as a provider-configuration file. + */ + private Iterator parse(URL u) { + Set names = new LinkedHashSet<>(); // preserve insertion order + try { + URLConnection uc = u.openConnection(); + uc.setUseCaches(false); + try (InputStream in = uc.getInputStream(); + BufferedReader r + = new BufferedReader(new InputStreamReader(in, "utf-8"))) + { + int lc = 1; + while ((lc = parseLine(u, r, lc, names)) >= 0); + } + } catch (IOException x) { + fail(service, "Error accessing configuration file", x); + } + return names.iterator(); + } + + private boolean hasNextService() { + if (nextClass != null || nextErrorMessage != null) { return true; } - if (configs == null) { + + Class clazz = null; + do { + if (configs == null) { + try { + String fullName = PREFIX + service.getName(); + if (loader == null) + configs = ClassLoader.getSystemResources(fullName); + else + configs = loader.getResources(fullName); + } catch (IOException x) { + fail(service, "Error locating configuration files", x); + } + } + while ((pending == null) || !pending.hasNext()) { + if (!configs.hasMoreElements()) { + return false; + } + pending = parse(configs.nextElement()); + } + String cn = pending.next(); try { - String fullName = PREFIX + service.getName(); - if (loader == null) - configs = ClassLoader.getSystemResources(fullName); - else - configs = loader.getResources(fullName); - } catch (IOException x) { - fail(service, "Error locating configuration files", x); + clazz = Class.forName(cn, false, loader); + } catch (ClassNotFoundException x) { + // don't throw SCE here to long standing behavior + nextErrorMessage = "Provider " + cn + " not found"; + return true; } - } - while ((pending == null) || !pending.hasNext()) { - if (!configs.hasMoreElements()) { - return false; - } - pending = parse(service, configs.nextElement()); - } - nextName = pending.next(); + + } while (clazz.getModule().isNamed()); // ignore if in named module + + nextClass = clazz; return true; } - @Override - S nextService() { + private Provider nextService() { if (!hasNextService()) throw new NoSuchElementException(); - String cn = nextName; - nextName = null; - Class c = null; - try { - c = Class.forName(cn, false, loader); - } catch (ClassNotFoundException x) { - fail(service, - "Provider " + cn + " not found"); - } - if (!service.isAssignableFrom(c)) { - fail(service, - "Provider " + cn + " not a subtype"); + + // throw any SCE with error recorded by hasNext + if (nextErrorMessage != null) { + String msg = nextErrorMessage; + nextErrorMessage = null; + fail(service, msg); } - S p = null; - try { - @SuppressWarnings("deprecation") - Object tmp = c.newInstance(); - p = service.cast(tmp); - } catch (Throwable x) { - fail(service, - "Provider " + cn + " could not be instantiated", - x); + + // return next provider + Class clazz = nextClass; + nextClass = null; + return new ProviderImpl(service, clazz, acc); + } + + @Override + public boolean hasNext() { + if (acc == null) { + return hasNextService(); + } else { + PrivilegedAction action = new PrivilegedAction<>() { + public Boolean run() { return hasNextService(); } + }; + return AccessController.doPrivileged(action, acc); } - providers.add(p); - providerNames.add(cn); - return p; + } + + @Override + public Provider next() { + if (acc == null) { + return nextService(); + } else { + PrivilegedAction> action = new PrivilegedAction<>() { + public Provider run() { return nextService(); } + }; + return AccessController.doPrivileged(action, acc); + } } } /** - * Lazily loads the available providers of this loader's service. + * Returns a new lookup iterator. + */ + private Iterator> newLookupIterator() { + assert layer == null || loader == null; + if (layer != null) { + return new LayerLookupIterator<>(); + } else { + Iterator> first = new ModuleServicesLookupIterator<>(); + Iterator> second = new LazyClassPathLookupIterator<>(); + return new Iterator>() { + @Override + public boolean hasNext() { + return (first.hasNext() || second.hasNext()); + } + @Override + public Provider next() { + if (first.hasNext()) { + return first.next(); + } else if (second.hasNext()) { + return second.next(); + } else { + throw new NoSuchElementException(); + } + } + }; + } + } + + /** + * Lazily load and instantiate the available providers of this loader's + * service. * *

        The iterator returned by this method first yields all of the - * elements of the provider cache, in instantiation order. It then lazily - * loads and instantiates any remaining providers, adding each one to the - * cache in turn. + * elements of the provider cache, in the order that they were loaded. + * It then lazily loads and instantiates any remaining providers, + * adding each one to the cache in turn. * *

        To achieve laziness the actual work of locating and instantiating * providers must be done by the iterator itself. Its {@link * java.util.Iterator#hasNext hasNext} and {@link java.util.Iterator#next * next} methods can therefore throw a {@link ServiceConfigurationError} - * if a provider class cannot be loaded, doesn't have the appropriate - * constructor, can't be assigned to the service type or if any other kind - * of exception or error is thrown as the next provider is located and - * instantiated. To write robust code it is only necessary to catch {@link - * ServiceConfigurationError} when using a service iterator. + * if a provider class cannot be loaded, doesn't have an appropriate static + * factory method or constructor, can't be assigned to the service type or + * if any other kind of exception or error is thrown as the next provider + * is located and instantiated. To write robust code it is only necessary + * to catch {@link ServiceConfigurationError} when using a service iterator. * *

        If such an error is thrown then subsequent invocations of the * iterator will make a best effort to locate and instantiate the next @@ -856,7 +1200,7 @@ * preferable to throw an error rather than try to recover or, even worse, * fail silently. * - *

        If this loader's provider cache is cleared by invoking the {@link + *

        If this loader's provider caches are cleared by invoking the {@link * #reload() reload} method then existing iterators for this service * loader should be discarded. * The {@link java.util.Iterator#hasNext() hasNext} and {@link @@ -868,16 +1212,16 @@ * Invoking its {@link java.util.Iterator#remove() remove} method will * cause an {@link UnsupportedOperationException} to be thrown. * - * @implNote When adding providers to the cache, the {@link #iterator - * Iterator} processes resources in the order that the {@link - * java.lang.ClassLoader#getResources(java.lang.String) - * ClassLoader.getResources(String)} method finds the service configuration - * files. - * * @return An iterator that lazily loads providers for this loader's * service */ public Iterator iterator() { + + // create lookup iterator if needed + if (lookupIterator1 == null) { + lookupIterator1 = newLookupIterator(); + } + return new Iterator() { // record reload count @@ -895,34 +1239,23 @@ throw new ConcurrentModificationException(); } + @Override public boolean hasNext() { checkReloadCount(); - if (index < providers.size()) + if (index < instantiatedProviders.size()) return true; - - if (layerLookupIterator != null) { - return layerLookupIterator.hasNext(); - } else { - return moduleServicesIterator.hasNext() || - lazyClassPathIterator.hasNext(); - } + return lookupIterator1.hasNext(); } + @Override public S next() { checkReloadCount(); S next; - if (index < providers.size()) { - next = providers.get(index); + if (index < instantiatedProviders.size()) { + next = instantiatedProviders.get(index); } else { - if (layerLookupIterator != null) { - next = layerLookupIterator.next(); - } else { - if (moduleServicesIterator.hasNext()) { - next = moduleServicesIterator.next(); - } else { - next = lazyClassPathIterator.next(); - } - } + next = lookupIterator1.next().get(); + instantiatedProviders.add(next); } index++; return next; @@ -932,6 +1265,108 @@ } /** + * Returns a stream that lazily loads the available providers of this + * loader's service. The stream elements are of type {@link Provider + * Provider}, the {@code Provider}'s {@link Provider#get() get} method + * must be invoked to get or instantiate the provider. + * + *

        When processing the stream then providers that were previously + * loaded by stream operations are processed first, in load order. It then + * lazily loads any remaining providers. If a provider class cannot be + * loaded, can't be assigned to the service type, or some other error is + * thrown when locating the provider then it is wrapped with a {@code + * ServiceConfigurationError} and thrown by whatever method caused the + * provider to be loaded.

        + * + *

        If this loader's provider caches are cleared by invoking the {@link + * #reload() reload} method then existing streams for this service + * loader should be discarded.

        + * + *

        The following examples demonstrate usage. The first example + * creates a stream of providers, the second example is the same except + * that it sorts the providers by provider class name (and so locate all + * providers). + *

        {@code
        +     *    Stream providers = ServiceLoader.load(CodecSet.class)
        +     *            .stream()
        +     *            .map(Provider::get);
        +     *
        +     *    Stream providers = ServiceLoader.load(CodecSet.class)
        +     *            .stream()
        +     *            .sorted(Comparator.comparing(p -> p.type().getName()))
        +     *            .map(Provider::get);
        +     * }
        + * + * @return A stream that lazily loads providers for this loader's service + * + * @since 9 + */ + public Stream> stream() { + // use cached providers as the source when all providers loaded + if (loadedAllProviders) { + return loadedProviders.stream(); + } + + // create lookup iterator if needed + if (lookupIterator2 == null) { + lookupIterator2 = newLookupIterator(); + } + + // use lookup iterator and cached providers as source + Spliterator> s = new ProviderSpliterator<>(lookupIterator2); + return StreamSupport.stream(s, false); + } + + private class ProviderSpliterator implements Spliterator> { + final int expectedReloadCount = ServiceLoader.this.reloadCount; + final Iterator> iterator; + int index; + + ProviderSpliterator(Iterator> iterator) { + this.iterator = iterator; + } + + @Override + public Spliterator> trySplit() { + return null; + } + + @Override + @SuppressWarnings("unchecked") + public boolean tryAdvance(Consumer> action) { + if (ServiceLoader.this.reloadCount != expectedReloadCount) + throw new ConcurrentModificationException(); + Provider next = null; + if (index < loadedProviders.size()) { + next = (Provider) loadedProviders.get(index++); + } else if (iterator.hasNext()) { + next = iterator.next(); + } else { + loadedAllProviders = true; + } + if (next != null) { + action.accept(next); + return true; + } else { + return false; + } + } + + @Override + public int characteristics() { + // not IMMUTABLE as structural interference possible + // not NOTNULL so that the characteristics are a subset of the + // characteristics when all Providers have been located. + return Spliterator.ORDERED; + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + } + + /** * Creates a new service loader for the given service type, class * loader, and caller. * @@ -977,7 +1412,7 @@ * * @throws ServiceConfigurationError * if the service type is not accessible to the caller or the - * caller is in a named module and its module descriptor does + * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} */ @CallerSensitive @@ -993,15 +1428,23 @@ * context class loader}. * *

        An invocation of this convenience method of the form - * - *

        -     * ServiceLoader.load(service)
        + *
        {@code
        +     * ServiceLoader.load(service)
        +     * }
        * * is equivalent to * - *
        -     * ServiceLoader.load(service,
        -     *                    Thread.currentThread().getContextClassLoader())
        + *
        {@code
        +     * ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
        +     * }
        + * + * @apiNote Service loader objects obtained with this method should not be + * cached VM-wide. For example, different applications in the same VM may + * have different thread context class loaders. A lookup by one application + * may locate a service provider that is only visible via its thread + * context class loader and so is not suitable to be located by the other + * application. Memory leaks can also arise. A thread local may be suited + * to some applications. * * @param the class of the service type * @@ -1012,7 +1455,7 @@ * * @throws ServiceConfigurationError * if the service type is not accessible to the caller or the - * caller is in a named module and its module descriptor does + * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} */ @CallerSensitive @@ -1027,9 +1470,9 @@ * *

        This convenience method is equivalent to:

        * - *
        -     * ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
        -     * 
        + *
        {@code
        +     * ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
        +     * }
        * *

        This method is intended for use when only installed providers are * desired. The resulting service will only find and load providers that @@ -1045,18 +1488,13 @@ * * @throws ServiceConfigurationError * if the service type is not accessible to the caller or the - * caller is in a named module and its module descriptor does + * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} */ @CallerSensitive public static ServiceLoader loadInstalled(Class service) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - ClassLoader prev = null; - while (cl != null) { - prev = cl; - cl = cl.getParent(); - } - return new ServiceLoader<>(Reflection.getCallerClass(), service, prev); + ClassLoader cl = ClassLoader.getPlatformClassLoader(); + return new ServiceLoader<>(Reflection.getCallerClass(), service, cl); } /** @@ -1080,16 +1518,71 @@ * * @throws ServiceConfigurationError * if the service type is not accessible to the caller or the - * caller is in a named module and its module descriptor does + * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} * * @since 9 */ @CallerSensitive public static ServiceLoader load(Layer layer, Class service) { - return new ServiceLoader<>(Reflection.getCallerClass(), - Objects.requireNonNull(layer), - Objects.requireNonNull(service)); + return new ServiceLoader<>(Reflection.getCallerClass(), layer, service); + } + + /** + * Load the first available provider of this loader's service. This + * convenience method is equivalent to invoking the {@link #iterator() + * iterator()} method and obtaining the first element. It therefore + * returns the first element from the provider cache if possible, it + * otherwise attempts to load and instantiate the first provider. + * + *

        The following example loads the first available provider. If there + * are no providers deployed then it uses a default implementation. + *

        {@code
        +     *    CodecSet provider =
        +     *        ServiceLoader.load(CodecSet.class).findFirst().orElse(DEFAULT_CODECSET);
        +     * }
        + * @return The first provider or empty {@code Optional} if no providers + * are located + * + * @throws ServiceConfigurationError + * If a provider class cannot be loaded, doesn't have the + * appropriate static factory method or constructor, can't be + * assigned to the service type, or if any other kind of exception + * or error is thrown when locating or instantiating the provider. + * + * @since 9 + */ + public Optional findFirst() { + Iterator iterator = iterator(); + if (iterator.hasNext()) { + return Optional.of(iterator.next()); + } else { + return Optional.empty(); + } + } + + /** + * Clear this loader's provider cache so that all providers will be + * reloaded. + * + *

        After invoking this method, subsequent invocations of the {@link + * #iterator() iterator} or {@link #stream() stream} methods will lazily + * look up providers (and instantiate in the case of {@code iterator}) + * from scratch, just as is done by a newly-created loader. + * + *

        This method is intended for use in situations in which new providers + * can be installed into a running Java virtual machine. + */ + public void reload() { + lookupIterator1 = null; + instantiatedProviders.clear(); + + lookupIterator2 = null; + loadedProviders.clear(); + loadedAllProviders = false; + + // increment count to allow CME be thrown + reloadCount++; } /** diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java --- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,37 +25,47 @@ package java.util.spi; +import jdk.internal.misc.JavaUtilResourceBundleAccess; +import jdk.internal.misc.SharedSecrets; + import java.io.IOException; +import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Locale; +import java.util.PropertyResourceBundle; import java.util.ResourceBundle; -import sun.util.locale.provider.ResourceBundleProviderSupport; import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; - /** - * {@code AbstractResourceBundleProvider} is an abstract class for helping - * implement the {@link ResourceBundleProvider} interface. + * {@code AbstractResourceBundleProvider} is an abstract class that provides + * the basic support for a provider implementation class for + * {@link ResourceBundleProvider}. * *

        - * Resource bundles can be packaged in a named module separated from - * the caller module loading the resource bundle, i.e. the module - * calling {@link ResourceBundle#getBundle(String)}. For the caller module - * to load a resource bundle "{@code com.example.app.MyResources}" - * from another module and a service interface named - * "{@code com.example.app.MyResourcesProvider}", - * the bundle provider module can provide the implementation class + * Resource bundles can be packaged in one or more + * named modules, bundle modules. The consumer of the + * resource bundle is the one calling {@link ResourceBundle#getBundle(String)}. + * In order for the consumer module to load a resource bundle + * "{@code com.example.app.MyResources}" provided by another module, + * it will use the {@linkplain java.util.ServiceLoader service loader} + * mechanism. A service interface named "{@code com.example.app.MyResourcesProvider}" + * must be defined and a bundle provider module will provide an + * implementation class of "{@code com.example.app.MyResourcesProvider}" * as follows: * *

        
          * import com.example.app.MyResourcesProvider;
          * class MyResourcesProviderImpl extends AbstractResourceBundleProvider
          *     implements MyResourcesProvider
        - * {
        - *     {@code @Override
        + * {
        + *     protected String toBundleName(String baseName, Locale locale) {
        + *         // return the bundle name per the naming of the resource bundle
        + *         :
        + *     }
        + *
          *     public ResourceBundle getBundle(String baseName, Locale locale) {
          *         // this module only provides bundles in french
          *         if (locale.equals(Locale.FRENCH)) {
        @@ -63,7 +73,7 @@
          *         }
          *         return null;
          *     }
        - * }}
        + * }
  • * * @see * Resource Bundles in Named Modules @@ -73,6 +83,9 @@ * @since 9 */ public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider { + private static final JavaUtilResourceBundleAccess RB_ACCESS = + SharedSecrets.getJavaUtilResourceBundleAccess(); + private static final String FORMAT_CLASS = "java.class"; private static final String FORMAT_PROPERTIES = "java.properties"; @@ -112,7 +125,23 @@ /** * Returns the bundle name for the given {@code baseName} and {@code - * locale}. This method is called from the default implementation of the + * locale} that this provider provides. + * + * @apiNote + * A resource bundle provider may package its resource bundles in the + * same package as the base name of the resource bundle if the package + * is not split among other named modules. If there are more than one + * bundle providers providing the resource bundle of a given base name, + * the resource bundles can be packaged with per-language grouping + * or per-region grouping to eliminate the split packages. + * + *

    For example, if {@code baseName} is {@code "p.resources.Bundle"} then + * the resource bundle name of {@code "p.resources.Bundle"} of + * {@code Locale("ja", "", "XX")} and {@code Locale("en")} + * could be {@code "p.resources.ja.Bundle_ja_ _XX"} and + * {@code p.resources.Bundle_en"} respectively + * + *

    This method is called from the default implementation of the * {@link #getBundle(String, Locale)} method. * * @implNote The default implementation of this method is the same as the @@ -126,27 +155,28 @@ */ protected String toBundleName(String baseName, Locale locale) { return ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT) - .toBundleName(baseName, locale); + .toBundleName(baseName, locale); } /** * Returns a {@code ResourceBundle} for the given {@code baseName} and - * {@code locale}. This method calls the - * {@link #toBundleName(String, Locale) toBundleName} method to get the - * bundle name for the {@code baseName} and {@code locale}. The formats - * specified by the constructor will be searched to find the resource - * bundle. + * {@code locale}. * * @implNote - * The default implementation of this method will find the resource bundle - * local to the module of this provider. + * The default implementation of this method calls the + * {@link #toBundleName(String, Locale) toBundleName} method to get the + * bundle name for the {@code baseName} and {@code locale} and finds the + * resource bundle of the bundle name local in the module of this provider. + * It will only search the formats specified when this provider was + * constructed. * * @param baseName the base bundle name of the resource bundle, a fully * qualified class name. * @param locale the locale for which the resource bundle should be instantiated - * @return {@code ResourceBundle} of the given {@code baseName} and {@code locale}, - * or null if no resource bundle is found - * @throws NullPointerException if {@code baseName} or {@code locale} is null + * @return {@code ResourceBundle} of the given {@code baseName} and + * {@code locale}, or {@code null} if no resource bundle is found + * @throws NullPointerException if {@code baseName} or {@code locale} is + * {@code null} * @throws UncheckedIOException if any IO exception occurred during resource * bundle loading */ @@ -159,13 +189,9 @@ for (String format : formats) { try { if (FORMAT_CLASS.equals(format)) { - PrivilegedAction pa = () -> - ResourceBundleProviderSupport - .loadResourceBundle(module, bundleName); - bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION); + bundle = loadResourceBundle(module, bundleName); } else if (FORMAT_PROPERTIES.equals(format)) { - bundle = ResourceBundleProviderSupport - .loadPropertyResourceBundle(module, bundleName); + bundle = loadPropertyResourceBundle(module, bundleName); } if (bundle != null) { break; @@ -176,4 +202,61 @@ } return bundle; } + + /* + * Returns the ResourceBundle of .class format if found in the module + * of this provider. + */ + private static ResourceBundle loadResourceBundle(Module module, String bundleName) + { + PrivilegedAction> pa = () -> Class.forName(module, bundleName); + Class c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION); + if (c != null && ResourceBundle.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class bundleClass = (Class) c; + return RB_ACCESS.newResourceBundle(bundleClass); + } + return null; + } + + /* + * Returns the ResourceBundle of .property format if found in the module + * of this provider. + */ + private static ResourceBundle loadPropertyResourceBundle(Module module, + String bundleName) + throws IOException + { + String resourceName = toResourceName(bundleName, "properties"); + if (resourceName == null) { + return null; + } + + PrivilegedAction pa = () -> { + try { + return module.getResourceAsStream(resourceName); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + try (InputStream stream = AccessController.doPrivileged(pa)) { + if (stream != null) { + return new PropertyResourceBundle(stream); + } else { + return null; + } + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + private static String toResourceName(String bundleName, String suffix) { + if (bundleName.contains("://")) { + return null; + } + StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length()); + sb.append(bundleName.replace('.', '/')).append('.').append(suffix); + return sb.toString(); + } + } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java Thu Dec 01 08:57:53 2016 +0000 @@ -71,8 +71,8 @@ private static final ServicesCatalog SERVICES_CATALOG = ServicesCatalog.create(); // ClassLoaderValue map for boot class loader - private static final ConcurrentHashMap CLASS_LOADER_VALUE_MAP = - new ConcurrentHashMap<>(); + private static final ConcurrentHashMap CLASS_LOADER_VALUE_MAP + = new ConcurrentHashMap<>(); /** * Returns the unnamed module for the boot loader. @@ -111,14 +111,27 @@ } /** - * Returns a URL to a resource in a named module defined to the boot loader. + * Loads the Class object with the given name in the given module + * defined to the boot loader. Returns {@code null} if not found. + */ + public static Class loadClass(Module module, String name) { + Class c = loadClassOrNull(name); + if (c != null && c.getModule() == module) { + return c; + } else { + return null; + } + } + + /** + * Returns a URL to a resource in a module defined to the boot loader. */ public static URL findResource(String mn, String name) throws IOException { return ClassLoaders.bootLoader().findResource(mn, name); } /** - * Returns an input stream to a resource in a named module defined to the + * Returns an input stream to a resource in a module defined to the * boot loader. */ public static InputStream findResourceAsStream(String mn, String name) @@ -128,9 +141,8 @@ } /** - * Returns the URL to the given resource if the resource can be located - * on the boot class path. This method does not locate a resource in any - * of the named modules defined to the boot loader. + * Returns the URL to the given resource in any of the modules + * defined to the boot loader and the boot class path. */ public static URL findResource(String name) { return ClassLoaders.bootLoader().findResource(name); @@ -138,8 +150,7 @@ /** * Returns an Iterator to iterate over the resources of the given name - * on the boot class path. This method does not locate resources in any - * of the named modules defined to the boot loader. + * in any of the modules defined to the boot loader. */ public static Enumeration findResources(String name) throws IOException { return ClassLoaders.bootLoader().findResources(name); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,8 +29,10 @@ import java.io.FilePermission; import java.io.IOException; import java.io.InputStream; +import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleReference; import java.lang.module.ModuleReader; +import java.lang.ref.SoftReference; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -91,7 +93,7 @@ { static { if (!ClassLoader.registerAsParallelCapable()) - throw new InternalError(); + throw new InternalError("Unable to register as parallel capable"); } // parent ClassLoader @@ -117,7 +119,7 @@ if (mref.location().isPresent()) { try { url = mref.location().get().toURL(); - } catch (MalformedURLException e) { } + } catch (MalformedURLException | IllegalArgumentException e) { } } this.loader = loader; this.mref = mref; @@ -141,6 +143,9 @@ // maps a module reference to a module reader private final Map moduleToReader; + // cache of resource name -> list of URLs. + // used only for resources that are not in module packages + private volatile SoftReference>> resourceCache; /** * Create a new instance. @@ -161,6 +166,8 @@ * the types in the module visible. */ public void loadModule(ModuleReference mref) { + assert !VM.isModuleSystemInited(); + String mn = mref.descriptor().name(); if (nameToModule.putIfAbsent(mn, mref) != null) { throw new InternalError(mn + " already defined to this loader"); @@ -195,32 +202,20 @@ */ @Override public URL findResource(String mn, String name) throws IOException { - ModuleReference mref = nameToModule.get(mn); - if (mref == null) - return null; // not defined to this class loader - - URL url; + URL url = null; - try { - url = AccessController.doPrivileged( - new PrivilegedExceptionAction() { - @Override - public URL run() throws IOException { - URI u = moduleReaderFor(mref).find(name).orElse(null); - if (u != null) { - try { - return u.toURL(); - } catch (MalformedURLException e) { } - } - return null; - } - }); - } catch (PrivilegedActionException pae) { - throw (IOException) pae.getCause(); + if (mn != null) { + // find in module + ModuleReference mref = nameToModule.get(mn); + if (mref != null) { + url = findResource(mref, name); + } + } else { + // find on class path + url = findResourceOnClassPath(name); } - // check access to the URL - return checkURL(url); + return checkURL(url); // check access before returning } /** @@ -232,70 +227,234 @@ { // Need URL to resource when running with a security manager so that // the right permission check is done. - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - + if (System.getSecurityManager() != null || mn == null) { URL url = findResource(mn, name); return (url != null) ? url.openStream() : null; - - } else { - - ModuleReference mref = nameToModule.get(mn); - if (mref == null) - return null; // not defined to this class loader + } - try { - return AccessController.doPrivileged( - new PrivilegedExceptionAction() { - @Override - public InputStream run() throws IOException { - return moduleReaderFor(mref).open(name).orElse(null); - } - }); - } catch (PrivilegedActionException pae) { - throw (IOException) pae.getCause(); - } - } - } - - /** - * Finds the resource with the given name on the class path of this class - * loader. - */ - @Override - public URL findResource(String name) { - if (ucp != null) { - PrivilegedAction pa = () -> ucp.findResource(name, false); - URL url = AccessController.doPrivileged(pa); - return checkURL(url); + // find in module defined to this loader, no security manager + ModuleReference mref = nameToModule.get(mn); + if (mref != null) { + return moduleReaderFor(mref).open(name).orElse(null); } else { return null; } } /** + * Finds a resource with the given name in the modules defined to this + * class loader or its class path. + */ + @Override + public URL findResource(String name) { + String pn = ResourceHelper.getPackageName(name); + LoadedModule module = packageToModule.get(pn); + if (module != null) { + + // resource is in a package of a module defined to this loader + if (module.loader() == this + && (name.endsWith(".class") || isOpen(module.mref(), pn))) { + try { + return findResource(module.name(), name); // checks URL + } catch (IOException ioe) { + return null; + } + } + + } else { + + // not in a module package but may be in module defined to this loader + try { + List urls = findMiscResource(name); + if (!urls.isEmpty()) { + URL url = urls.get(0); + if (url != null) { + return checkURL(url); // check access before returning + } + } + } catch (IOException ioe) { + return null; + } + + } + + // search class path + URL url = findResourceOnClassPath(name); + return checkURL(url); + } + + /** * Returns an enumeration of URL objects to all the resources with the - * given name on the class path of this class loader. + * given name in modules defined to this class loader or on the class + * path of this loader. */ @Override public Enumeration findResources(String name) throws IOException { - if (ucp != null) { - List result = new ArrayList<>(); - PrivilegedAction> pa = () -> ucp.findResources(name, false); - Enumeration e = AccessController.doPrivileged(pa); - while (e.hasMoreElements()) { - URL url = checkURL(e.nextElement()); + List checked = new ArrayList<>(); // list of checked URLs + + String pn = ResourceHelper.getPackageName(name); + LoadedModule module = packageToModule.get(pn); + if (module != null) { + + // resource is in a package of a module defined to this loader + if (module.loader() == this + && (name.endsWith(".class") || isOpen(module.mref(), pn))) { + URL url = findResource(module.name(), name); // checks URL if (url != null) { - result.add(url); + checked.add(url); + } + } + + } else { + // not in a package of a module defined to this loader + for (URL url : findMiscResource(name)) { + url = checkURL(url); + if (url != null) { + checked.add(url); } } - return Collections.enumeration(result); // checked URLs + } + + // search class path + Enumeration e = findResourcesOnClassPath(name); + while (e.hasMoreElements()) { + URL url = checkURL(e.nextElement()); + if (url != null) { + checked.add(url); + } + } + + return Collections.enumeration(checked); + } + + /** + * Returns the list of URLs to a "miscellaneous" resource in modules + * defined to this loader. A miscellaneous resource is not in a module + * package, e.g. META-INF/services/p.S. + * + * The cache used by this method avoids repeated searching of all modules. + */ + private List findMiscResource(String name) throws IOException { + SoftReference>> ref = this.resourceCache; + Map> map = (ref != null) ? ref.get() : null; + if (map != null) { + List urls = map.get(name); + if (urls != null) + return urls; + } + + // search all modules for the resource + List urls; + try { + urls = AccessController.doPrivileged( + new PrivilegedExceptionAction<>() { + @Override + public List run() throws IOException { + List result = new ArrayList<>(); + for (ModuleReference mref : nameToModule.values()) { + URI u = moduleReaderFor(mref).find(name).orElse(null); + if (u != null) { + try { + result.add(u.toURL()); + } catch (MalformedURLException | + IllegalArgumentException e) { + } + } + } + return result; + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + + // only cache resources after all modules have been defined + if (VM.isModuleSystemInited()) { + if (map == null) { + map = new ConcurrentHashMap<>(); + this.resourceCache = new SoftReference<>(map); + } + if (urls.isEmpty()) + urls = Collections.emptyList(); + map.putIfAbsent(name, urls); + } + return urls; + } + + /** + * Returns the URL to a resource in a module or {@code null} if not found. + */ + private URL findResource(ModuleReference mref, String name) throws IOException { + URI u; + if (System.getSecurityManager() == null) { + u = moduleReaderFor(mref).find(name).orElse(null); } else { + try { + u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () { + @Override + public URI run() throws IOException { + return moduleReaderFor(mref).find(name).orElse(null); + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + } + if (u != null) { + try { + return u.toURL(); + } catch (MalformedURLException | IllegalArgumentException e) { } + } + return null; + } + + /** + * Returns the URL to a resource in a module. Returns {@code null} if not found + * or an I/O error occurs. + */ + private URL findResourceOrNull(ModuleReference mref, String name) { + try { + return findResource(mref, name); + } catch (IOException ignore) { + return null; + } + } + + /** + * Returns a URL to a resource on the class path. + */ + private URL findResourceOnClassPath(String name) { + if (ucp != null) { + if (System.getSecurityManager() == null) { + return ucp.findResource(name, false); + } else { + PrivilegedAction pa = () -> ucp.findResource(name, false); + return AccessController.doPrivileged(pa); + } + } else { + // no class path + return null; + } + } + + /** + * Returns the URLs of all resources of the given name on the class path. + */ + private Enumeration findResourcesOnClassPath(String name) { + if (ucp != null) { + if (System.getSecurityManager() == null) { + return ucp.findResources(name, false); + } else { + PrivilegedAction> pa; + pa = () -> ucp.findResources(name, false); + return AccessController.doPrivileged(pa); + } + } else { + // no class path return Collections.emptyEnumeration(); } } - // -- finding/loading classes /** @@ -335,24 +494,30 @@ } /** - * Finds the class with the specified binary name in a given module. - * This method returns {@code null} if the class cannot be found. + * Finds the class with the specified binary name in a module. + * This method returns {@code null} if the class cannot be found + * or not defined in the specified module. */ @Override protected Class findClass(String mn, String cn) { - ModuleReference mref = nameToModule.get(mn); - if (mref == null) - return null; // not defined to this class loader + if (mn != null) { + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(mn, cn); + if (loadedModule == null) { + return null; + } - // find the candidate module for this class - LoadedModule loadedModule = findLoadedModule(cn); - if (loadedModule == null || !loadedModule.name().equals(mn)) { - return null; // module name does not match + // attempt to load class in module defined to this loader + assert loadedModule.loader() == this; + return findClassInModuleOrNull(loadedModule, cn); } - // attempt to load class in module defined to this loader - assert loadedModule.loader() == this; - return findClassInModuleOrNull(loadedModule, cn); + // search class path + if (ucp != null) { + return findClassOnClassPathOrNull(cn); + } + + return null; } /** @@ -441,14 +606,33 @@ } /** + * Find the candidate loaded module for the given class name + * in the named module. Returns {@code null} if the named module + * is not defined to this class loader or does not contain + * the API package for the class. + */ + private LoadedModule findLoadedModule(String mn, String cn) { + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null && mn.equals(loadedModule.name())) { + return loadedModule; + } else { + return null; + } + } + + /** * Finds the class with the specified binary name if in a module * defined to this ClassLoader. * * @return the resulting Class or {@code null} if not found */ private Class findClassInModuleOrNull(LoadedModule loadedModule, String cn) { - PrivilegedAction> pa = () -> defineClass(cn, loadedModule); - return AccessController.doPrivileged(pa); + if (System.getSecurityManager() == null) { + return defineClass(cn, loadedModule); + } else { + PrivilegedAction> pa = () -> defineClass(cn, loadedModule); + return AccessController.doPrivileged(pa); + } } /** @@ -457,10 +641,21 @@ * @return the resulting Class or {@code null} if not found */ private Class findClassOnClassPathOrNull(String cn) { - return AccessController.doPrivileged( - new PrivilegedAction>() { + String path = cn.replace('.', '/').concat(".class"); + if (System.getSecurityManager() == null) { + Resource res = ucp.getResource(path, false); + if (res != null) { + try { + return defineClass(cn, res); + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + } + } + return null; + } else { + // avoid use of lambda here + PrivilegedAction> pa = new PrivilegedAction<>() { public Class run() { - String path = cn.replace('.', '/').concat(".class"); Resource res = ucp.getResource(path, false); if (res != null) { try { @@ -471,7 +666,9 @@ } return null; } - }); + }; + return AccessController.doPrivileged(pa); + } } /** @@ -662,13 +859,13 @@ sealBase = url; } return definePackage(pn, - specTitle, - specVersion, - specVendor, - implTitle, - implVersion, - implVendor, - sealBase); + specTitle, + specVersion, + specVendor, + implTitle, + implVersion, + implVendor, + sealBase); } /** @@ -760,6 +957,27 @@ }; /** + * Returns true if the given module opens the given package + * unconditionally. + * + * @implNote This method currently iterates over each of the open + * packages. This will be replaced once the ModuleDescriptor.Opens + * API is updated. + */ + private boolean isOpen(ModuleReference mref, String pn) { + ModuleDescriptor descriptor = mref.descriptor(); + if (descriptor.isOpen()) + return true; + for (ModuleDescriptor.Opens opens : descriptor.opens()) { + String source = opens.source(); + if (!opens.isQualified() && source.equals(pn)) { + return true; + } + } + return false; + } + + /** * Checks access to the given URL. We use URLClassPath for consistent * checking with java.net.URLClassLoader. */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java Thu Dec 01 08:57:53 2016 +0000 @@ -48,13 +48,19 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.SecureClassLoader; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import jdk.internal.misc.SharedSecrets; + /** * A class loader that loads classes and resources from a collection of @@ -119,7 +125,7 @@ if (mref.location().isPresent()) { try { url = mref.location().get().toURL(); - } catch (MalformedURLException e) { } + } catch (MalformedURLException | IllegalArgumentException e) { } } this.mref = mref; this.url = url; @@ -141,7 +147,7 @@ LoaderPool pool, ClassLoader parent) { - super(parent); + super("Loader-" + resolvedModule.name(), parent); this.pool = pool; this.parent = parent; @@ -200,12 +206,12 @@ * @param cf the Configuration containing at least modules to be defined to * this class loader * - * @param parentLayer the parent Layer + * @param parentLayers the parent Layers */ - public Loader initRemotePackageMap(Configuration cf, Layer parentLayer) { - + public Loader initRemotePackageMap(Configuration cf, + List parentLayers) + { for (String name : nameToModule.keySet()) { - ResolvedModule resolvedModule = cf.findModule(name).get(); assert resolvedModule.configuration() == cf; @@ -228,17 +234,15 @@ } else { - // find the layer contains the module that is read - Layer layer = parentLayer; - while (layer != null) { - if (layer.configuration() == other.configuration()) { - break; - } - layer = layer.parent().orElse(null); - } - assert layer != null; + // find the layer for the target module + Layer layer = parentLayers.stream() + .map(parent -> findLayer(parent, other.configuration())) + .flatMap(Optional::stream) + .findAny() + .orElseThrow(() -> + new InternalError("Unable to find parent layer")); - // find the class loader for the module in the layer + // find the class loader for the module // For now we use the platform loader for modules defined to the // boot loader assert layer.findModule(mn).isPresent(); @@ -268,7 +272,6 @@ throw new IllegalArgumentException("Package " + pn + " cannot be imported from multiple loaders"); } - } } } @@ -279,6 +282,17 @@ } /** + * Find the layer corresponding to the given configuration in the tree + * of layers rooted at the given parent. + */ + private Optional findLayer(Layer parent, Configuration cf) { + return SharedSecrets.getJavaLangReflectModuleAccess().layers(parent) + .filter(l -> l.configuration() == cf) + .findAny(); + } + + + /** * Returns the loader pool that this loader is in or {@code null} if this * loader is not in a loader pool. */ @@ -296,12 +310,14 @@ */ @Override protected URL findResource(String mn, String name) throws IOException { - ModuleReference mref = nameToModule.get(mn); + ModuleReference mref = (mn != null) ? nameToModule.get(mn) : null; if (mref == null) return null; // not defined to this class loader + // locate resource + URL url = null; try { - return AccessController.doPrivileged( + url = AccessController.doPrivileged( new PrivilegedExceptionAction() { @Override public URL run() throws IOException { @@ -309,16 +325,89 @@ if (ouri.isPresent()) { try { return ouri.get().toURL(); - } catch (MalformedURLException e) { } + } catch (MalformedURLException | + IllegalArgumentException e) { } } return null; } - }, acc); + }); } catch (PrivilegedActionException pae) { throw (IOException) pae.getCause(); - } catch (SecurityException se) { - return null; + } + + // check access with permissions restricted by ACC + if (url != null && System.getSecurityManager() != null) { + try { + URL urlToCheck = url; + url = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public URL run() throws IOException { + return URLClassPath.checkURL(urlToCheck); + } + }, acc); + } catch (PrivilegedActionException pae) { + url = null; + } } + + return url; + } + + @Override + public URL findResource(String name) { + URL url = null; + String pn = ResourceHelper.getPackageName(name); + LoadedModule module = localPackageToModule.get(pn); + if (module != null) { + if (name.endsWith(".class") || isOpen(module.mref(), pn)) { + try { + url = findResource(module.name(), name); + } catch (IOException ioe) { + // ignore + } + } + } else { + for (ModuleReference mref : nameToModule.values()) { + try { + url = findResource(mref.descriptor().name(), name); + if (url != null) + break; + } catch (IOException ioe) { + // ignore + } + } + } + return url; + } + + @Override + public Enumeration findResources(String name) throws IOException { + List urls = new ArrayList<>(); + String pn = ResourceHelper.getPackageName(name); + LoadedModule module = localPackageToModule.get(pn); + if (module != null) { + if (name.endsWith(".class") || isOpen(module.mref(), pn)) { + try { + URL url = findResource(module.name(), name); + if (url != null) + urls.add(url); + } catch (IOException ioe) { + // ignore + } + } + } else { + for (ModuleReference mref : nameToModule.values()) { + try { + URL url = findResource(mref.descriptor().name(), name); + if (url != null) + urls.add(url); + } catch (IOException ioe) { + // ignore + } + } + } + return Collections.enumeration(urls); } @@ -544,4 +633,24 @@ } } + /** + * Returns true if the given module opens the given package + * unconditionally. + * + * @implNote This method currently iterates over each of the open + * packages. This will be replaced once the ModuleDescriptor.Opens + * API is updated. + */ + private boolean isOpen(ModuleReference mref, String pn) { + ModuleDescriptor descriptor = mref.descriptor(); + if (descriptor.isOpen()) + return true; + for (ModuleDescriptor.Opens opens : descriptor.opens()) { + String source = opens.source(); + if (!opens.isQualified() && source.equals(pn)) { + return true; + } + } + return false; + } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java --- a/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,10 +26,10 @@ package jdk.internal.loader; import java.lang.module.Configuration; -import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -51,7 +51,7 @@ * created with the given parent class loader as its parent. */ public LoaderPool(Configuration cf, - Layer parentLayer, + List parentLayers, ClassLoader parentLoader) { Map loaders = new HashMap<>(); @@ -63,7 +63,7 @@ this.loaders = loaders; // complete the initialization - loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer)); + loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayers)); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.loader; + +import jdk.internal.module.Checks; + +/** + * Helper class for Class#getResource, Module#getResourceAsStream, and other + * methods that locate a resource in a module. + */ +public final class ResourceHelper { + private ResourceHelper() { } + + /** + * Returns the package name for a resource. + */ + public static String getPackageName(String name) { + int index = name.lastIndexOf('/'); + if (index != -1) { + return name.substring(0, index).replace("/", "."); + } else { + return ""; + } + } + + /** + * Returns true if the resource is a simple resource that can + * never be encapsulated. Resources ending in "{@code .class}" or where + * the package name is not a Java identifier are resources that can + * never be encapsulated. + */ + public static boolean isSimpleResource(String name) { + int len = name.length(); + if (len > 6 && name.endsWith(".class")) { + return true; + } + if (!Checks.isJavaIdentifier(getPackageName(name))) { + return true; + } + return false; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Executable; import java.lang.reflect.Layer; +import java.lang.reflect.Method; import java.lang.reflect.Module; import java.net.URL; import java.security.AccessControlContext; @@ -36,12 +37,19 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; -import jdk.internal.module.ServicesCatalog; import jdk.internal.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; import sun.nio.ch.Interruptible; public interface JavaLangAccess { + + /** + * Returns a {@code Method} object that reflects the specified public + * member method of the given class. Returns {@code null} if the + * method is not defined. + */ + Method getMethodOrNull(Class klass, String name, Class... parameterTypes); + /** Return the constant pool for a class. */ ConstantPool getConstantPool(Class klass); @@ -136,17 +144,6 @@ Layer getBootLayer(); /** - * Returns the ServicesCatalog for the given class loader. - */ - ServicesCatalog getServicesCatalog(ClassLoader cl); - - /** - * Returns the ServicesCatalog for the given class loader, creating it - * if doesn't already exist. - */ - ServicesCatalog createOrGetServicesCatalog(ClassLoader cl); - - /** * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s) * associated with the given class loader, creating it if it doesn't already exist. */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,24 +27,26 @@ import java.io.PrintStream; import java.lang.module.Configuration; -import jdk.internal.module.ModuleHashes; - import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Version; import java.lang.module.ModuleFinder; -import java.util.Collection; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.net.URI; import java.nio.file.Path; import java.util.Map; +import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; +import jdk.internal.module.ModuleHashes; + /** * Provides access to non-public methods in java.lang.module. */ @@ -52,28 +54,59 @@ public interface JavaLangModuleAccess { /** - * Returns {@code ModuleDescriptor.Requires} of the given modifier + * Creates a builder for building a module with the given module name. + * + * @param strict + * Indicates whether module names are checked or not + */ + ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict); + + /** + * Creates a builder for building an open module with the given module name. + * + * @param strict + * Indicates whether module names are checked or not + */ + ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict); + + /** + * Returns a {@code ModuleDescriptor.Requires} of the given modifiers * and module name. */ Requires newRequires(Set ms, String mn); /** * Returns an unqualified {@code ModuleDescriptor.Exports} - * of the given package name. + * of the given modifiers and package name source. */ - Exports newExports(String source); + Exports newExports(Set ms, + String source); /** * Returns a qualified {@code ModuleDescriptor.Exports} - * of the given package name and targets. + * of the given modifiers, package name source and targets. */ - Exports newExports(String source, Set targets); + Exports newExports(Set ms, + String source, + Set targets); + + /** + * Returns an unqualified {@code ModuleDescriptor.Opens} + * of the given modifiers and package name source. + */ + Opens newOpens(Set ms, String source); + + /** + * Returns a qualified {@code ModuleDescriptor.Opens} + * of the given modifiers, package name source and targets. + */ + Opens newOpens(Set ms, String source, Set targets); /** * Returns a {@code ModuleDescriptor.Provides} * of the given service name and providers. */ - Provides newProvides(String service, Set providers); + Provides newProvides(String service, List providers); /** * Returns a {@code ModuleDescriptor.Version} of the given version. @@ -89,19 +122,22 @@ * Returns a new {@code ModuleDescriptor} instance. */ ModuleDescriptor newModuleDescriptor(String name, + boolean open, boolean automatic, boolean synthetic, Set requires, + Set exports, + Set opens, Set uses, - Set exports, - Map provides, + Set provides, Version version, String mainClass, String osName, String osArch, String osVersion, Set packages, - ModuleHashes hashes); + ModuleHashes hashes, + int hashCode); /** * Returns the object with the hashes of other modules diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ import java.lang.reflect.Layer; import java.lang.reflect.Module; import java.net.URI; +import java.util.stream.Stream; import jdk.internal.module.ServicesCatalog; @@ -71,16 +72,37 @@ void addExports(Module m1, String pkg, Module m2); /** + * Updates module m1 to open a package to module m2. Opening the + * package does not result in a strong reference to m2 (m2 can be GC'ed). + */ + void addOpens(Module m1, String pkg, Module m2); + + /** * Updates a module m to export a package to all modules. */ void addExportsToAll(Module m, String pkg); /** + * Updates a module m to open a package to all modules. + */ + void addOpensToAll(Module m, String pkg); + + /** * Updates a module m to export a package to all unnamed modules. */ void addExportsToAllUnnamed(Module m, String pkg); /** + * Updates a module m to open a package to all unnamed modules. + */ + void addOpensToAllUnnamed(Module m, String pkg); + + /** + * Updates a module m to use a service. + */ + void addUses(Module m, Class service); + + /** * Add a package to the given module. */ void addPackage(Module m, String pkg); @@ -90,4 +112,15 @@ */ ServicesCatalog getServicesCatalog(Layer layer); + /** + * Returns an ordered stream of layers. The first element is is the + * given layer, the remaining elements are its parents, in DFS order. + */ + Stream layers(Layer layer); + + /** + * Returns a stream of the layers that have modules defined to the + * given class loader. + */ + Stream layers(ClassLoader loader); } \ No newline at end of file diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ package jdk.internal.misc; +import java.lang.reflect.Module; import java.util.Locale; import java.util.ResourceBundle; @@ -51,4 +52,16 @@ * Sets the bundle's base name to the given name. */ void setName(ResourceBundle bundle, String name); + + /** + * Returns a {@code ResourceBundle} of the given baseName and locale + * loaded on behalf of the given module with no caller module + * access check. + */ + ResourceBundle getBundle(String baseName, Locale locale, Module module); + + /** + * Instantiates a {@code ResourceBundle} of the given bundle class. + */ + ResourceBundle newResourceBundle(Class bundleClass); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,7 @@ package jdk.internal.misc; import java.lang.module.ModuleDescriptor; +import java.util.ResourceBundle; import java.util.jar.JarFile; import java.io.Console; import java.io.FileDescriptor; @@ -294,6 +295,8 @@ } public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() { + if (javaUtilResourceBundleAccess == null) + unsafe.ensureClassInitialized(ResourceBundle.class); return javaUtilResourceBundleAccess; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/Builder.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,14 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Version; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -40,7 +42,7 @@ /** * This builder is optimized for reconstituting ModuleDescriptor - * for installed modules. The validation should be done at jlink time. + * for system modules. The validation should be done at jlink time. * * 1. skip name validation * 2. ignores dependency hashes. @@ -53,66 +55,137 @@ private static final JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess(); - private static final Set MANDATED = - Collections.singleton(Requires.Modifier.MANDATED); - private static final Set PUBLIC = - Collections.singleton(Requires.Modifier.PUBLIC); - // Static cache of the most recently seen Version to cheaply deduplicate // most Version objects. JDK modules have the same version. static Version cachedVersion; + /** + * Returns a {@link Requires} for a dependence on a module + * with the given (and possibly empty) set of modifiers. + */ + public static Requires newRequires(Set mods, + String mn) + { + return jlma.newRequires(mods, mn); + } + + /** + * Returns a {@link Exports} for a qualified export, with + * the given (and possibly empty) set of modifiers, + * to a set of target modules. + */ + public static Exports newExports(Set ms, + String pn, + Set targets) { + return jlma.newExports(ms, pn, targets); + } + + /** + * Returns an {@link Opens} for an unqualified open with a given set of + * modifiers. + */ + public static Opens newOpens(Set ms, String pn) { + return jlma.newOpens(ms, pn); + } + + /** + * Returns an {@link Opens} for a qualified opens, with + * the given (and possibly empty) set of modifiers, + * to a set of target modules. + */ + public static Opens newOpens(Set ms, + String pn, + Set targets) { + return jlma.newOpens(ms, pn, targets); + } + + /** + * Returns a {@link Exports} for an unqualified export with a given set + * of modifiers. + */ + public static Exports newExports(Set ms, String pn) { + return jlma.newExports(ms, pn); + } + + /** + * Returns a {@link Provides} for a service with a given list of + * implementation classes. + */ + public static Provides newProvides(String st, List pcs) { + return jlma.newProvides(st, pcs); + } + final String name; - final Set requires; - final Set exports; - final Map provides; + boolean open; + boolean automatic; + boolean synthetic; + Set requires; + Set exports; + Set opens; Set packages; Set uses; + Set provides; Version version; String mainClass; String osName; String osArch; String osVersion; String algorithm; - Map hashes; + Map hashes; - Builder(String name, int reqs, int exports, - int provides, int packages) { + Builder(String name) { this.name = name; - this.requires = reqs > 0 ? new HashSet<>(reqs) : Collections.emptySet(); - this.exports = exports > 0 ? new HashSet<>(exports) : Collections.emptySet(); - this.provides = provides > 0 ? new HashMap<>(provides) : Collections.emptyMap(); + this.requires = Collections.emptySet(); + this.exports = Collections.emptySet(); + this.opens = Collections.emptySet(); + this.provides = Collections.emptySet(); this.uses = Collections.emptySet(); } - /** - * Adds a module dependence with the given (and possibly empty) set - * of modifiers. - */ - public Builder requires(Set mods, String mn) { - requires.add(jlma.newRequires(Collections.unmodifiableSet(mods), mn)); + Builder open(boolean value) { + this.open = value; + return this; + } + + Builder automatic(boolean value) { + this.automatic = value; + return this; + } + + Builder synthetic(boolean value) { + this.synthetic = value; return this; } /** - * Adds a module dependence with an empty set of modifiers. + * Sets module exports. */ - public Builder requires(String mn) { - requires.add(jlma.newRequires(Collections.emptySet(), mn)); + public Builder exports(Exports[] exports) { + this.exports = Set.of(exports); return this; } /** - * Adds a module dependence with the given modifier. + * Sets module opens. + */ + public Builder opens(Opens[] opens) { + this.opens = Set.of(opens); + return this; + } + + /** + * Sets module requires. */ - public Builder requires(Requires.Modifier mod, String mn) { - if (mod == Requires.Modifier.MANDATED) { - requires.add(jlma.newRequires(MANDATED, mn)); - } else if (mod == Requires.Modifier.PUBLIC) { - requires.add(jlma.newRequires(PUBLIC, mn)); - } else { - requires.add(jlma.newRequires(Collections.singleton(mod), mn)); - } + public Builder requires(Requires[] requires) { + this.requires = Set.of(requires); + return this; + } + + /** + * Adds a set of (possible empty) packages. + */ + public Builder packages(Set packages) { + this.packages = packages; return this; } @@ -125,51 +198,10 @@ } /** - * Adds an export to a set of target modules. - */ - public Builder exports(String pn, Set targets) { - exports.add(jlma.newExports(pn, targets)); - return this; - } - - /** - * Adds an export to a target module. - */ - public Builder exports(String pn, String target) { - return exports(pn, Collections.singleton(target)); - } - - /** - * Adds an export. + * Sets module provides. */ - public Builder exports(String pn) { - exports.add(jlma.newExports(pn)); - return this; - } - - /** - * Provides service {@code st} with implementations {@code pcs}. - */ - public Builder provides(String st, Set pcs) { - if (provides.containsKey(st)) - throw new IllegalStateException("Providers of service " - + st + " already declared"); - provides.put(st, jlma.newProvides(st, pcs)); - return this; - } - - /** - * Provides service {@code st} with implementation {@code pc}. - */ - public Builder provides(String st, String pc) { - return provides(st, Collections.singleton(pc)); - } - - /** - * Adds a set of (possible empty) packages. - */ - public Builder packages(Set packages) { - this.packages = packages; + public Builder provides(Provides[] provides) { + this.provides = Set.of(provides); return this; } @@ -253,7 +285,7 @@ /** * Sets the module hash for the given module name */ - public Builder moduleHash(String mn, String hash) { + public Builder moduleHash(String mn, byte[] hash) { if (hashes == null) hashes = new HashMap<>(); @@ -264,18 +296,20 @@ /** * Builds a {@code ModuleDescriptor} from the components. */ - public ModuleDescriptor build() { + public ModuleDescriptor build(int hashCode) { assert name != null; ModuleHashes moduleHashes = hashes != null ? new ModuleHashes(algorithm, hashes) : null; return jlma.newModuleDescriptor(name, - false, // automatic - false, // assume not synthetic for now + open, + automatic, + synthetic, requires, + exports, + opens, uses, - exports, provides, version, mainClass, @@ -283,6 +317,7 @@ osArch, osVersion, packages, - moduleHashes); + moduleHashes, + hashCode); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/Checks.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,6 @@ package jdk.internal.module; - public final class Checks { private Checks() { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,17 +27,20 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Requires; -import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Version; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import jdk.internal.misc.JavaLangModuleAccess; +import jdk.internal.misc.SharedSecrets; import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.ByteVector; import jdk.internal.org.objectweb.asm.ClassReader; @@ -51,7 +54,7 @@ * class file attributes in a module-info class file. */ -class ClassFileAttributes { +public final class ClassFileAttributes { private ClassFileAttributes() { } @@ -60,16 +63,18 @@ * // See lang-vm.html for details. * } */ - static class ModuleAttribute extends Attribute { + public static class ModuleAttribute extends Attribute { + private static final JavaLangModuleAccess JLMA + = SharedSecrets.getJavaLangModuleAccess(); private ModuleDescriptor descriptor; - ModuleAttribute(ModuleDescriptor descriptor) { + public ModuleAttribute(ModuleDescriptor descriptor) { super(MODULE); this.descriptor = descriptor; } - ModuleAttribute() { + public ModuleAttribute() { super(MODULE); } @@ -81,27 +86,43 @@ int codeOff, Label[] labels) { - ModuleDescriptor.Builder builder - = new ModuleDescriptor.Builder("xyzzy"); // Name never used ModuleAttribute attr = new ModuleAttribute(); + // module_name + String mn = cr.readUTF8(off, buf).replace('/', '.'); + off += 2; + + // module_flags + int module_flags = cr.readUnsignedShort(off); + boolean open = ((module_flags & ACC_OPEN) != 0); + off += 2; + + ModuleDescriptor.Builder builder; + if (open) { + builder = JLMA.newOpenModuleBuilder(mn, false); + } else { + builder = JLMA.newModuleBuilder(mn, false); + } + // requires_count and requires[requires_count] int requires_count = cr.readUnsignedShort(off); off += 2; for (int i=0; i mods; + Set mods; if (flags == 0) { mods = Collections.emptySet(); } else { mods = new HashSet<>(); - if ((flags & ACC_PUBLIC) != 0) - mods.add(Modifier.PUBLIC); + if ((flags & ACC_TRANSITIVE) != 0) + mods.add(Requires.Modifier.TRANSITIVE); + if ((flags & ACC_STATIC_PHASE) != 0) + mods.add(Requires.Modifier.STATIC); if ((flags & ACC_SYNTHETIC) != 0) - mods.add(Modifier.SYNTHETIC); + mods.add(Requires.Modifier.SYNTHETIC); if ((flags & ACC_MANDATED) != 0) - mods.add(Modifier.MANDATED); + mods.add(Requires.Modifier.MANDATED); } builder.requires(mods, dn); off += 4; @@ -113,18 +134,70 @@ if (exports_count > 0) { for (int i=0; i mods; + if (flags == 0) { + mods = Collections.emptySet(); + } else { + mods = new HashSet<>(); + if ((flags & ACC_SYNTHETIC) != 0) + mods.add(Exports.Modifier.SYNTHETIC); + if ((flags & ACC_MANDATED) != 0) + mods.add(Exports.Modifier.MANDATED); + } + + int exports_to_count = cr.readUnsignedShort(off); + off += 2; if (exports_to_count > 0) { Set targets = new HashSet<>(); for (int j=0; j 0) { + for (int i=0; i mods; + if (flags == 0) { + mods = Collections.emptySet(); + } else { + mods = new HashSet<>(); + if ((flags & ACC_SYNTHETIC) != 0) + mods.add(Opens.Modifier.SYNTHETIC); + if ((flags & ACC_MANDATED) != 0) + mods.add(Opens.Modifier.MANDATED); + } + + int opens_to_count = cr.readUnsignedShort(off); + off += 2; + if (opens_to_count > 0) { + Set targets = new HashSet<>(); + for (int j=0; j 0) { - Map> provides = new HashMap<>(); for (int i=0; i new LinkedHashSet<>()).add(cn); - off += 4; + String service = cr.readClass(off, buf).replace('/', '.'); + off += 2; + int with_count = cr.readUnsignedShort(off); + off += 2; + List providers = new ArrayList<>(); + for (int j=0; j builder.provides(e.getKey(), - e.getValue())); } attr.descriptor = builder.build(); @@ -169,6 +246,19 @@ assert descriptor != null; ByteVector attr = new ByteVector(); + // module_name + String mn = descriptor.name(); + int module_name_index = cw.newUTF8(mn.replace('.', '/')); + attr.putShort(module_name_index); + + // module_flags + int module_flags = 0; + if (descriptor.isOpen()) + module_flags |= ACC_OPEN; + if (descriptor.isSynthetic()) + module_flags |= ACC_SYNTHETIC; + attr.putShort(module_flags); + // requires_count attr.putShort(descriptor.requires().size()); @@ -176,32 +266,61 @@ for (Requires md : descriptor.requires()) { String dn = md.name(); int flags = 0; - if (md.modifiers().contains(Modifier.PUBLIC)) - flags |= ACC_PUBLIC; - if (md.modifiers().contains(Modifier.SYNTHETIC)) + if (md.modifiers().contains(Requires.Modifier.TRANSITIVE)) + flags |= ACC_TRANSITIVE; + if (md.modifiers().contains(Requires.Modifier.STATIC)) + flags |= ACC_STATIC_PHASE; + if (md.modifiers().contains(Requires.Modifier.SYNTHETIC)) flags |= ACC_SYNTHETIC; - if (md.modifiers().contains(Modifier.MANDATED)) + if (md.modifiers().contains(Requires.Modifier.MANDATED)) flags |= ACC_MANDATED; - int index = cw.newUTF8(dn); + int index = cw.newUTF8(dn.replace('.', '/')); attr.putShort(index); attr.putShort(flags); } // exports_count and exports[exports_count]; - if (descriptor.exports().isEmpty()) { - attr.putShort(0); - } else { - attr.putShort(descriptor.exports().size()); - for (Exports e : descriptor.exports()) { - String pkg = e.source().replace('.', '/'); - attr.putShort(cw.newUTF8(pkg)); - if (e.isQualified()) { - Set ts = e.targets(); - attr.putShort(ts.size()); - ts.forEach(t -> attr.putShort(cw.newUTF8(t))); - } else { - attr.putShort(0); - } + attr.putShort(descriptor.exports().size()); + for (Exports e : descriptor.exports()) { + String pkg = e.source().replace('.', '/'); + attr.putShort(cw.newUTF8(pkg)); + + int flags = 0; + if (e.modifiers().contains(Exports.Modifier.SYNTHETIC)) + flags |= ACC_SYNTHETIC; + if (e.modifiers().contains(Exports.Modifier.MANDATED)) + flags |= ACC_MANDATED; + attr.putShort(flags); + + if (e.isQualified()) { + Set ts = e.targets(); + attr.putShort(ts.size()); + ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/')))); + } else { + attr.putShort(0); + } + } + + + // opens_counts and opens[opens_counts] + attr.putShort(descriptor.opens().size()); + for (Opens obj : descriptor.opens()) { + String pkg = obj.source().replace('.', '/'); + attr.putShort(cw.newUTF8(pkg)); + + int flags = 0; + if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC)) + flags |= ACC_SYNTHETIC; + if (obj.modifiers().contains(Opens.Modifier.MANDATED)) + flags |= ACC_MANDATED; + attr.putShort(flags); + + if (obj.isQualified()) { + Set ts = obj.targets(); + attr.putShort(ts.size()); + ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/')))); + } else { + attr.putShort(0); } } @@ -221,14 +340,13 @@ if (descriptor.provides().isEmpty()) { attr.putShort(0); } else { - int count = descriptor.provides().values() - .stream().mapToInt(ps -> ps.providers().size()).sum(); - attr.putShort(count); - for (Provides p : descriptor.provides().values()) { + attr.putShort(descriptor.provides().size()); + for (Provides p : descriptor.provides()) { String service = p.service().replace('.', '/'); - int index = cw.newClass(service); + attr.putShort(cw.newClass(service)); + int with_count = p.providers().size(); + attr.putShort(with_count); for (String provider : p.providers()) { - attr.putShort(index); attr.putShort(cw.newClass(provider.replace('.', '/'))); } } @@ -239,44 +357,13 @@ } /** - * Synthetic attribute. - */ - static class SyntheticAttribute extends Attribute { - SyntheticAttribute() { - super(SYNTHETIC); - } - - @Override - protected Attribute read(ClassReader cr, - int off, - int len, - char[] buf, - int codeOff, - Label[] labels) - { - return new SyntheticAttribute(); - } - - @Override - protected ByteVector write(ClassWriter cw, - byte[] code, - int len, - int maxStack, - int maxLocals) - { - ByteVector attr = new ByteVector(); - return attr; - } - } - - /** - * ConcealedPackages attribute. + * ModulePackages attribute. * *

     {@code
          *
    -     * ConcealedPackages_attribute {
    +     * ModulePackages_attribute {
          *   // index to CONSTANT_utf8_info structure in constant pool representing
    -     *   // the string "ConcealedPackages"
    +     *   // the string "ModulePackages"
          *   u2 attribute_name_index;
          *   u4 attribute_length;
          *
    @@ -288,15 +375,15 @@
          *
          * }
    */ - static class ConcealedPackagesAttribute extends Attribute { + public static class ModulePackagesAttribute extends Attribute { private final Set packages; - ConcealedPackagesAttribute(Set packages) { - super(CONCEALED_PACKAGES); + public ModulePackagesAttribute(Set packages) { + super(MODULE_PACKAGES); this.packages = packages; } - ConcealedPackagesAttribute() { + public ModulePackagesAttribute() { this(null); } @@ -320,7 +407,7 @@ off += 2; } - return new ConcealedPackagesAttribute(packages); + return new ModulePackagesAttribute(packages); } @Override @@ -348,13 +435,13 @@ } /** - * Version attribute. + * ModuleVersion attribute. * *
     {@code
          *
    -     * Version_attribute {
    +     * ModuleVersion_attribute {
          *   // index to CONSTANT_utf8_info structure in constant pool representing
    -     *   // the string "Version"
    +     *   // the string "ModuleVersion"
          *   u2 attribute_name_index;
          *   u4 attribute_length;
          *
    @@ -364,15 +451,15 @@
          *
          * } 
    */ - static class VersionAttribute extends Attribute { + public static class ModuleVersionAttribute extends Attribute { private final Version version; - VersionAttribute(Version version) { - super(VERSION); + public ModuleVersionAttribute(Version version) { + super(MODULE_VERSION); this.version = version; } - VersionAttribute() { + public ModuleVersionAttribute() { this(null); } @@ -385,7 +472,7 @@ Label[] labels) { String value = cr.readUTF8(off, buf); - return new VersionAttribute(Version.parse(value)); + return new ModuleVersionAttribute(Version.parse(value)); } @Override @@ -403,13 +490,13 @@ } /** - * MainClass attribute. + * ModuleMainClass attribute. * *
     {@code
          *
          * MainClass_attribute {
          *   // index to CONSTANT_utf8_info structure in constant pool representing
    -     *   // the string "MainClass"
    +     *   // the string "ModuleMainClass"
          *   u2 attribute_name_index;
          *   u4 attribute_length;
          *
    @@ -419,15 +506,15 @@
          *
          * } 
    */ - static class MainClassAttribute extends Attribute { + public static class ModuleMainClassAttribute extends Attribute { private final String mainClass; - MainClassAttribute(String mainClass) { - super(MAIN_CLASS); + public ModuleMainClassAttribute(String mainClass) { + super(MODULE_MAIN_CLASS); this.mainClass = mainClass; } - MainClassAttribute() { + public ModuleMainClassAttribute() { this(null); } @@ -440,7 +527,7 @@ Label[] labels) { String value = cr.readClass(off, buf); - return new MainClassAttribute(value); + return new ModuleMainClassAttribute(value); } @Override @@ -458,13 +545,13 @@ } /** - * TargetPlatform attribute. + * ModuleTarget attribute. * *
     {@code
          *
          * TargetPlatform_attribute {
          *   // index to CONSTANT_utf8_info structure in constant pool representing
    -     *   // the string "TargetPlatform"
    +     *   // the string "ModuleTarget"
          *   u2 attribute_name_index;
          *   u4 attribute_length;
          *
    @@ -478,19 +565,19 @@
          *
          * } 
    */ - static class TargetPlatformAttribute extends Attribute { + public static class ModuleTargetAttribute extends Attribute { private final String osName; private final String osArch; private final String osVersion; - TargetPlatformAttribute(String osName, String osArch, String osVersion) { - super(TARGET_PLATFORM); + public ModuleTargetAttribute(String osName, String osArch, String osVersion) { + super(MODULE_TARGET); this.osName = osName; this.osArch = osArch; this.osVersion = osVersion; } - TargetPlatformAttribute() { + public ModuleTargetAttribute() { this(null, null, null); } @@ -522,7 +609,7 @@ osVersion = cr.readUTF8(off, buf); off += 2; - return new TargetPlatformAttribute(osName, osArch, osVersion); + return new ModuleTargetAttribute(osName, osArch, osVersion); } @Override @@ -554,39 +641,37 @@ } /** - * Hashes attribute. + * ModuleHashes attribute. * *
     {@code
          *
    -     * Hashes_attribute {
    +     * ModuleHashes_attribute {
          *   // index to CONSTANT_utf8_info structure in constant pool representing
    -     *   // the string "Hashes"
    +     *   // the string "ModuleHashes"
          *   u2 attribute_name_index;
          *   u4 attribute_length;
          *
    -     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
    +     *   // index to CONSTANT_utf8_info structure with algorithm name
          *   u2 algorithm_index;
          *
          *   // the number of entries in the hashes table
    -     *   u2 hash_count;
    -     *   {   u2 requires_index
    -     *       u2 hash_index;
    -     *   } hashes[hash_count];
    +     *   u2 hashes_count;
    +     *   {   u2 module_name_index
    +     *       u2 hash_length;
    +     *       u1 hash[hash_length];
    +     *   } hashes[hashes_count];
          *
          * } 
    - * - * @apiNote For now the hash is stored in base64 as a UTF-8 string, an - * alternative is to store it as an array of u1. */ - static class HashesAttribute extends Attribute { + static class ModuleHashesAttribute extends Attribute { private final ModuleHashes hashes; - HashesAttribute(ModuleHashes hashes) { - super(HASHES); + ModuleHashesAttribute(ModuleHashes hashes) { + super(MODULE_HASHES); this.hashes = hashes; } - HashesAttribute() { + ModuleHashesAttribute() { this(null); } @@ -601,21 +686,28 @@ String algorithm = cr.readUTF8(off, buf); off += 2; - int hash_count = cr.readUnsignedShort(off); + int hashes_count = cr.readUnsignedShort(off); off += 2; - Map map = new HashMap<>(); - for (int i=0; i map = new HashMap<>(); + for (int i=0; i names = hashes.names(); attr.putShort(names.size()); - for (String dn : names) { - String hash = hashes.hashFor(dn); + for (String mn : names) { + byte[] hash = hashes.hashFor(mn); assert hash != null; - attr.putShort(cw.newUTF8(dn)); - attr.putShort(cw.newUTF8(hash)); + attr.putShort(cw.newUTF8(mn.replace('.', '/'))); + + attr.putShort(hash.length); + for (byte b: hash) { + attr.putByte(b); + } } return attr; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java Thu Dec 01 08:57:53 2016 +0000 @@ -35,19 +35,20 @@ // Attribute names public static final String MODULE = "Module"; public static final String SOURCE_FILE = "SourceFile"; - public static final String SYNTHETIC = "Synthetic"; public static final String SDE = "SourceDebugExtension"; - public static final String CONCEALED_PACKAGES = "ConcealedPackages"; - public static final String VERSION = "Version"; - public static final String MAIN_CLASS = "MainClass"; - public static final String TARGET_PLATFORM = "TargetPlatform"; - public static final String HASHES = "Hashes"; + public static final String MODULE_PACKAGES = "ModulePackages"; + public static final String MODULE_VERSION = "ModuleVersion"; + public static final String MODULE_MAIN_CLASS = "ModuleMainClass"; + public static final String MODULE_TARGET = "ModuleTarget"; + public static final String MODULE_HASHES = "ModuleHashes"; - // access and requires flags - public static final int ACC_MODULE = 0x8000; - public static final int ACC_PUBLIC = 0x0020; - public static final int ACC_SYNTHETIC = 0x1000; - public static final int ACC_MANDATED = 0x8000; + // access, requires, exports, and opens flags + public static final int ACC_MODULE = 0x8000; + public static final int ACC_OPEN = 0x0020; + public static final int ACC_TRANSITIVE = 0x0010; + public static final int ACC_STATIC_PHASE = 0x0020; + public static final int ACC_SYNTHETIC = 0x1000; + public static final int ACC_MANDATED = 0x8000; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Thu Dec 01 08:57:53 2016 +0000 @@ -37,9 +37,11 @@ import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -81,10 +83,20 @@ // the token for "all modules on the module path" private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; + // The ModulePatcher for the initial configuration + private static final ModulePatcher patcher = initModulePatcher(); + // ModuleFinder for the initial configuration private static ModuleFinder initialFinder; /** + * Returns the ModulePatcher for the initial configuration. + */ + public static ModulePatcher patcher() { + return patcher; + } + + /** * Returns the ModuleFinder for the initial configuration */ public static ModuleFinder finder() { @@ -101,7 +113,7 @@ long t0 = System.nanoTime(); - // system modules + // system modules (may be patched) ModuleFinder systemModules = ModuleFinder.ofSystem(); PerfCounters.systemModulesTime.addElapsedTimeFrom(t0); @@ -247,7 +259,7 @@ if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here && (upgradeModulePath == null) && (appModulePath == null) - && (!ModulePatcher.isBootLayerPatched())) { + && (patcher.isEmpty())) { needPostResolutionChecks = false; } @@ -314,9 +326,9 @@ PerfCounters.loadModulesTime.addElapsedTimeFrom(t5); - // --add-reads and --add-exports + // --add-reads, -add-exports/-add-opens addExtraReads(bootLayer); - addExtraExports(bootLayer); + addExtraExportsAndOpens(bootLayer); // total time to initialize PerfCounters.bootstrapTime.addElapsedTimeFrom(t0); @@ -389,6 +401,18 @@ } } + + /** + * Initialize the module patcher for the initial configuration passed on the + * value of the --patch-module options. + */ + private static ModulePatcher initModulePatcher() { + Map> map = decode("jdk.module.patch.", + File.pathSeparator, + false); + return new ModulePatcher(map); + } + /** * Returns the set of module names specified via --add-modules options * on the command line @@ -408,7 +432,6 @@ for (String s : value.split(",")) { if (s.length() > 0) modules.add(s); } - index++; value = getAndRemoveProperty(prefix + index); } @@ -423,9 +446,11 @@ private static void addExtraReads(Layer bootLayer) { // decode the command line options - Map> map = decode("jdk.module.addreads."); + Map> map = decode("jdk.module.addreads."); + if (map.isEmpty()) + return; - for (Map.Entry> e : map.entrySet()) { + for (Map.Entry> e : map.entrySet()) { // the key is $MODULE String mn = e.getKey(); @@ -448,22 +473,36 @@ warn("Unknown module: " + name); } } - } } } - /** - * Process the --add-exports options to add any additional read edges that - * are specified on the command-line. + * Process the --add-exports and --add-opens options to export/open + * additional packages specified on the command-line. */ - private static void addExtraExports(Layer bootLayer) { + private static void addExtraExportsAndOpens(Layer bootLayer) { + + // --add-exports + String prefix = "jdk.module.addexports."; + Map> extraExports = decode(prefix); + if (!extraExports.isEmpty()) { + addExtraExportsOrOpens(bootLayer, extraExports, false); + } - // decode the command line options - Map> map = decode("jdk.module.addexports."); + // --add-opens + prefix = "jdk.module.addopens."; + Map> extraOpens = decode(prefix); + if (!extraOpens.isEmpty()) { + addExtraExportsOrOpens(bootLayer, extraOpens, true); + } + } - for (Map.Entry> e : map.entrySet()) { + private static void addExtraExportsOrOpens(Layer bootLayer, + Map> map, + boolean opens) + { + for (Map.Entry> e : map.entrySet()) { // the key is $MODULE/$PACKAGE String key = e.getKey(); @@ -507,28 +546,40 @@ } } if (allUnnamed) { - Modules.addExportsToAllUnnamed(m, pn); + if (opens) { + Modules.addOpensToAllUnnamed(m, pn); + } else { + Modules.addExportsToAllUnnamed(m, pn); + } } else { - Modules.addExports(m, pn, other); + if (opens) { + Modules.addOpens(m, pn, other); + } else { + Modules.addExports(m, pn, other); + } } + } } } - /** - * Decodes the values of --add-reads or --add-exports options + * Decodes the values of --add-reads, -add-exports, --add-opens or + * --patch-modules options that are encoded in system properties. * - * The format of the options is: $KEY=$MODULE(,$MODULE)* + * @param prefix the system property prefix + * @praam regex the regex for splitting the RHS of the option value */ - private static Map> decode(String prefix) { + private static Map> decode(String prefix, + String regex, + boolean allowDuplicates) { int index = 0; // the system property is removed after decoding String value = getAndRemoveProperty(prefix + index); if (value == null) return Collections.emptyMap(); - Map> map = new HashMap<>(); + Map> map = new HashMap<>(); while (value != null) { @@ -545,8 +596,11 @@ if (rhs.isEmpty()) fail("Unable to parse: " + value); - Set values = map.computeIfAbsent(key, k -> new HashSet<>()); - for (String s : rhs.split(",")) { + // value is (,)* or ()* + if (!allowDuplicates && map.containsKey(key)) + fail(key + " specified more than once"); + List values = map.computeIfAbsent(key, k -> new ArrayList<>()); + for (String s : rhs.split(regex)) { if (s.length() > 0) values.add(s); } @@ -558,6 +612,14 @@ } /** + * Decodes the values of --add-reads, -add-exports or --add-opens + * which use the "," to separate the RHS of the option value. + */ + private static Map> decode(String prefix) { + return decode(prefix, ",", true); + } + + /** * Gets and remove the named system property */ private static String getAndRemoveProperty(String key) { diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,7 +32,6 @@ import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.Base64; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -45,23 +44,23 @@ public final class ModuleHashes { /** - * A supplier of an encoded message digest. + * A supplier of a message digest. */ public static interface HashSupplier { - String generate(String algorithm); + byte[] generate(String algorithm); } private final String algorithm; - private final Map nameToHash; + private final Map nameToHash; /** * Creates a {@code ModuleHashes}. * * @param algorithm the algorithm used to create the hashes - * @param nameToHash the map of module name to hash value (in string form) + * @param nameToHash the map of module name to hash value */ - public ModuleHashes(String algorithm, Map nameToHash) { + public ModuleHashes(String algorithm, Map nameToHash) { this.algorithm = algorithm; this.nameToHash = Collections.unmodifiableMap(nameToHash); } @@ -81,28 +80,28 @@ } /** - * Returns the hash string for the given module name, {@code null} + * Returns the hash for the given module name, {@code null} * if there is no hash recorded for the module. */ - public String hashFor(String mn) { + public byte[] hashFor(String mn) { return nameToHash.get(mn); } /** - * Returns unmodifiable map of module name to hash string. + * Returns unmodifiable map of module name to hash */ - public Map hashes() { + public Map hashes() { return nameToHash; } /** * Computes the hash for the given file with the given message digest - * algorithm. Returns the results a base64-encoded String. + * algorithm. * * @throws UncheckedIOException if an I/O error occurs * @throws RuntimeException if the algorithm is not available */ - public static String computeHashAsString(Path file, String algorithm) { + public static byte[] computeHash(Path file, String algorithm) { try { MessageDigest md = MessageDigest.getInstance(algorithm); @@ -118,8 +117,7 @@ } } - byte[] bytes = md.digest(); - return Base64.getEncoder().encodeToString(bytes); + return md.digest(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } catch (IOException ioe) { @@ -133,14 +131,14 @@ * the entry name, typically the module name. The map value is the file * path to the entry (module artifact). * - * @return ModuleHashes encapsulate the hashes + * @return ModuleHashes that encapsulates the hashes */ public static ModuleHashes generate(Map map, String algorithm) { - Map nameToHash = new HashMap<>(); + Map nameToHash = new HashMap<>(); for (Map.Entry entry: map.entrySet()) { String name = entry.getKey(); Path path = entry.getValue(); - nameToHash.put(name, computeHashAsString(path, algorithm)); + nameToHash.put(name, computeHash(path, algorithm)); } return new ModuleHashes(algorithm, nameToHash); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java Thu Dec 01 08:57:53 2016 +0000 @@ -53,8 +53,8 @@ // the input stream to read the original module-info.class private final InputStream in; - // the packages in the ConcealedPackages attribute - private Set conceals; + // the packages in the Packages attribute + private Set packages; // the value of the Version attribute private Version version; @@ -75,10 +75,10 @@ } /** - * Sets the set of packages for the ConcealedPackages attribute + * Sets the set of packages for the Packages attribute */ - public ModuleInfoExtender conceals(Set packages) { - this.conceals = Collections.unmodifiableSet(packages); + public ModuleInfoExtender packages(Set packages) { + this.packages = Collections.unmodifiableSet(packages); return this; } @@ -181,26 +181,26 @@ ClassReader cr = new ClassReader(in); - if (conceals != null) - cv.addAttribute(new ConcealedPackagesAttribute(conceals)); + if (packages != null) + cv.addAttribute(new ModulePackagesAttribute(packages)); if (version != null) - cv.addAttribute(new VersionAttribute(version)); + cv.addAttribute(new ModuleVersionAttribute(version)); if (mainClass != null) - cv.addAttribute(new MainClassAttribute(mainClass)); + cv.addAttribute(new ModuleMainClassAttribute(mainClass)); if (osName != null || osArch != null || osVersion != null) - cv.addAttribute(new TargetPlatformAttribute(osName, osArch, osVersion)); + cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion)); if (hashes != null) - cv.addAttribute(new HashesAttribute(hashes)); + cv.addAttribute(new ModuleHashesAttribute(hashes)); List attrs = new ArrayList<>(); // prototypes of attributes that should be parsed attrs.add(new ModuleAttribute()); - attrs.add(new ConcealedPackagesAttribute()); - attrs.add(new VersionAttribute()); - attrs.add(new MainClassAttribute()); - attrs.add(new TargetPlatformAttribute()); - attrs.add(new HashesAttribute()); + attrs.add(new ModulePackagesAttribute()); + attrs.add(new ModuleVersionAttribute()); + attrs.add(new ModuleMainClassAttribute()); + attrs.add(new ModuleTargetAttribute()); + attrs.add(new ModuleHashesAttribute()); cr.accept(cv, attrs.toArray(new Attribute[0]), 0); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,9 +27,8 @@ import java.io.IOException; import java.io.OutputStream; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Version; import java.nio.ByteBuffer; -import java.util.Optional; +import java.util.stream.Stream; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Opcodes; @@ -52,31 +51,28 @@ private static byte[] toModuleInfo(ModuleDescriptor md) { ClassWriter cw = new ClassWriter(0); - - String name = md.name().replace('.', '/') + "/module-info"; - cw.visit(Opcodes.V1_9, ACC_MODULE, name, null, null, null); - + cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null); cw.visitAttribute(new ModuleAttribute(md)); - // for tests: write the ConcealedPackages attribute when there are non-exported packages - long nExportedPackages = md.exports().stream() - .map(ModuleDescriptor.Exports::source) - .distinct() - .count(); - if (md.packages().size() > nExportedPackages) - cw.visitAttribute(new ConcealedPackagesAttribute(md.packages())); + // for tests: write the Packages attribute when there are packages that + // aren't exported or open + Stream exported = md.exports().stream() + .map(ModuleDescriptor.Exports::source); + Stream open = md.opens().stream() + .map(ModuleDescriptor.Opens::source); + long exportedOrOpen = Stream.concat(exported, open).distinct().count(); + if (md.packages().size() > exportedOrOpen) + cw.visitAttribute(new ModulePackagesAttribute(md.packages())); - md.version().ifPresent(v -> cw.visitAttribute(new VersionAttribute(v))); - md.mainClass().ifPresent(mc -> cw.visitAttribute(new MainClassAttribute(mc))); + md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v))); + md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc))); // write the TargetPlatform attribute if have any of OS name/arch/version String osName = md.osName().orElse(null); String osArch = md.osArch().orElse(null); String osVersion = md.osVersion().orElse(null); if (osName != null || osArch != null || osVersion != null) { - cw.visitAttribute(new TargetPlatformAttribute(osName, - osArch, - osVersion)); + cw.visitAttribute(new ModuleTargetAttribute(osName, osArch, osVersion)); } cw.visitEnd(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Thu Dec 01 08:57:53 2016 +0000 @@ -50,6 +50,7 @@ import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.loader.Resource; @@ -59,7 +60,7 @@ /** - * Provides support for patching modules in the boot layer with --patch-module. + * Provides support for patching modules, mostly the boot layer. */ public final class ModulePatcher { @@ -67,89 +68,46 @@ private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); - // the prefix of the system properties that encode the value of --patch-module - private static final String PATCH_PROPERTY_PREFIX = "jdk.module.patch."; - // module name -> sequence of patches (directories or JAR files) - private static final Map> PATCH_MAP = decodeProperties(); - - private ModulePatcher() { } + private final Map> map; /** - * Decodes the values of --patch-module options, returning a Map of module - * name to list of file paths. - * - * @throws IllegalArgumentException if the the module name is missing or - * --patch-module is used more than once to patch the same module + * Initialize the module patcher with the given map. The map key is + * the module name, the value is a list of path strings. */ - private static Map> decodeProperties() { - - int index = 0; - String value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index); - if (value == null) - return Collections.emptyMap(); // --patch-module not specified - - Map> map = new HashMap<>(); - while (value != null) { - - // =(:)* - - int pos = value.indexOf('='); - if (pos == -1) - throwIAE("Unable to parse: " + value); - if (pos == 0) - throwIAE("Missing module name: " + value); - - String mn = value.substring(0, pos); - List list = map.get(mn); - if (list != null) - throwIAE("Module " + mn + " specified more than once"); - list = new ArrayList<>(); - map.put(mn, list); - - String paths = value.substring(pos+1); - for (String path : paths.split(File.pathSeparator)) { - if (!path.isEmpty()) { - list.add(Paths.get(path)); - } + public ModulePatcher(Map> input) { + if (input.isEmpty()) { + this.map = Collections.emptyMap(); + } else { + Map> map = new HashMap<>(); + for (Map.Entry> e : input.entrySet()) { + String mn = e.getKey(); + List paths = e.getValue().stream() + .map(Paths::get) + .collect(Collectors.toList()); + map.put(mn, paths); } - - index++; - value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index); + this.map = map; } - - return map; - } - - - /** - * Returns {@code true} is --patch-module is specified to patch modules - * in the boot layer. - */ - static boolean isBootLayerPatched() { - return !PATCH_MAP.isEmpty(); } /** * Returns a module reference that interposes on the given module if * needed. If there are no patches for the given module then the module * reference is simply returned. Otherwise the patches for the module - * are scanned (to find any new concealed packages) and a new module - * reference is returned. + * are scanned (to find any new packages) and a new module reference is + * returned. * * @throws UncheckedIOException if an I/O error is detected */ - public static ModuleReference interposeIfNeeded(ModuleReference mref) { - + public ModuleReference patchIfNeeded(ModuleReference mref) { + // if there are no patches for the module then nothing to do ModuleDescriptor descriptor = mref.descriptor(); String mn = descriptor.name(); - - // if there are no patches for the module then nothing to do - List paths = PATCH_MAP.get(mn); + List paths = map.get(mn); if (paths == null) return mref; - // scan the JAR file or directory tree to get the set of packages Set packages = new HashSet<>(); try { @@ -197,6 +155,13 @@ } + /** + * Returns true is this module patcher has no patches. + */ + public boolean isEmpty() { + return map.isEmpty(); + } + /** * A ModuleReader that reads resources from a patched module. @@ -569,13 +534,6 @@ } /** - * Gets and remove the named system property - */ - private static String getAndRemoveProperty(String key) { - return (String)System.getProperties().remove(key); - } - - /** * Derives a package name from the name of an entry in a JAR file. */ private static String toPackageName(Path file, JarEntry entry) { @@ -593,9 +551,4 @@ System.err.println("WARNING: " + e + " ignored in patch: " + file); return ""; } - - private static void throwIAE(String msg) { - throw new IllegalArgumentException(msg); - } - } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/Modules.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,8 +26,11 @@ package jdk.internal.module; import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Layer; import java.lang.reflect.Module; import java.net.URI; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Set; import jdk.internal.loader.BootLoader; @@ -35,7 +38,6 @@ import jdk.internal.misc.JavaLangReflectModuleAccess; import jdk.internal.misc.SharedSecrets; - /** * A helper class to allow JDK classes create dynamic modules and to update * modules, exports and the readability graph. It is also invoked by the VM @@ -53,7 +55,6 @@ private static final JavaLangReflectModuleAccess JLRMA = SharedSecrets.getJavaLangReflectModuleAccess(); - /** * Creates a new Module. The module has the given ModuleDescriptor and * is defined to the given class loader. @@ -72,7 +73,7 @@ /** * Define a new module to the VM. The module has the given set of - * concealed packages and is defined to the given class loader. + * packages and is defined to the given class loader. * * The resulting Module is in a larval state in that it does not not read * any other module and does not have any exports. @@ -81,8 +82,9 @@ String name, Set packages) { - ModuleDescriptor descriptor - = new ModuleDescriptor.Builder(name).conceals(packages).build(); + ModuleDescriptor descriptor = ModuleDescriptor.module(name) + .contains(packages) + .build(); return JLRMA.defineModule(loader, descriptor, null); } @@ -104,13 +106,21 @@ /** * Updates module m1 to export a package to module m2. - * Same as m1.addExports(pkg, m2) but without a caller check. + * Same as m1.addExports(pn, m2) but without a caller check. */ public static void addExports(Module m1, String pn, Module m2) { JLRMA.addExports(m1, pn, m2); } /** + * Updates module m1 to open a package to module m2. + * Same as m1.addOpens(pn, m2) but without a caller check. + */ + public static void addOpens(Module m1, String pn, Module m2) { + JLRMA.addOpens(m1, pn, m2); + } + + /** * Updates a module m to export a package to all modules. */ public static void addExportsToAll(Module m, String pn) { @@ -118,6 +128,13 @@ } /** + * Updates a module m to open a package to all modules. + */ + public static void addOpensToAll(Module m, String pn) { + JLRMA.addOpensToAll(m, pn); + } + + /** * Updates module m to export a package to all unnamed modules. */ public static void addExportsToAllUnnamed(Module m, String pn) { @@ -125,6 +142,47 @@ } /** + * Updates module m to open a package to all unnamed modules. + */ + public static void addOpensToAllUnnamed(Module m, String pn) { + JLRMA.addOpensToAllUnnamed(m, pn); + } + + /** + * Updates module m to use a service + */ + public static void addUses(Module m, Class service) { + JLRMA.addUses(m, service); + } + + /** + * Updates module m to provide a service + */ + public static void addProvides(Module m, Class service, Class impl) { + Layer layer = m.getLayer(); + + if (layer == null || layer == Layer.boot()) { + // update ClassLoader catalog + PrivilegedAction pa = m::getClassLoader; + ClassLoader loader = AccessController.doPrivileged(pa); + ServicesCatalog catalog; + if (loader == null) { + catalog = BootLoader.getServicesCatalog(); + } else { + catalog = ServicesCatalog.getServicesCatalog(loader); + } + catalog.addProvider(m, service, impl); + } + + if (layer != null) { + // update Layer catalog + SharedSecrets.getJavaLangReflectModuleAccess() + .getServicesCatalog(layer) + .addProvider(m, service, impl); + } + } + + /** * Adds a package to a module's content. * * This method is a no-op if the module already contains the package. @@ -142,5 +200,4 @@ addReads(m, BootLoader.getUnnamedModule()); addReads(m, ClassLoaders.appClassLoader().getUnnamedModule()); } - } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,20 +28,24 @@ import java.lang.reflect.Module; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Provides; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import jdk.internal.loader.ClassLoaderValue; /** * A services catalog. Each {@code ClassLoader} and {@code Layer} has * an optional {@code ServicesCatalog} for modules that provide services. * - * @see java.util.ServiceLoader + * @apiNote This class will be replaced once the ServiceLoader is further + * specified */ -public interface ServicesCatalog { +public final class ServicesCatalog { /** * Represents a service provider in the services catalog. @@ -78,56 +82,98 @@ } } - /** - * Registers the providers in the given module in this services catalog. - * - * @throws UnsupportedOperationException - * If this services catalog is immutable - */ - void register(Module module); + // service name -> list of providers + private final Map> map = new ConcurrentHashMap<>(); - /** - * Returns the (possibly empty) set of service providers that implement the - * given service type. - */ - Set findServices(String service); + private ServicesCatalog() { } /** * Creates a ServicesCatalog that supports concurrent registration and - * and lookup. + * and lookup + */ + public static ServicesCatalog create() { + return new ServicesCatalog(); + } + + /** + * Returns the list of service provides for the given service type + * name, creating it if needed. */ - static ServicesCatalog create() { - return new ServicesCatalog() { - - private Map> map = new ConcurrentHashMap<>(); + private List providers(String service) { + // avoid computeIfAbsent here + List list = map.get(service); + if (list == null) { + list = new CopyOnWriteArrayList<>(); + List prev = map.putIfAbsent(service, list); + if (prev != null) + list = prev; // someone else got there + } + return list; + } - @Override - public void register(Module m) { - ModuleDescriptor descriptor = m.getDescriptor(); - - for (Provides provides : descriptor.provides().values()) { - String service = provides.service(); - Set providerNames = provides.providers(); + /** + * Registers the providers in the given module in this services catalog. + */ + public void register(Module module) { + ModuleDescriptor descriptor = module.getDescriptor(); + for (Provides provides : descriptor.provides()) { + String service = provides.service(); + List providerNames = provides.providers(); + int count = providerNames.size(); + if (count == 1) { + String pn = providerNames.get(0); + providers(service).add(new ServiceProvider(module, pn)); + } else { + List list = new ArrayList<>(count); + for (String pn : providerNames) { + list.add(new ServiceProvider(module, pn)); + } + providers(service).addAll(list); + } + } + } - // create a new set to replace the existing - Set result = new HashSet<>(); - Set providers = map.get(service); - if (providers != null) { - result.addAll(providers); - } - for (String pn : providerNames) { - result.add(new ServiceProvider(m, pn)); - } - map.put(service, Collections.unmodifiableSet(result)); - } + /** + * Add a provider in the given module to this services catalog + * + * @apiNote This method is for use by java.lang.instrument + */ + public void addProvider(Module module, Class service, Class impl) { + List list = providers(service.getName()); + list.add(new ServiceProvider(module, impl.getName())); + } + + /** + * Returns the (possibly empty) list of service providers that implement + * the given service type. + */ + public List findServices(String service) { + return map.getOrDefault(service, Collections.emptyList()); + } - } + /** + * Returns the ServicesCatalog for the given class loader or {@code null} + * if there is none. + */ + public static ServicesCatalog getServicesCatalogOrNull(ClassLoader loader) { + return CLV.get(loader); + } - @Override - public Set findServices(String service) { - return map.getOrDefault(service, Collections.emptySet()); - } + /** + * Returns the ServicesCatalog for the given class loader, creating it if + * needed. + */ + public static ServicesCatalog getServicesCatalog(ClassLoader loader) { + // CLV.computeIfAbsent(loader, (cl, clv) -> create()); + ServicesCatalog catalog = CLV.get(loader); + if (catalog == null) { + catalog = create(); + ServicesCatalog previous = CLV.putIfAbsent(loader, catalog); + if (previous != null) catalog = previous; + } + return catalog; + } - }; - } + // the ServicesCatalog registered to a class loader + private static final ClassLoaderValue CLV = new ClassLoaderValue<>(); } \ No newline at end of file diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Thu Dec 01 08:57:53 2016 +0000 @@ -51,7 +51,7 @@ /** * Hash of system modules. */ - public static String[] MODULES_TO_HASH = new String[0]; + public static byte[][] MODULES_TO_HASH = new byte[0][]; /** * Number of packages in the boot layer from the installed modules. diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java Thu Dec 01 08:57:53 2016 +0000 @@ -695,7 +695,7 @@ final String[] interfaces) { this.version = version; this.access = access; - this.name = newClass(name); + this.name = (name == null) ? 0 : newClass(name); thisName = name; if (ClassReader.SIGNATURES && signature != null) { this.signature = newUTF8(signature); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java Thu Dec 01 08:57:53 2016 +0000 @@ -112,10 +112,13 @@ } } - private static boolean verifyMemberAccess(Class currentClass, - Class memberClass, - Class targetClass, - int modifiers) + /** + * Verify access to a member, returning {@code false} if no access + */ + public static boolean verifyMemberAccess(Class currentClass, + Class memberClass, + Class targetClass, + int modifiers) { // Verify that currentClass can access a field, method, or // constructor of memberClass, where that member's access bits are diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/module-info.java --- a/jdk/src/java.base/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -115,16 +115,16 @@ // additional qualified exports may be inserted at build time // see make/gensrc/GenModuleInfo.gmk - // CORBA serialization needs reflective access - exports sun.util.calendar to - java.corba; - exports com.sun.security.ntlm to java.security.sasl; exports jdk.internal.jimage to jdk.jlink; exports jdk.internal.jimage.decompressor to jdk.jlink; + exports jdk.internal.loader to + java.instrument, + java.logging, + jdk.jlink; exports jdk.internal.jmod to jdk.compiler, jdk.jlink; @@ -146,9 +146,6 @@ jdk.scripting.nashorn; exports jdk.internal.org.objectweb.asm.signature to jdk.scripting.nashorn; - exports jdk.internal.loader to - java.instrument, - java.logging; exports jdk.internal.math to java.desktop; exports jdk.internal.module to @@ -307,6 +304,7 @@ // JDK-internal service types uses jdk.internal.logger.DefaultLoggerFinder; uses sun.security.ssl.ClientKeyExchangeService; + uses sun.security.util.AuthResourcesProvider; uses sun.util.spi.CalendarProvider; uses sun.util.locale.provider.LocaleDataMetaInfo; uses sun.util.resources.LocaleData.CommonResourceBundleProvider; @@ -317,4 +315,6 @@ provides java.nio.file.spi.FileSystemProvider with jdk.internal.jrtfs.JrtFileSystemProvider; + provides sun.security.util.AuthResourcesProvider with + sun.security.util.AuthResourcesProviderImpl; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java --- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java Thu Dec 01 08:57:53 2016 +0000 @@ -48,6 +48,7 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Provides; import java.lang.reflect.Layer; import java.lang.reflect.Method; @@ -62,24 +63,29 @@ import java.nio.file.Path; import java.text.Normalizer; import java.text.MessageFormat; -import java.util.ResourceBundle; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Locale.Category; +import java.util.Map; import java.util.Optional; import java.util.Properties; -import java.util.Map; +import java.util.ResourceBundle; import java.util.Set; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import jdk.internal.misc.VM; +import jdk.internal.module.Modules; public final class LauncherHelper { @@ -95,6 +101,8 @@ private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX = "sun.launcher.LauncherHelper$FXHelper"; private static final String MAIN_CLASS = "Main-Class"; + private static final String ADD_EXPORTS = "Add-Exports"; + private static final String ADD_OPENS = "Add-Opens"; private static StringBuilder outBuf = new StringBuilder(); @@ -413,11 +421,23 @@ if (mainAttrs == null) { abort(null, "java.launcher.jar.error3", jarname); } + + // Main-Class mainValue = mainAttrs.getValue(MAIN_CLASS); if (mainValue == null) { abort(null, "java.launcher.jar.error3", jarname); } + // Add-Exports and Add-Opens to break encapsulation + String exports = mainAttrs.getValue(ADD_EXPORTS); + if (exports != null) { + addExportsOrOpens(exports, false); + } + String opens = mainAttrs.getValue(ADD_OPENS); + if (opens != null) { + addExportsOrOpens(opens, true); + } + /* * Hand off to FXHelper if it detects a JavaFX application * This must be done after ensuring a Main-Class entry @@ -436,6 +456,29 @@ return null; } + /** + * Process the Add-Exports or Add-Opens value. The value is + * {@code / ( /)*}. + */ + static void addExportsOrOpens(String value, boolean open) { + for (String moduleAndPackage : value.split(" ")) { + String[] s = moduleAndPackage.trim().split("/"); + if (s.length == 2) { + String mn = s[0]; + String pn = s[1]; + Layer.boot().findModule(mn).ifPresent(m -> { + if (m.getDescriptor().packages().contains(pn)) { + if (open) { + Modules.addOpensToAllUnnamed(m, pn); + } else { + Modules.addExportsToAllUnnamed(m, pn); + } + } + }); + } + } + } + // From src/share/bin/java.c: // enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR, LM_MODULE } @@ -899,12 +942,26 @@ for (String name: names) { ModuleReference mref = finder.find(name).orElse(null); if (mref == null) { - // not found + System.err.format("%s not observable!%n", name); continue; } ModuleDescriptor md = mref.descriptor(); - ostream.println(midAndLocation(md, mref.location())); + if (md.isOpen()) + ostream.print("open "); + if (md.isAutomatic()) + ostream.print("automatic "); + ostream.println("module " + midAndLocation(md, mref.location())); + + // unqualified exports (sorted by package) + Set exports = new TreeSet<>(Comparator.comparing(Exports::source)); + md.exports().stream().filter(e -> !e.isQualified()).forEach(exports::add); + for (Exports e : exports) { + String modsAndSource = Stream.concat(toStringStream(e.modifiers()), + Stream.of(e.source())) + .collect(Collectors.joining(" ")); + ostream.format(" exports %s%n", modsAndSource); + } for (Requires d : md.requires()) { ostream.format(" requires %s%n", d); @@ -913,31 +970,51 @@ ostream.format(" uses %s%n", s); } - // sorted exports - Set exports = new TreeSet<>(Comparator.comparing(Exports::source)); - exports.addAll(md.exports()); - for (Exports e : exports) { - ostream.format(" exports %s", e.source()); + for (Provides ps : md.provides()) { + ostream.format(" provides %s with %s%n", ps.service(), + ps.providers().stream().collect(Collectors.joining(", "))); + } + + // qualified exports + for (Exports e : md.exports()) { if (e.isQualified()) { + String modsAndSource = Stream.concat(toStringStream(e.modifiers()), + Stream.of(e.source())) + .collect(Collectors.joining(" ")); + ostream.format(" exports %s", modsAndSource); formatCommaList(ostream, " to", e.targets()); - } else { - ostream.println(); } } - // concealed packages - new TreeSet<>(md.conceals()) - .forEach(p -> ostream.format(" conceals %s%n", p)); + // open packages + for (Opens obj: md.opens()) { + String modsAndSource = Stream.concat(toStringStream(obj.modifiers()), + Stream.of(obj.source())) + .collect(Collectors.joining(" ")); + ostream.format(" opens %s", modsAndSource); + if (obj.isQualified()) + formatCommaList(ostream, " to", obj.targets()); + else + ostream.println(); + } - Map provides = md.provides(); - for (Provides ps : provides.values()) { - for (String impl : ps.providers()) - ostream.format(" provides %s with %s%n", ps.service(), impl); - } + // non-exported/non-open packages + Set concealed = new TreeSet<>(md.packages()); + md.exports().stream().map(Exports::source).forEach(concealed::remove); + md.opens().stream().map(Opens::source).forEach(concealed::remove); + concealed.forEach(p -> ostream.format(" contains %s%n", p)); } } } + static String toString(Set s) { + return toStringStream(s).collect(Collectors.joining(" ")); + } + + static Stream toStringStream(Set s) { + return s.stream().map(e -> e.toString().toLowerCase()); + } + static String midAndLocation(ModuleDescriptor md, Optional location ) { URI loc = location.orElse(null); if (loc == null || loc.getScheme().equalsIgnoreCase("jrt")) diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Thu Dec 01 08:57:53 2016 +0000 @@ -28,8 +28,8 @@ \ (to execute a class)\n or {0} [options] -jar jarfile [args...]\n\ \ (to execute a jar file)\n\ \ or {0} [options] -p -m [/] [args...]\n\ -\ (to execute the main class in a module)\n\ -where options include:\n +\ (to execute the main class in a module)\n\n\ +where options include:\n\n java.launcher.opt.datamodel =\ -d{0}\t Deprecated, will be removed in a future release\n java.launcher.opt.vmselect =\ {0}\t to select the "{1}" VM\n @@ -68,11 +68,16 @@ \ set a system property\n\ \ -verbose:[class|gc|jni]\n\ \ enable verbose output\n\ -\ -version print product version and exit\n\ -\ -showversion print product version and continue\n\ -\ -? -help --help\n\ -\ print this help message\n\ -\ -X print help on non-standard options\n\ +\ -version print product version to the error stream and exit\n\ +\ --version print product version to the output stream and exit\n\ +\ -showversion print product version to the error stream and continue\n\ +\ --show-version\n\ +\ print product version to the output stream and continue\n\ +\ -? -h -help\n\ +\ print this help message to the error stream\n\ +\ --help print this help message to the output stream\n\ +\ -X print help on extra options to the error stream\n\ +\ --help-extra print help on extra options to the output stream\n\ \ -ea[:...|:]\n\ \ -enableassertions[:...|:]\n\ \ enable assertions with specified granularity\n\ @@ -98,14 +103,12 @@ \ The most appropriate scaled image provided will be picked up\n\ \ automatically.\n\ \ See the SplashScreen API documentation for more information.\n\ -\ @ read options from the specified file\n\ +\ @ read options from the specified file\n\n\ \To specify an argument for a long option, you can use --= or\n\ -\-- .\n\ - -See http://www.oracle.com/technetwork/java/javase/documentation/index.html for more details. +\-- .\n # Translators please note do not translate the options themselves -java.launcher.X.usage=\ +java.launcher.X.usage=\n\ \ -Xbatch disable background compilation\n\ \ -Xbootclasspath/a:\n\ \ append to end of bootstrap class path\n\ @@ -152,10 +155,13 @@ \ regardless of module declaration.\n\ \ can be ALL-UNNAMED to export to all\n\ \ unnamed modules.\n\ +\ --add-opens /=(,)*\n\ +\ updates to open to\n\ +\ , regardless of module declaration.\n\ \ --patch-module =({0})*\n\ \ Override or augment a module with classes and resources\n\ \ in JAR files or directories.\n\n\ -These options are non-standard and subject to change without notice.\n +These extra options are subject to change without notice.\n # Translators please note do not translate the options themselves java.launcher.X.macosx.usage=\ diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +public interface AuthResourcesProvider extends java.util.spi.ResourceBundleProvider { +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +import java.util.spi.AbstractResourceBundleProvider; + +public final class AuthResourcesProviderImpl extends AbstractResourceBundleProvider + implements AuthResourcesProvider { + public AuthResourcesProviderImpl() { + super("java.class"); + } +} \ No newline at end of file diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.util.locale.provider; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.lang.reflect.Module; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.PropertyResourceBundle; -import java.util.ResourceBundle; - -/** - * ResourceBundleProviderSupport provides convenience methods for loading - * resource bundles. - */ -public class ResourceBundleProviderSupport { - /** - * Loads a {@code ResourceBundle} of the given {@code bundleName} local to - * the given {@code module}. - * - * @apiNote - * {@link Class#forName(Module, String)} does a stack-based permission check. - * Caller of this method is responsible for doing an appropriate permission - * on behalf of the caller before calling this method. - * - * @param module the module from which the {@code ResourceBundle} is loaded - * @param bundleName the bundle name for the {@code ResourceBundle} class, - * such as "com.example.app.MyResources_fr" - * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found - * @throws SecurityException - * if a security manager exists, it denies loading the class given by - * {@code bundleName} from the given {@code module}. - * If the given module is "java.base", this method will not do security check. - * @throws NullPointerException - * if {@code module} or {@code bundleName) is null - * @see Class#forName(Module, String) - */ - public static ResourceBundle loadResourceBundle(Module module, String bundleName) - { - Class c = Class.forName(module, bundleName); - if (c != null && ResourceBundle.class.isAssignableFrom(c)) { - try { - @SuppressWarnings("unchecked") - Class bundleClass = (Class) c; - Constructor ctor = bundleClass.getConstructor(); - if (!Modifier.isPublic(ctor.getModifiers())) { - return null; - } - // java.base may not be able to read the bundleClass's module. - PrivilegedAction pa1 = () -> { ctor.setAccessible(true); return null; }; - AccessController.doPrivileged(pa1); - try { - return ctor.newInstance((Object[]) null); - } catch (InvocationTargetException e) { - uncheckedThrow(e); - } catch (InstantiationException | IllegalAccessException e) { - throw new InternalError(e); - } - } catch (NoSuchMethodException e) { - } - } - return null; - } - - @SuppressWarnings("unchecked") - private static void uncheckedThrow(Throwable t) throws T { - if (t != null) - throw (T)t; - else - throw new Error("Unknown Exception"); - } - - /** - * Loads properties of the given {@code bundleName} local to the given - * {@code module} and returns a {@code ResourceBundle} produced from the - * loaded properties. - * - * @apiNote This method is intended for internal use. Need to refactor. - * - * @param module the module from which the properties are loaded - * @param bundleName the bundle name of the properties, - * such as "com.example.app.MyResources_de" - * @return the {@code ResourceBundle} produced from the loaded properties, - * or null if no properties are found - * @see PropertyResourceBundle - */ - public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName) - throws IOException - { - String resourceName = toResourceName(bundleName, "properties"); - if (resourceName == null) { - return null; - } - - PrivilegedAction pa = () -> { - try { - return module.getResourceAsStream(resourceName); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }; - try (InputStream stream = AccessController.doPrivileged(pa)) { - if (stream != null) { - return new PropertyResourceBundle(stream); - } else { - return null; - } - } catch (UncheckedIOException e) { - throw e.getCause(); - } - } - - private static String toResourceName(String bundleName, String suffix) { - if (bundleName.contains("://")) { - return null; - } - StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length()); - sb.append(bundleName.replace('.', '/')).append('.').append(suffix); - return sb.toString(); - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/classes/sun/util/resources/Bundles.java --- a/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java Thu Dec 01 08:57:53 2016 +0000 @@ -58,8 +58,6 @@ import java.util.spi.ResourceBundleProvider; import jdk.internal.misc.JavaUtilResourceBundleAccess; import jdk.internal.misc.SharedSecrets; -import sun.util.locale.provider.ResourceBundleProviderSupport; - /** */ @@ -203,9 +201,13 @@ bundle = loadBundleFromProviders(baseName, targetLocale, providers, cacheKey); } else { try { - bundle = ResourceBundleProviderSupport - .loadResourceBundle(Bundles.class.getModule(), - strategy.toBundleName(baseName, targetLocale)); + String bundleName = strategy.toBundleName(baseName, targetLocale); + Class c = Class.forName(Bundles.class.getModule(), bundleName); + if (c != null && ResourceBundle.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class bundleClass = (Class) c; + bundle = bundleAccess.newResourceBundle(bundleClass); + } } catch (Exception e) { cacheKey.setCause(e); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/native/include/jni.h --- a/jdk/src/java.base/share/native/include/jni.h Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/native/include/jni.h Thu Dec 01 08:57:53 2016 +0000 @@ -770,12 +770,6 @@ jobject (JNICALL *GetModule) (JNIEnv* env, jclass clazz); - - void (JNICALL *AddModuleReads) - (JNIEnv* env, jobject m1, jobject m2); - - jboolean (JNICALL *CanReadModule) - (JNIEnv* env, jobject m1, jobject m2); }; /* @@ -1874,14 +1868,6 @@ return functions->GetModule(this, clazz); } - void AddModuleReads(jobject m1, jobject m2) { - functions->AddModuleReads(this, m1, m2); - } - - jboolean CanReadModule(jobject m1, jobject m2) { - return functions->CanReadModule(this, m1, m2); - } - #endif /* __cplusplus */ }; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/native/include/jvm.h --- a/jdk/src/java.base/share/native/include/jvm.h Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/native/include/jvm.h Thu Dec 01 08:57:53 2016 +0000 @@ -402,8 +402,8 @@ */ JNIEXPORT void JNICALL -JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location, - jobjectArray packages); +JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version, + jstring location, jobjectArray packages); JNIEXPORT void JNICALL JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); @@ -411,9 +411,6 @@ JNIEXPORT void JNICALL JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject to_module); -JNIEXPORT jboolean JNICALL -JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module); - JNIEXPORT void JNICALL JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); @@ -423,9 +420,6 @@ JNIEXPORT void JNICALL JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); -JNIEXPORT jboolean JNICALL -JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module); - JNIEXPORT void JNICALL JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/native/libjava/Module.c --- a/jdk/src/java.base/share/native/libjava/Module.c Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/native/libjava/Module.c Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ JNIEXPORT void JNICALL Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module, - jstring version, jstring location, - jobjectArray packages) + jboolean is_open, jstring version, + jstring location, jobjectArray packages) { - JVM_DefineModule(env, module, version, location, packages); + JVM_DefineModule(env, module, is_open, version, location, packages); } JNIEXPORT void JNICALL diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/native/libjli/java.c --- a/jdk/src/java.base/share/native/libjli/java.c Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/native/libjli/java.c Thu Dec 01 08:57:53 2016 +0000 @@ -61,12 +61,13 @@ * interfaces. */ -/* we always print to stderr */ -#define USE_STDERR JNI_TRUE +#define USE_STDERR JNI_TRUE /* we usually print to stderr */ +#define USE_STDOUT JNI_FALSE static jboolean printVersion = JNI_FALSE; /* print and exit */ static jboolean showVersion = JNI_FALSE; /* print but continue */ static jboolean printUsage = JNI_FALSE; /* print and exit*/ +static jboolean printTo = USE_STDERR; /* where to print version/usage */ static jboolean printXUsage = JNI_FALSE; /* print and exit*/ static jboolean dryRun = JNI_FALSE; /* initialize VM and exit */ static char *showSettings = NULL; /* print but continue */ @@ -567,6 +568,7 @@ JLI_StrCmp(name, "--add-modules") == 0 || JLI_StrCmp(name, "--limit-modules") == 0 || JLI_StrCmp(name, "--add-exports") == 0 || + JLI_StrCmp(name, "--add-opens") == 0 || JLI_StrCmp(name, "--add-reads") == 0 || JLI_StrCmp(name, "--patch-module") == 0; } @@ -758,12 +760,15 @@ if (*arg != '-' || JLI_StrCmp(arg, "-version") == 0 + || JLI_StrCmp(arg, "--version") == 0 || JLI_StrCmp(arg, "-fullversion") == 0 + || JLI_StrCmp(arg, "--full-version") == 0 || JLI_StrCmp(arg, "-help") == 0 || JLI_StrCmp(arg, "--help") == 0 || JLI_StrCmp(arg, "-?") == 0 || JLI_StrCmp(arg, "-jar") == 0 - || JLI_StrCmp(arg, "-X") == 0) { + || JLI_StrCmp(arg, "-X") == 0 + || JLI_StrCmp(arg, "--help-extra") == 0) { return; } } @@ -1288,6 +1293,7 @@ } else if (JLI_StrCmp(arg, "--add-modules") == 0 || JLI_StrCmp(arg, "--limit-modules") == 0 || JLI_StrCmp(arg, "--add-exports") == 0 || + JLI_StrCmp(arg, "--add-opens") == 0 || JLI_StrCmp(arg, "--add-reads") == 0 || JLI_StrCmp(arg, "--patch-module") == 0) { REPORT_ERROR (has_arg, ARG_ERROR6, arg); @@ -1295,22 +1301,36 @@ /* * The following cases will cause the argument parsing to stop */ - } else if (JLI_StrCmp(arg, "--help") == 0 || - JLI_StrCmp(arg, "-help") == 0 || + } else if (JLI_StrCmp(arg, "-help") == 0 || JLI_StrCmp(arg, "-h") == 0 || JLI_StrCmp(arg, "-?") == 0) { printUsage = JNI_TRUE; return JNI_TRUE; + } else if (JLI_StrCmp(arg, "--help") == 0) { + printUsage = JNI_TRUE; + printTo = USE_STDOUT; + return JNI_TRUE; } else if (JLI_StrCmp(arg, "-version") == 0) { printVersion = JNI_TRUE; return JNI_TRUE; + } else if (JLI_StrCmp(arg, "--version") == 0) { + printVersion = JNI_TRUE; + printTo = USE_STDOUT; + return JNI_TRUE; } else if (JLI_StrCmp(arg, "-showversion") == 0) { showVersion = JNI_TRUE; + } else if (JLI_StrCmp(arg, "--show-version") == 0) { + showVersion = JNI_TRUE; + printTo = USE_STDOUT; } else if (JLI_StrCmp(arg, "--dry-run") == 0) { dryRun = JNI_TRUE; } else if (JLI_StrCmp(arg, "-X") == 0) { printXUsage = JNI_TRUE; return JNI_TRUE; + } else if (JLI_StrCmp(arg, "--help-extra") == 0) { + printXUsage = JNI_TRUE; + printTo = USE_STDOUT; + return JNI_TRUE; /* * The following case checks for -XshowSettings OR -XshowSetting:SUBOPT. * In the latter case, any SUBOPT value not recognized will default to "all" @@ -1330,6 +1350,9 @@ } else if (JLI_StrCmp(arg, "-fullversion") == 0) { JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion()); return JNI_FALSE; + } else if (JLI_StrCmp(arg, "--full-version") == 0) { + JLI_ShowMessage("%s %s", _launcher_name, GetFullVersion()); + return JNI_FALSE; } else if (JLI_StrCmp(arg, "-verbosegc") == 0) { AddOption("-verbose:gc", NULL); } else if (JLI_StrCmp(arg, "-t") == 0) { @@ -1752,11 +1775,11 @@ NULL_CHECK(print = (*env)->GetStaticMethodID(env, ver, (extraLF == JNI_TRUE) ? "println" : "print", - "()V" + "(Z)V" ) ); - (*env)->CallStaticVoidMethod(env, ver, print); + (*env)->CallStaticVoidMethod(env, ver, print, printTo); } /* @@ -1794,7 +1817,7 @@ "listModules", "(ZLjava/lang/String;)V")); NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString)); (*env)->CallStaticVoidMethod(env, cls, listModulesID, - USE_STDERR, + USE_STDOUT, joptString); } @@ -1812,7 +1835,7 @@ if (doXUsage) { NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls, "printXUsageMessage", "(Z)V")); - (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, USE_STDERR); + (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, printTo); } else { NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls, "initHelpMessage", "(Ljava/lang/String;)V")); @@ -1853,7 +1876,7 @@ } /* Complete the usage message and print to stderr*/ - (*env)->CallStaticVoidMethod(env, cls, printHelp, USE_STDERR); + (*env)->CallStaticVoidMethod(env, cls, printHelp, printTo); } return; } @@ -2255,3 +2278,16 @@ fprintf(stderr, "\n"); va_end(vl); } + +/* + * A utility procedure to always print to stdout + */ +void +JLI_ShowMessage(const char* fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + vfprintf(stdout, fmt, vl); + fprintf(stdout, "\n"); + va_end(vl); +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.base/share/native/libjli/java.h --- a/jdk/src/java.base/share/native/libjli/java.h Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.base/share/native/libjli/java.h Thu Dec 01 08:57:53 2016 +0000 @@ -140,6 +140,9 @@ /* Reports an error message only to stderr. */ void JLI_ReportMessage(const char * message, ...); +/* Reports a message only to stdout. */ +void JLI_ShowMessage(const char * message, ...); + /* * Reports an exception which terminates the vm to stderr or a window * as appropriate. diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.compact1/share/classes/module-info.java --- a/jdk/src/java.compact1/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.compact1/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,7 @@ * Aggregates {@code java.base}, {@code java.logging}, and {@code java.scripting}. */ module java.compact1 { - requires public java.logging; - requires public java.scripting; + requires transitive java.logging; + requires transitive java.scripting; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.compact2/share/classes/module-info.java --- a/jdk/src/java.compact2/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.compact2/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,9 +27,9 @@ * Supplements {@code java.compact1} with JDBC, JAXP, and RMI. */ module java.compact2 { - requires public java.compact1; - requires public java.rmi; - requires public java.sql; - requires public java.xml; + requires transitive java.compact1; + requires transitive java.rmi; + requires transitive java.sql; + requires transitive java.xml; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.compact3/share/classes/module-info.java --- a/jdk/src/java.compact3/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.compact3/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,15 +28,15 @@ * Instrumentation, Preferences, Security, and XML cryptography APIs. */ module java.compact3 { - requires public java.compact2; - requires public java.compiler; - requires public java.instrument; - requires public java.management; - requires public java.naming; - requires public java.prefs; - requires public java.security.jgss; - requires public java.security.sasl; - requires public java.sql.rowset; - requires public java.xml.crypto; + requires transitive java.compact2; + requires transitive java.compiler; + requires transitive java.instrument; + requires transitive java.management; + requires transitive java.naming; + requires transitive java.prefs; + requires transitive java.security.jgss; + requires transitive java.security.sasl; + requires transitive java.sql.rowset; + requires transitive java.xml.crypto; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.desktop/share/classes/module-info.java --- a/jdk/src/java.desktop/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.desktop/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,8 +28,8 @@ * accessibility, audio, imaging, printing, and JavaBeans. */ module java.desktop { - requires public java.datatransfer; - requires public java.xml; + requires transitive java.datatransfer; + requires transitive java.xml; requires java.prefs; exports java.applet; @@ -91,6 +91,11 @@ exports com.sun.awt to jdk.desktop; + opens javax.swing.plaf.basic to + jdk.jconsole; + opens com.sun.java.swing.plaf.windows to + jdk.jconsole; + uses java.awt.im.spi.InputMethodDescriptor; uses javax.accessibility.AccessibilityProvider; uses javax.imageio.spi.ImageInputStreamSpi; @@ -113,31 +118,44 @@ provides java.net.ContentHandlerFactory with sun.awt.www.content.MultimediaContentHandlers; provides javax.print.PrintServiceLookup with sun.print.PrintServiceLookupProvider; provides javax.print.StreamPrintServiceFactory with sun.print.PSStreamPrinterFactory; - provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiInDeviceProvider; - provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiOutDeviceProvider; - provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.RealTimeSequencerProvider; - provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.SoftProvider; + + provides javax.sound.midi.spi.MidiDeviceProvider with + com.sun.media.sound.MidiInDeviceProvider, + com.sun.media.sound.MidiOutDeviceProvider, + com.sun.media.sound.RealTimeSequencerProvider, + com.sun.media.sound.SoftProvider; + provides javax.sound.midi.spi.MidiFileReader with com.sun.media.sound.StandardMidiFileReader; provides javax.sound.midi.spi.MidiFileWriter with com.sun.media.sound.StandardMidiFileWriter; - provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.AudioFileSoundbankReader; - provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.DLSSoundbankReader; - provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.JARSoundbankReader; - provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.SF2SoundbankReader; - provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AiffFileReader; - provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AuFileReader; - provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.SoftMidiAudioFileReader; - provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFileReader; - provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFloatFileReader; - provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveExtensibleFileReader; - provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AiffFileWriter; - provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AuFileWriter; - provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFileWriter; - provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFloatFileWriter; - provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AlawCodec; - provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AudioFloatFormatConverter; - provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.PCMtoPCMCodec; - provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.UlawCodec; - provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.DirectAudioDeviceProvider; - provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.PortMixerProvider; + + provides javax.sound.midi.spi.SoundbankReader with + com.sun.media.sound.AudioFileSoundbankReader, + com.sun.media.sound.DLSSoundbankReader, + com.sun.media.sound.JARSoundbankReader, + com.sun.media.sound.SF2SoundbankReader; + + provides javax.sound.sampled.spi.AudioFileReader with + com.sun.media.sound.AiffFileReader, + com.sun.media.sound.AuFileReader, + com.sun.media.sound.SoftMidiAudioFileReader, + com.sun.media.sound.WaveFileReader, + com.sun.media.sound.WaveFloatFileReader, + com.sun.media.sound.WaveExtensibleFileReader; + + provides javax.sound.sampled.spi.AudioFileWriter with + com.sun.media.sound.AiffFileWriter, + com.sun.media.sound.AuFileWriter, + com.sun.media.sound.WaveFileWriter, + com.sun.media.sound.WaveFloatFileWriter; + + provides javax.sound.sampled.spi.FormatConversionProvider with + com.sun.media.sound.AlawCodec, + com.sun.media.sound.AudioFloatFormatConverter, + com.sun.media.sound.PCMtoPCMCodec, + com.sun.media.sound.UlawCodec; + + provides javax.sound.sampled.spi.MixerProvider with + com.sun.media.sound.DirectAudioDeviceProvider, + com.sun.media.sound.PortMixerProvider; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java --- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java Thu Dec 01 08:57:53 2016 +0000 @@ -362,6 +362,14 @@ }); } + /** + * If the module image layout changes the location of JDK fonts, + * this will be updated to reflect that. + */ + public static final String getJDKFontDir() { + return jreFontDirName; + } + public TrueTypeFont getEUDCFont() { // Overridden in Windows. return null; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.desktop/share/classes/sun/font/lookup/JDKFontLookup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/font/lookup/JDKFontLookup.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.font.lookup; + +import sun.font.SunFontManager; + +/** + * Implementation-class accessed by other JDK modules to + * locate the JDK-provided fonts. + */ +public final class JDKFontLookup { + + public final static String getJDKFontDir() { + return SunFontManager.getJDKFontDir(); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,9 @@ import java.lang.reflect.Module; import java.security.ProtectionDomain; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.jar.JarFile; /* @@ -660,19 +663,62 @@ setNativeMethodPrefix(ClassFileTransformer transformer, String prefix); /** - * Updates a module to read another module. + * Redefine a module to expand the set of modules that it reads, the set of + * packages that it exports or opens, or the services that it uses or + * provides. This method facilitates the instrumentation of code in named + * modules where that instrumentation requires changes to the set of modules + * that are read, the packages that are exported or open, or the services + * that are used or provided. + * + *

    This method cannot reduce the set of modules that a module reads, nor + * reduce the set of packages that it exports or opens, nor reduce the set + * of services that it uses or provides. This method is a no-op when invoked + * to redefine an unnamed module.

    * - * Agents that instrument code in named modules may need to arrange for the - * modules to read other modules. This method is equivalent to code in {@code - * module} calling {@link Module#addReads(Module) addReads} to read {@code - * other}. + *

    When expanding the services that a module uses or provides then the + * onus is on the agent to ensure that the service type will be accessible at + * each instrumentation site where the service type is used. This method + * does not check if the service type is a member of the module or in a + * package exported to the module by another module that it reads.

    + * + *

    The {@code extraExports} parameter is the map of additional packages + * to export. The {@code extraOpens} parameter is the map of additional + * packages to open. In both cases, the map key is the fully-qualified name + * of the package as defined in section 6.5.3 of + * The Java™ Language Specification , for example, {@code + * "java.lang"}. The map value is the non-empty set of modules that the + * package should be exported or opened to.

    * - * @param module the module to update - * @param other the module to read - * @throws NullPointerException if either module is {@code null} + *

    The {@code extraProvides} parameter is the additional service providers + * for the module to provide. The map key is the service type. The map value + * is the non-empty list of implementation types, each of which is a member + * of the module and an implementation of the service.

    + * + *

    This method is safe for concurrent use and so allows multiple agents + * to instrument and update the same module at around the same time.

    * + * @param module the module to redefine + * @param extraReads the possibly-empty set of additional modules to read + * @param extraExports the possibly-empty map of additional packages to export + * @param extraOpens the possibly-empty map of additional packages to open + * @param extraUses the possibly-empty set of additional services to use + * @param extraProvides the possibly-empty map of additional services to provide + * + * @throws IllegalArgumentException + * If {@code extraExports} or {@code extraOpens} contains a key + * that is not a package in the module; if {@code extraExports} or + * {@code extraOpens} maps a key to an empty set; if a value in the + * {@code extraProvides} map contains a service provider type that + * is not a member of the module or an implementation of the service; + * or {@code extraProvides} maps a key to an empty list + * @throws NullPointerException if any of the arguments are {@code null} or + * any of the Sets or Maps contains a {@code null} key or value * @since 9 - * @see Module#canRead(Module) */ - void addModuleReads(Module module, Module other); + void redefineModule(Module module, + Set extraReads, + Map> extraExports, + Map> extraOpens, + Set> extraUses, + Map, List>> extraProvides); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.instrument/share/classes/java/lang/instrument/package.html --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html Thu Dec 01 08:57:53 2016 +0000 @@ -277,15 +277,6 @@

    Instrumenting code in modules

    -Agents that instrument code in named modules may need to arrange for the -modules to read other modules. If code is instrumented to invoke a method -in a support class in another module, then the module of the instrumented -code should read the module of the supporting class. Furthermore, the -supporting class will only be accessible to the instrumented code if -it is public and in a package that is exported by its module. -Agents can use {@link Instrumentation#addModuleReads addModuleReads} to update -a module to read another. -

    As an aid to agents that deploy supporting classes on the search path of the bootstrap class loader, or the search path of the class loader that loads the main agent class, the Java virtual machine arranges for the module of diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java --- a/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,17 +29,22 @@ import java.lang.reflect.Method; import java.lang.reflect.Module; import java.lang.reflect.AccessibleObject; - import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.ClassDefinition; import java.lang.instrument.Instrumentation; - import java.security.AccessController; import java.security.PrivilegedAction; import java.security.ProtectionDomain; +import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.JarFile; -import java.util.Objects; -import java.util.jar.JarFile; +import jdk.internal.module.Modules; /* * Copyright 2003 Wily Technology, Inc. @@ -228,10 +233,100 @@ } @Override - public void addModuleReads(Module module, Module other) { - Objects.requireNonNull(module); - Objects.requireNonNull(other); - jdk.internal.module.Modules.addReads(module, other); + public void redefineModule(Module module, + Set extraReads, + Map> extraExports, + Map> extraOpens, + Set> extraUses, + Map, List>> extraProvides) + { + if (!module.isNamed()) + return; + + // copy and check reads + extraReads = new HashSet<>(extraReads); + if (extraReads.contains(null)) + throw new NullPointerException("'extraReads' contains null"); + + // copy and check exports and opens + extraExports = cloneAndCheckMap(module, extraExports); + extraOpens = cloneAndCheckMap(module, extraOpens); + + // copy and check uses + extraUses = new HashSet<>(extraUses); + if (extraUses.contains(null)) + throw new NullPointerException("'extraUses' contains null"); + + // copy and check provides + Map, List>> tmpProvides = new HashMap<>(); + for (Map.Entry, List>> e : extraProvides.entrySet()) { + Class service = e.getKey(); + if (service == null) + throw new NullPointerException("'extraProvides' contains null"); + List> providers = new ArrayList<>(e.getValue()); + if (providers.isEmpty()) + throw new IllegalArgumentException("list of providers is empty"); + providers.forEach(p -> { + if (p.getModule() != module) + throw new IllegalArgumentException(p + " not in " + module); + if (!service.isAssignableFrom(p)) + throw new IllegalArgumentException(p + " is not a " + service); + }); + tmpProvides.put(service, providers); + } + extraProvides = tmpProvides; + + + // update reads + extraReads.forEach(m -> Modules.addReads(module, m)); + + // update exports + for (Map.Entry> e : extraExports.entrySet()) { + String pkg = e.getKey(); + Set targets = e.getValue(); + targets.forEach(m -> Modules.addExports(module, pkg, m)); + } + + // update opens + for (Map.Entry> e : extraOpens.entrySet()) { + String pkg = e.getKey(); + Set targets = e.getValue(); + targets.forEach(m -> Modules.addOpens(module, pkg, m)); + } + + // update uses + extraUses.forEach(service -> Modules.addUses(module, service)); + + // update provides + for (Map.Entry, List>> e : extraProvides.entrySet()) { + Class service = e.getKey(); + List> providers = e.getValue(); + providers.forEach(p -> Modules.addProvides(module, service, p)); + } + } + + private Map> + cloneAndCheckMap(Module module, Map> map) + { + if (map.isEmpty()) + return Collections.emptyMap(); + + Map> result = new HashMap<>(); + Set packages = Set.of(module.getPackages()); + for (Map.Entry> e : map.entrySet()) { + String pkg = e.getKey(); + if (pkg == null) + throw new NullPointerException("package cannot be null"); + if (!packages.contains(pkg)) + throw new IllegalArgumentException(pkg + " not in module"); + Set targets = new HashSet<>(e.getValue()); + if (targets.isEmpty()) + throw new IllegalArgumentException("set of targets is empty"); + if (targets.contains(null)) + throw new NullPointerException("set of targets cannot include null"); + result.put(pkg, targets); + } + return result; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.logging/share/classes/java/util/logging/Level.java --- a/jdk/src/java.logging/share/classes/java/util/logging/Level.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.logging/share/classes/java/util/logging/Level.java Thu Dec 01 08:57:53 2016 +0000 @@ -40,6 +40,8 @@ import java.util.ResourceBundle; import java.util.function.Function; import jdk.internal.loader.ClassLoaderValue; +import jdk.internal.misc.JavaUtilResourceBundleAccess; +import jdk.internal.misc.SharedSecrets; /** * The Level class defines a set of standard logging levels that @@ -74,7 +76,11 @@ */ public class Level implements java.io.Serializable { - private static final String defaultBundle = "sun.util.logging.resources.logging"; + private static final String defaultBundle = + "sun.util.logging.resources.logging"; + + private static final JavaUtilResourceBundleAccess RB_ACCESS = + SharedSecrets.getJavaUtilResourceBundleAccess(); /** * @serial The non-localized name of the level. @@ -280,7 +286,7 @@ // or its defining class loader, if it's unnamed module, // of this Level instance that can be a custom Level subclass; Module module = this.getClass().getModule(); - ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, + ResourceBundle rb = RB_ACCESS.getBundle(resourceBundleName, newLocale, module); final String localizedName = rb.getString(name); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.logging/share/classes/java/util/logging/Logger.java --- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java Thu Dec 01 08:57:53 2016 +0000 @@ -38,6 +38,9 @@ import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; + +import jdk.internal.misc.JavaUtilResourceBundleAccess; +import jdk.internal.misc.SharedSecrets; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import static jdk.internal.logger.DefaultLoggerFinder.isSystem; @@ -256,8 +259,8 @@ private static final LoggerBundle NO_RESOURCE_BUNDLE = new LoggerBundle(null, null); - private static final RuntimePermission GET_CLASS_LOADER_PERMISSION = - new RuntimePermission("getClassLoader"); + private static final JavaUtilResourceBundleAccess RB_ACCESS = + SharedSecrets.getJavaUtilResourceBundleAccess(); // A value class that holds the logger configuration data. // This configuration can be shared between an application logger @@ -2180,9 +2183,7 @@ if (!useCallersModule || callerModule == null || !callerModule.isNamed()) { try { Module mod = cl.getUnnamedModule(); - PrivilegedAction pa = () -> - ResourceBundle.getBundle(name, currentLocale, mod); - catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION); + catalog = RB_ACCESS.getBundle(name, currentLocale, mod); catalogName = name; catalogLocale = currentLocale; return catalog; @@ -2226,9 +2227,7 @@ // Try with the caller's module try { // Use the caller's module - PrivilegedAction pa = () -> - ResourceBundle.getBundle(name, currentLocale, callerModule); - catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION); + catalog = RB_ACCESS.getBundle(name, currentLocale, callerModule); catalogName = name; catalogLocale = currentLocale; return catalog; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.management/share/classes/module-info.java --- a/jdk/src/java.management/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.management/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,7 +30,7 @@ * JVM and other components in the Java runtime. */ module java.management { - requires public java.rmi; + requires transitive java.rmi; requires java.logging; requires java.naming; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java --- a/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java Thu Dec 01 08:57:53 2016 +0000 @@ -625,26 +625,6 @@ // that has no from method to be embeded in another class. } - // check if a static "toCompositeData" method exists - try { - toMethod = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Method run() throws NoSuchMethodException { - Method m = javaClass.getDeclaredMethod("toCompositeData", javaClass); - if (m != null - && CompositeData.class.isAssignableFrom(m.getReturnType()) - && Modifier.isStatic(m.getModifiers())) { - m.setAccessible(true); - return m; - } else { - return null; - } - } - }); - } catch (PrivilegedActionException e) { - // ignore NoSuchMethodException since we allow classes - // that has no from method to be embeded in another class. - } - if (COMPOSITE_DATA_CLASS.isAssignableFrom(c)) { // c implements CompositeData - set openType to null // defer generating the CompositeType diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.se.ee/share/classes/module-info.java --- a/jdk/src/java.se.ee/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.se.ee/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,16 +29,17 @@ * This module requires {@code java.se} and supplements it with modules * that define CORBA and Java EE APIs. These modules are upgradeable. */ +@SuppressWarnings("deprecation") module java.se.ee { - requires public java.se; + requires transitive java.se; // Upgradeable modules for Java EE technologies - requires public java.activation; - requires public java.annotations.common; - requires public java.corba; - requires public java.transaction; - requires public java.xml.bind; - requires public java.xml.ws; + requires transitive java.activation; + requires transitive java.annotations.common; + requires transitive java.corba; + requires transitive java.transaction; + requires transitive java.xml.bind; + requires transitive java.xml.ws; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.se/share/classes/module-info.java --- a/jdk/src/java.se/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.se/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -31,8 +31,8 @@ * required by {@code java.se.ee}. */ module java.se { - requires public java.compact3; - requires public java.datatransfer; - requires public java.desktop; - requires public java.httpclient; + requires transitive java.compact3; + requires transitive java.datatransfer; + requires transitive java.desktop; + requires transitive java.httpclient; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.sql.rowset/share/classes/module-info.java --- a/jdk/src/java.sql.rowset/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.sql.rowset/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,9 +27,9 @@ * Defines the JDBC RowSet API. */ module java.sql.rowset { - requires public java.logging; - requires public java.naming; - requires public java.sql; + requires transitive java.logging; + requires transitive java.naming; + requires transitive java.sql; exports javax.sql.rowset; exports javax.sql.rowset.serial; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.sql/share/classes/module-info.java --- a/jdk/src/java.sql/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.sql/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,8 +27,8 @@ * Defines the JDBC API. */ module java.sql { - requires public java.logging; - requires public java.xml; + requires transitive java.logging; + requires transitive java.xml; exports java.sql; exports javax.sql; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.transaction/share/classes/module-info.java --- a/jdk/src/java.transaction/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.transaction/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,7 +30,7 @@ * exceptions by the 'Java Language to IDL Mapping Specification'. */ module java.transaction { - requires public java.rmi; + requires transitive java.rmi; exports javax.transaction; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/java.xml.crypto/share/classes/module-info.java --- a/jdk/src/java.xml.crypto/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/java.xml.crypto/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,7 @@ * Defines an API for XML cryptography. */ module java.xml.crypto { - requires public java.xml; + requires transitive java.xml; requires java.logging; exports javax.xml.crypto; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.accessibility/share/classes/module-info.java --- a/jdk/src/jdk.accessibility/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,7 @@ */ module jdk.accessibility { - requires public java.desktop; + requires transitive java.desktop; exports com.sun.java.accessibility.util; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.attach/share/classes/module-info.java --- a/jdk/src/jdk.attach/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.attach/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,9 @@ * questions. */ +/** + * Defines the attach API. + */ module jdk.attach { requires jdk.jvmstat; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.desktop/share/classes/module-info.java --- a/jdk/src/jdk.desktop/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.desktop/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,7 +28,7 @@ */ module jdk.desktop { - requires public java.desktop; + requires transitive java.desktop; exports jdk.awt; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.internal.le/share/classes/module-info.java --- a/jdk/src/jdk.internal.le/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.internal.le/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,9 @@ * questions. */ +/** + * Internal API for line editing + */ module jdk.internal.le { exports jdk.internal.jline to jdk.scripting.nashorn.shell, diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.internal.opt/share/classes/module-info.java --- a/jdk/src/jdk.internal.opt/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.internal.opt/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,9 @@ * questions. */ +/** + * Internal option processing API + */ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,7 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Version; import java.lang.module.ModuleFinder; @@ -58,6 +59,7 @@ import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.Checks; import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleInfoExtender; import jdk.internal.util.jar.JarIndex; @@ -80,7 +82,7 @@ String fname, mname, ename; String zname = ""; String rootjar = null; - Set concealedPackages = new HashSet<>(); + Set concealedPackages = new HashSet<>(); // used by Validator private static final int BASE_VERSION = 0; @@ -90,6 +92,13 @@ final File file; final boolean isDir; + Entry(File file, String basename, String entryname) { + this.file = file; + this.isDir = file.isDirectory(); + this.basename = basename; + this.entryname = entryname; + } + Entry(int version, File file) { this.file = file; String path = file.getPath(); @@ -105,6 +114,21 @@ entryname = en.entryName; } + /** + * Returns a new Entry that trims the versions directory. + * + * This entry should be a valid entry matching the given version. + */ + Entry toVersionedEntry(int version) { + assert isValidVersionedEntry(this, version); + + if (version == BASE_VERSION) + return this; + + EntryName en = new EntryName(trimVersionsDir(basename, version), version); + return new Entry(this.file, en.baseName, en.entryName); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -488,7 +512,9 @@ } else if (printModuleDescriptor) { boolean found; if (fname != null) { - found = printModuleDescriptor(new ZipFile(fname)); + try (ZipFile zf = new ZipFile(fname)) { + found = printModuleDescriptor(zf); + } } else { try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) { found = printModuleDescriptor(fin); @@ -822,21 +848,27 @@ return true; } - private static String toPackageName(ZipEntry entry) { - return toPackageName(entry.getName()); + /* + * Add the package of the given resource name if it's a .class + * or a resource in a named package. + */ + boolean addPackageIfNamed(String name) { + if (name.startsWith(VERSIONS_DIR)) { + throw new InternalError(name); + } + + String pn = toPackageName(name); + // add if this is a class or resource in a package + if (Checks.isJavaIdentifier(pn)) { + packages.add(pn); + return true; + } + + return false; } private static String toPackageName(String path) { - assert path.endsWith(".class"); - int index; - if (path.startsWith(VERSIONS_DIR)) { - index = path.indexOf('/', VERSIONS_DIR.length()); - if (index <= 0) { - return ""; - } - path = path.substring(index + 1); - } - index = path.lastIndexOf('/'); + int index = path.lastIndexOf('/'); if (index != -1) { return path.substring(0, index).replace('/', '.'); } else { @@ -844,6 +876,48 @@ } } + /* + * Returns true if the given entry is a valid entry of the given version. + */ + private boolean isValidVersionedEntry(Entry entry, int version) { + String name = entry.basename; + if (name.startsWith(VERSIONS_DIR) && version != BASE_VERSION) { + int i = name.indexOf('/', VERSIONS_DIR.length()); + // name == -1 -> not a versioned directory, something else + if (i == -1) + return false; + try { + String v = name.substring(VERSIONS_DIR.length(), i); + return Integer.valueOf(v) == version; + } catch (NumberFormatException x) { + return false; + } + } + return true; + } + + /* + * Trim META-INF/versions/$version/ from the given name if the + * given name is a versioned entry of the given version; or + * of any version if the given version is BASE_VERSION + */ + private String trimVersionsDir(String name, int version) { + if (name.startsWith(VERSIONS_DIR)) { + int i = name.indexOf('/', VERSIONS_DIR.length()); + if (i >= 0) { + try { + String v = name.substring(VERSIONS_DIR.length(), i); + if (version == BASE_VERSION || Integer.valueOf(v) == version) { + return name.substring(i + 1, name.length()); + } + } catch (NumberFormatException x) {} + } + throw new InternalError("unexpected versioned entry: " + + name + " version " + version); + } + return name; + } + /** * Expands list of files to process into full list of all files that * can be found by recursively descending directories. @@ -865,28 +939,47 @@ else f = new File(dir, files[i]); - Entry entry = new Entry(version, f); - String entryName = entry.entryname; - + Entry e = new Entry(version, f); + String entryName = e.entryname; + Entry entry = e; + if (e.basename.startsWith(VERSIONS_DIR) && isValidVersionedEntry(e, version)) { + entry = e.toVersionedEntry(version); + } if (f.isFile()) { if (entryName.endsWith(MODULE_INFO)) { moduleInfoPaths.put(entryName, f.toPath()); if (isUpdate) entryMap.put(entryName, entry); - } else if (entries.add(entry)) { - jarEntries.add(entryName); - if (entry.basename.endsWith(".class")) - packages.add(toPackageName(entry.basename)); - if (isUpdate) - entryMap.put(entryName, entry); + } else if (isValidVersionedEntry(entry, version)) { + if (entries.add(entry)) { + jarEntries.add(entryName); + // add the package if it's a class or resource + addPackageIfNamed(trimVersionsDir(entry.basename, version)); + if (isUpdate) + entryMap.put(entryName, entry); + } + } else { + error(formatMsg2("error.release.unexpected.versioned.entry", + entry.basename, String.valueOf(version))); + ok = false; } } else if (f.isDirectory()) { - if (entries.add(entry)) { - if (isUpdate) { - entryMap.put(entryName, entry); + if (isValidVersionedEntry(entry, version)) { + if (entries.add(entry)) { + if (isUpdate) { + entryMap.put(entryName, entry); + } } - expand(f, f.list(), isUpdate, moduleInfoPaths, version); + } else if (entry.basename.equals(VERSIONS_DIR)) { + if (vflag) { + output(formatMsg("out.ignore.entry", entry.basename)); + } + } else { + error(formatMsg2("error.release.unexpected.versioned.entry", + entry.basename, String.valueOf(version))); + ok = false; } + expand(f, f.list(), isUpdate, moduleInfoPaths, version); } else { error(formatMsg("error.nosuch.fileordir", String.valueOf(f))); ok = false; @@ -1047,6 +1140,7 @@ } else if (moduleInfos != null && isModuleInfoEntry) { moduleInfos.putIfAbsent(name, readModuleInfo(zis)); } else { + boolean isDir = e.isDirectory(); if (!entryMap.containsKey(name)) { // copy the old stuff // do our own compression ZipEntry e2 = new ZipEntry(name); @@ -1065,11 +1159,14 @@ addFile(zos, ent); entryMap.remove(name); entries.remove(ent); + isDir = ent.isDir; } jarEntries.add(name); - if (name.endsWith(".class")) - packages.add(toPackageName(name)); + if (!isDir) { + // add the package if it's a class or resource + addPackageIfNamed(trimVersionsDir(name, BASE_VERSION)); + } } } @@ -1850,13 +1947,13 @@ // Modular jar support - static String toString(Set set, + static String toString(Collection c, CharSequence prefix, CharSequence suffix ) { - if (set.isEmpty()) + if (c.isEmpty()) return ""; - return set.stream().map(e -> e.toString()) + return c.stream().map(e -> e.toString()) .collect(joining(", ", prefix, suffix)); } @@ -1890,7 +1987,7 @@ return false; } - static String toString(Set set) { + static String toString(Collection set) { if (set.isEmpty()) { return ""; } return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT)) .collect(joining(" ")); @@ -1903,7 +2000,10 @@ { ModuleDescriptor md = ModuleDescriptor.read(entryInputStream); StringBuilder sb = new StringBuilder(); - sb.append("\n").append(md.toNameAndVersion()); + sb.append("\n"); + if (md.isOpen()) + sb.append("open "); + sb.append(md.toNameAndVersion()); md.requires().stream() .sorted(Comparator.comparing(Requires::name)) @@ -1921,10 +2021,17 @@ .sorted(Comparator.comparing(Exports::source)) .forEach(p -> sb.append("\n exports ").append(p)); - md.conceals().stream().sorted() - .forEach(p -> sb.append("\n conceals ").append(p)); + md.opens().stream() + .sorted(Comparator.comparing(Opens::source)) + .forEach(p -> sb.append("\n opens ").append(p)); - md.provides().values().stream() + Set concealed = new HashSet<>(md.packages()); + md.exports().stream().map(Exports::source).forEach(concealed::remove); + md.opens().stream().map(Opens::source).forEach(concealed::remove); + concealed.stream().sorted() + .forEach(p -> sb.append("\n contains ").append(p)); + + md.provides().stream() .sorted(Comparator.comparing(Provides::service)) .forEach(p -> sb.append("\n provides ").append(p.service()) .append(" with ") @@ -1957,10 +2064,9 @@ { ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes)); Set missing = md.provides() - .values() .stream() .map(Provides::providers) - .flatMap(Set::stream) + .flatMap(List::stream) .filter(p -> !jarEntries.contains(toBinaryName(p))) .collect(Collectors.toSet()); if (missing.size() > 0) { @@ -1988,22 +2094,17 @@ ModuleDescriptor vd = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue())); if (!(isValidVersionedDescriptor(vd, rd))) return false; - e.setValue(extendedInfoBytes(rd, vd, e.getValue(), concealedPackages)); + e.setValue(extendedInfoBytes(rd, vd, e.getValue(), packages)); } return true; } - private Set findConcealedPackages(ModuleDescriptor md){ + private Set findConcealedPackages(ModuleDescriptor md) { Objects.requireNonNull(md); - - Set exports = md.exports() - .stream() - .map(Exports::source) - .collect(toSet()); - - return packages.stream() - .filter(p -> !exports.contains(p)) - .collect(toSet()); + Set concealed = new HashSet<>(packages); + md.exports().stream().map(Exports::source).forEach(concealed::remove); + md.opens().stream().map(Opens::source).forEach(concealed::remove); + return concealed; } private static boolean isPlatformModule(String name) { @@ -2034,8 +2135,8 @@ for (Requires r : vd.requires()) { if (rootRequires.contains(r)) { continue; - } else if (r.modifiers().contains(Requires.Modifier.PUBLIC)) { - fatalError(getMsg("error.versioned.info.requires.public")); + } else if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) { + fatalError(getMsg("error.versioned.info.requires.transitive")); return false; } else if (!isPlatformModule(r.name())) { fatalError(getMsg("error.versioned.info.requires.added")); @@ -2056,6 +2157,10 @@ fatalError(getMsg("error.versioned.info.exports.notequal")); return false; } + if (!rd.opens().equals(vd.opens())) { + fatalError(getMsg("error.versioned.info.opens.notequal")); + return false; + } if (!rd.provides().equals(vd.provides())) { fatalError(getMsg("error.versioned.info.provides.notequal")); return false; @@ -2074,15 +2179,15 @@ private byte[] extendedInfoBytes(ModuleDescriptor rootDescriptor, ModuleDescriptor md, byte[] miBytes, - Set conceals) + Set packages) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); InputStream is = new ByteArrayInputStream(miBytes); ModuleInfoExtender extender = ModuleInfoExtender.newExtender(is); - // Add (or replace) the ConcealedPackages attribute - extender.conceals(conceals); + // Add (or replace) the Packages attribute + extender.packages(packages); // --main-class if (ename != null) diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Thu Dec 01 08:57:53 2016 +0000 @@ -67,14 +67,16 @@ in the root error.versioned.info.name.notequal=\ module-info.class in a versioned directory contains incorrect name -error.versioned.info.requires.public=\ - module-info.class in a versioned directory contains additional "requires public" +error.versioned.info.requires.transitive=\ + module-info.class in a versioned directory contains additional "requires transitive" error.versioned.info.requires.added=\ module-info.class in a versioned directory contains additional "requires" error.versioned.info.requires.dropped=\ module-info.class in a versioned directory contains missing "requires" error.versioned.info.exports.notequal=\ module-info.class in a versioned directory contains different "exports" +error.versioned.info.opens.notequal=\ + module-info.class in a versioned directory contains different "opens" error.versioned.info.provides.notequal=\ module-info.class in a versioned directory contains different "provides" error.invalid.versioned.module.attribute=\ @@ -85,6 +87,8 @@ release {0} not valid error.release.value.toosmall=\ release {0} not valid, must be >= 9 +error.release.unexpected.versioned.entry=\ + unexpected versioned entry {0} for release {1} error.validator.jarfile.exception=\ can not validate {0}: {1} error.validator.jarfile.invalid=\ @@ -104,14 +108,16 @@ error.validator.different.api=\ entry: {0}, contains a class with different api from earlier version error.validator.names.mismatch=\ - entry: {0}, contains a class with internal name {1}, names do not match + entry: {0}, contains a class with internal name {1}, names do not match warn.validator.identical.entry=\ - warning - entry: {0} contains a class that is identical to an entry already in the jar + Warning: entry {0} contains a class that\n\ + is identical to an entry already in the jar warn.validator.resources.with.same.name=\ - warning - entry: {0}, multiple resources with same name + Warning: entry {0}, multiple resources with same name warn.validator.concealed.public.class=\ - warning - entry {0} is a public class in a concealed package, \n\ - placing this jar on the class path will result in incompatible public interfaces + Warning: entry {0} is a public class\n\ + in a concealed package, placing this jar on the class path will result\n\ + in incompatible public interfaces out.added.manifest=\ added manifest out.added.module-info=\ diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jconsole/share/classes/module-info.java --- a/jdk/src/jdk.jconsole/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jconsole/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,8 +24,8 @@ */ module jdk.jconsole { - requires public java.desktop; - requires public java.management; + requires transitive java.desktop; + requires transitive java.management; requires java.logging; requires java.rmi; requires jdk.attach; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java --- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,17 +30,17 @@ * A module in the target VM. *

    * Any method on {@code ModuleReference} which directly or - * indirectly takes {@code ModuleReference} as an parameter may throw + * indirectly takes {@code ModuleReference} as a parameter may throw * {@link com.sun.jdi.VMDisconnectedException} if the target VM is * disconnected and the {@link com.sun.jdi.event.VMDisconnectEvent} has been or is * available to be read from the {@link com.sun.jdi.event.EventQueue}. *

    * Any method on {@code ModuleReference} which directly or - * indirectly takes {@code ModuleReference} as an parameter may throw + * indirectly takes {@code ModuleReference} as a parameter may throw * {@link com.sun.jdi.VMOutOfMemoryException} if the target VM has run out of memory. *

    * Any method on {@code ModuleReference} or which directly or indirectly takes - * {@code ModuleReference} as parameter may throw + * {@code ModuleReference} as a parameter may throw * {@link com.sun.jdi.InvalidModuleException} if the mirrored module * has been unloaded. * @@ -67,12 +67,4 @@ * @return the {@link ClassLoaderReference} object for this module. */ ClassLoaderReference classLoader(); - - /** - * Indicates if this module reads another module. - * - * @return {@code true} if this module reads {@code other}, - * {@code false} otherwise - */ - boolean canRead(ModuleReference other); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java Thu Dec 01 08:57:53 2016 +0000 @@ -75,15 +75,4 @@ } return classLoader; } - - public synchronized boolean canRead(ModuleReference module) { - boolean ret; - try { - ret = JDWP.ModuleReference.CanRead. - process(this.vm, this, (ModuleReferenceImpl)module).canRead; - } catch (JDWPException ex) { - throw ex.toJDIException(); - } - return ret; - } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jdi/share/classes/module-info.java --- a/jdk/src/jdk.jdi/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jdi/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,9 @@ * questions. */ +/** + * Defines the Java Debugger Interface. + */ module jdk.jdi { requires jdk.attach; requires jdk.jdwp.agent; @@ -37,10 +40,11 @@ uses com.sun.jdi.connect.spi.TransportService; // windows shared memory connector providers are added at build time - provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.ProcessAttachingConnector; - provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.RawCommandLineLauncher; - provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketAttachingConnector; - provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketListeningConnector; - provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SunCommandLineLauncher; + provides com.sun.jdi.connect.Connector with + com.sun.tools.jdi.ProcessAttachingConnector, + com.sun.tools.jdi.RawCommandLineLauncher, + com.sun.tools.jdi.SocketAttachingConnector, + com.sun.tools.jdi.SocketListeningConnector, + com.sun.tools.jdi.SunCommandLineLauncher; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jdi/windows/classes/module-info.java.extra --- a/jdk/src/jdk.jdi/windows/classes/module-info.java.extra Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jdi/windows/classes/module-info.java.extra Thu Dec 01 08:57:53 2016 +0000 @@ -23,5 +23,6 @@ * questions. */ -provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryAttachingConnector; -provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryListeningConnector; +provides com.sun.jdi.connect.Connector with + com.sun.tools.jdi.SharedMemoryAttachingConnector, + com.sun.tools.jdi.SharedMemoryListeningConnector; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jdwp.agent/share/classes/module-info.java --- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,9 @@ * questions. */ +/** + * Java Debug Wire Protocol. + */ module jdk.jdwp.agent { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c --- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c Thu Dec 01 08:57:53 2016 +0000 @@ -83,36 +83,8 @@ return JNI_TRUE; } -static jboolean -canRead(PacketInputStream *in, PacketOutputStream *out) -{ - static jmethodID method = NULL; - JNIEnv *env = getEnv(); - jboolean can_read; - jobject module; - jobject source_module; - - if (method == NULL) { - method = getMethod(env, jlrM(env), "canRead", "(Ljava/lang/reflect/Module;)Z"); - } - module = inStream_readModuleRef(env, in); - if (inStream_error(in)) { - return JNI_TRUE; - } - source_module = inStream_readModuleRef(env, in); - if (inStream_error(in)) { - return JNI_TRUE; - } - can_read = JNI_FUNC_PTR(env, CallBooleanMethod) - (env, module, method, source_module); - - (void)outStream_writeBoolean(out, can_read); - return JNI_TRUE; -} - void *ModuleReference_Cmds[] = { (void *)3 ,(void *)getName ,(void *)getClassLoader - ,(void *)canRead }; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.lang.module.ResolutionException; @@ -191,6 +192,7 @@ taskHelper.showVersion(options.fullVersion); return EXIT_OK; } + if (taskHelper.getExistingImage() == null) { if (options.modulePath.isEmpty()) { throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true); @@ -256,7 +258,6 @@ ImageProvider imageProvider = createImageProvider(finder, config.getModules(), - config.getLimitmods(), config.getByteOrder(), null, IGNORE_SIGNING_DEFAULT); @@ -291,23 +292,43 @@ postProcessImage(img, config.getPlugins()); } + // the token for "all modules on the module path" + private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; private void createImage() throws Exception { if (options.output == null) { throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true); } - ModuleFinder finder - = newModuleFinder(options.modulePath, options.limitMods, options.addMods); + if (options.addMods.isEmpty()) { throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules") .showUsage(true); } + + Set roots = new HashSet<>(); + for (String mod : options.addMods) { + if (mod.equals(ALL_MODULE_PATH)) { + ModuleFinder finder = modulePathFinder(); + finder.findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .forEach(mn -> roots.add(mn)); + } else { + roots.add(mod); + } + } + + ModuleFinder finder = newModuleFinder(options.modulePath, + options.limitMods, + roots); + + // First create the image provider ImageProvider imageProvider = createImageProvider(finder, - options.addMods, - options.limitMods, - options.endian, - options.packagedModulesPath, - options.ignoreSigning); + roots, + options.endian, + options.packagedModulesPath, + options.ignoreSigning); // Then create the Plugin Stack ImagePluginStack stack = ImagePluginConfiguration. @@ -362,21 +383,20 @@ } private static ImageProvider createImageProvider(ModuleFinder finder, - Set addMods, - Set limitMods, + Set roots, ByteOrder order, Path retainModulesPath, boolean ignoreSigning) throws IOException { - if (addMods.isEmpty()) { + if (roots.isEmpty()) { throw new IllegalArgumentException("empty modules and limitmods"); } Configuration cf = Configuration.empty() .resolveRequires(finder, ModuleFinder.of(), - addMods); + roots); Map mods = cf.modules().stream() .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation)); @@ -388,8 +408,8 @@ * modules, their transitive dependences, plus a set of other modules. */ private static ModuleFinder limitFinder(ModuleFinder finder, - Set roots, - Set otherMods) { + Set roots, + Set otherMods) { // resolve all root modules Configuration cf = Configuration.empty() @@ -535,40 +555,4 @@ return image; } } - - private static enum Section { - NATIVE_LIBS("native"), - NATIVE_CMDS("bin"), - CLASSES("classes"), - CONFIG("conf"), - UNKNOWN("unknown"); - - private final String jmodDir; - - Section(String jmodDir) { - this.jmodDir = jmodDir; - } - - String jmodDir() { - return jmodDir; - } - - boolean matches(String path) { - return path.startsWith(jmodDir); - } - - static Section getSectionFromName(String dir) { - if (Section.NATIVE_LIBS.matches(dir)) { - return Section.NATIVE_LIBS; - } else if (Section.NATIVE_CMDS.matches(dir)) { - return Section.NATIVE_CMDS; - } else if (Section.CLASSES.matches(dir)) { - return Section.CLASSES; - } else if (Section.CONFIG.matches(dir)) { - return Section.CONFIG; - } else { - return Section.UNKNOWN; - } - } - } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java Thu Dec 01 08:57:53 2016 +0000 @@ -50,24 +50,23 @@ ModuleDescriptor md = mod.descriptor(); // drop hashes - ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(md.name()); + ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name()); md.requires().stream() .forEach(builder::requires); md.exports().stream() .forEach(builder::exports); + md.opens().stream() + .forEach(builder::opens); md.uses().stream() .forEach(builder::uses); - md.provides().values().stream() + md.provides().stream() .forEach(builder::provides); // build the proper concealed packages - Set exps = md.exports().stream() - .map(ModuleDescriptor.Exports::source) - .collect(Collectors.toSet()); - - mod.packages().stream() - .filter(pn -> !exps.contains(pn)) - .forEach(builder::conceals); + Set concealed = new HashSet<>(mod.packages()); + md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove); + md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove); + concealed.stream().forEach(builder::contains); md.version().ifPresent(builder::version); md.mainClass().ifPresent(builder::mainClass); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java Thu Dec 01 08:57:53 2016 +0000 @@ -35,6 +35,7 @@ import java.util.Set; import java.util.stream.Stream; import jdk.internal.jimage.decompressor.CompressedResourceHeader; +import jdk.internal.loader.ResourceHelper; import jdk.tools.jlink.plugin.ResourcePool; import jdk.tools.jlink.plugin.ResourcePoolBuilder; import jdk.tools.jlink.plugin.ResourcePoolEntry; @@ -58,6 +59,14 @@ return ModuleDescriptor.read(bb); } + /** + * Returns true if a resource has an effective package. + */ + public static boolean isNamedPackageResource(String path) { + return (path.endsWith(".class") && !path.endsWith("module-info.class")) || + !ResourceHelper.isSimpleResource(path); + } + class ResourcePoolModuleImpl implements ResourcePoolModule { final Map moduleContent = new LinkedHashMap<>(); @@ -100,7 +109,7 @@ .filter(m -> m.type() == ResourcePoolEntry.Type.CLASS_OR_RESOURCE) .forEach(res -> { String name = ImageFileCreator.resourceName(res.path()); - if (name.endsWith(".class") && !name.endsWith("module-info.class")) { + if (isNamedPackageResource(name)) { String pkg = ImageFileCreator.toPackage(name); if (!pkg.isEmpty()) { pkgs.add(pkg); diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Thu Dec 01 08:57:53 2016 +0000 @@ -118,7 +118,7 @@ null)); } - plugins.add(Jlink.newPlugin("installed-modules", Collections.emptyMap(), null)); + plugins.add(Jlink.newPlugin("system-modules", Collections.emptyMap(), null)); // build the image Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration( diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,17 +28,18 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.*; -import java.lang.module.ModuleDescriptor; import java.util.ArrayList; -import java.util.Collections; +import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; +import java.util.function.IntSupplier; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; @@ -50,16 +51,17 @@ import jdk.internal.org.objectweb.asm.Opcodes; import static jdk.internal.org.objectweb.asm.Opcodes.*; + import jdk.tools.jlink.plugin.PluginException; import jdk.tools.jlink.plugin.ResourcePool; import jdk.tools.jlink.plugin.Plugin; -import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.Builder.*; +import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.SystemModulesClassGenerator.*; import jdk.tools.jlink.plugin.ResourcePoolBuilder; import jdk.tools.jlink.plugin.ResourcePoolEntry; /** - * Jlink plugin to reconstitute module descriptors for installed modules. - * It will extend module-info.class with ConcealedPackages attribute, + * Jlink plugin to reconstitute module descriptors for system modules. + * It will extend module-info.class with Packages attribute, * if not present. It also determines the number of packages of * the boot layer at link time. * @@ -69,16 +71,14 @@ * @see SystemModules */ public final class SystemModuleDescriptorPlugin implements Plugin { - private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); + private static final JavaLangModuleAccess JLMA = + SharedSecrets.getJavaLangModuleAccess(); - // TODO: packager has the dependency on the plugin name - // Keep it as "--installed-modules" until packager removes such - // dependency (should not need to specify this plugin since it - // is enabled by default) - private static final String NAME = "installed-modules"; - private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME); + private static final String NAME = "system-modules"; + private static final String DESCRIPTION = + PluginsResourceBundle.getDescription(NAME); + private boolean enabled; - public SystemModuleDescriptorPlugin() { this.enabled = true; } @@ -106,39 +106,38 @@ } } - @Override public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) { if (!enabled) { throw new PluginException(NAME + " was set"); } - Builder builder = new Builder(); + SystemModulesClassGenerator generator = new SystemModulesClassGenerator(); // generate the byte code to create ModuleDescriptors // skip parsing module-info.class and skip name check in.moduleView().modules().forEach(module -> { - Optional optData = module.findEntry("module-info.class"); - if (! optData.isPresent()) { + + ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow( // automatic module not supported yet - throw new PluginException("module-info.class not found for " + - module.name() + " module"); - } - ResourcePoolEntry data = optData.get(); + () -> new PluginException("module-info.class not found for " + + module.name() + " module") + ); + assert module.name().equals(data.moduleName()); try { ByteArrayInputStream bain = new ByteArrayInputStream(data.contentBytes()); ModuleDescriptor md = ModuleDescriptor.read(bain); validateNames(md); - ModuleDescriptorBuilder mbuilder = builder.module(md, module.packages()); - int packages = md.exports().size() + md.conceals().size(); - if (md.conceals().isEmpty() && - packages != module.packages().size()) { - // add ConcealedPackages attribute if not exist + Set packages = module.packages(); + generator.addModule(md, module.packages()); + + // add Packages attribute if not exist + if (md.packages().isEmpty() && packages.size() > 0) { bain.reset(); ModuleInfoRewriter minfoWriter = - new ModuleInfoRewriter(bain, mbuilder.conceals()); + new ModuleInfoRewriter(bain, module.packages()); // replace with the overridden version data = data.copyWithContent(minfoWriter.getBytes()); } @@ -149,11 +148,11 @@ }); // Generate the new class - ClassWriter cwriter = builder.build(); + ClassWriter cwriter = generator.getClassWriter(); in.entries().forEach(data -> { if (data.path().endsWith("module-info.class")) return; - if (builder.isOverriddenClass(data.path())) { + if (generator.isOverriddenClass(data.path())) { byte[] bytes = cwriter.toByteArray(); ResourcePoolEntry ndata = data.copyWithContent(bytes); out.add(ndata); @@ -166,14 +165,14 @@ } /* - * Add ConcealedPackages attribute + * Add Packages attribute */ class ModuleInfoRewriter extends ByteArrayOutputStream { final ModuleInfoExtender extender; - ModuleInfoRewriter(InputStream in, Set conceals) throws IOException { + ModuleInfoRewriter(InputStream in, Set packages) throws IOException { this.extender = ModuleInfoExtender.newExtender(in); - // Add ConcealedPackages attribute - this.extender.conceals(conceals); + // Add Packages attribute + this.extender.packages(packages); this.extender.write(this); } @@ -190,19 +189,21 @@ for (Exports e : md.exports()) { Checks.requirePackageName(e.source()); if (e.isQualified()) - e.targets().forEach(Checks::requireModuleName); + e.targets().forEach(Checks::requireModuleName); } - for (Map.Entry e : md.provides().entrySet()) { - String service = e.getKey(); - Provides provides = e.getValue(); - Checks.requireServiceTypeName(service); + for (Opens opens : md.opens()) { + Checks.requirePackageName(opens.source()); + if (opens.isQualified()) + opens.targets().forEach(Checks::requireModuleName); + } + for (Provides provides : md.provides()) { Checks.requireServiceTypeName(provides.service()); provides.providers().forEach(Checks::requireServiceProviderName); } for (String service : md.uses()) { Checks.requireServiceTypeName(service); } - for (String pn : md.conceals()) { + for (String pn : md.packages()) { Checks.requirePackageName(pn); } } @@ -222,45 +223,60 @@ } /** - * Builder of a new jdk.internal.module.SystemModules class - * to reconstitute ModuleDescriptor of the installed modules. + * ClassWriter of a new jdk.internal.module.SystemModules class + * to reconstitute ModuleDescriptor of the system modules. */ - static class Builder { + static class SystemModulesClassGenerator { private static final String CLASSNAME = "jdk/internal/module/SystemModules"; private static final String MODULE_DESCRIPTOR_BUILDER = "jdk/internal/module/Builder"; private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE = "[Ljava/lang/module/ModuleDescriptor;"; + private static final String REQUIRES_MODIFIER_CLASSNAME = + "java/lang/module/ModuleDescriptor$Requires$Modifier"; + private static final String EXPORTS_MODIFIER_CLASSNAME = + "java/lang/module/ModuleDescriptor$Exports$Modifier"; + private static final String OPENS_MODIFIER_CLASSNAME = + "java/lang/module/ModuleDescriptor$Opens$Modifier"; // static variables in SystemModules class private static final String MODULE_NAMES = "MODULE_NAMES"; private static final String MODULES_TO_HASH = "MODULES_TO_HASH"; private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER"; - private static final int BUILDER_VAR = 0; - private static final int MD_VAR = 1; // variable for ModuleDescriptor - private static final int MODS_VAR = 2; // variable for Set - private static final int STRING_SET_VAR = 3; // variable for Set private static final int MAX_LOCAL_VARS = 256; + private final int BUILDER_VAR = 0; + private final int MD_VAR = 1; // variable for ModuleDescriptor + private int nextLocalVar = 2; // index to next local variable + private final ClassWriter cw; private MethodVisitor mv; - private int nextLocalVar = 4; private int nextModulesIndex = 0; // list of all ModuleDescriptorBuilders, invoked in turn when building. private final List builders = new ArrayList<>(); // module name to hash - private final Map modulesToHash = new HashMap<>(); + private final Map modulesToHash = new HashMap<>(); + + // module name to index in MODULES_TO_HASH + private final Map modulesToHashIndex = new HashMap<>(); - // map Set to a specialized builder to allow them to be - // deduplicated as they are requested - private final Map, StringSetBuilder> stringSets = new HashMap<>(); + // A builder to create one single Set instance for a given set of + // names or modifiers to reduce the footprint + // e.g. target modules of qualified exports + private final DedupSetBuilder dedupSetBuilder + = new DedupSetBuilder(this::getNextLocalVar); - public Builder() { - this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES); + public SystemModulesClassGenerator() { + this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); + } + + private int getNextLocalVar() { + return nextLocalVar++; } /* @@ -270,16 +286,16 @@ */ private void clinit(int numModules, int numPackages) { cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME, - null, "java/lang/Object", null); + null, "java/lang/Object", null); // public static String[] MODULE_NAMES = new String[] {....}; cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES, "[Ljava/lang/String;", null, null) .visitEnd(); - // public static String[] MODULES_TO_HASH = new String[] {....}; + // public static byte[][] MODULES_TO_HASH cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH, - "[Ljava/lang/String;", null, null) + "[[B", null, null) .visitEnd(); // public static int PACKAGES_IN_BOOT_LAYER; @@ -308,23 +324,30 @@ // create the MODULES_TO_HASH array pushInt(numModules); - mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); + mv.visitTypeInsn(ANEWARRAY, "[B"); index = 0; for (ModuleDescriptorBuilder builder : builders) { String mn = builder.md.name(); - String recordedHash = modulesToHash.get(mn); + byte[] recordedHash = modulesToHash.get(mn); if (recordedHash != null) { mv.visitInsn(DUP); // arrayref pushInt(index); - mv.visitLdcInsn(recordedHash); // value + pushInt(recordedHash.length); + mv.visitIntInsn(NEWARRAY, T_BYTE); + for (int i = 0; i < recordedHash.length; i++) { + mv.visitInsn(DUP); // arrayref + pushInt(i); + mv.visitIntInsn(BIPUSH, recordedHash[i]); + mv.visitInsn(BASTORE); + } mv.visitInsn(AASTORE); + modulesToHashIndex.put(mn, index); } index++; } - mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, - "[Ljava/lang/String;"); + mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); @@ -333,42 +356,42 @@ } /* - * Adds the given ModuleDescriptor to the installed module list, and - * prepares mapping from Set to StringSetBuilders to emit an - * optimized number of string sets during build. + * Adds the given ModuleDescriptor to the system module list, and + * prepares mapping from various Sets to SetBuilders to emit an + * optimized number of sets during build. */ - public ModuleDescriptorBuilder module(ModuleDescriptor md, Set packages) { + public void addModule(ModuleDescriptor md, Set packages) { ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages); builders.add(builder); // exports - for (ModuleDescriptor.Exports e : md.exports()) { - if (e.isQualified()) { - stringSets.computeIfAbsent(e.targets(), s -> new StringSetBuilder(s)) - .increment(); - } + for (Exports e : md.exports()) { + dedupSetBuilder.stringSet(e.targets()); + dedupSetBuilder.exportsModifiers(e.modifiers()); } - // provides (preserve iteration order) - for (ModuleDescriptor.Provides p : md.provides().values()) { - stringSets.computeIfAbsent(p.providers(), s -> new StringSetBuilder(s, true)) - .increment(); + // opens + for (Opens opens : md.opens()) { + dedupSetBuilder.stringSet(opens.targets()); + dedupSetBuilder.opensModifiers(opens.modifiers()); + } + + // requires + for (Requires r : md.requires()) { + dedupSetBuilder.requiresModifiers(r.modifiers()); } // uses - stringSets.computeIfAbsent(md.uses(), s -> new StringSetBuilder(s)) - .increment(); + dedupSetBuilder.stringSet(md.uses()); // hashes JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes())); - - return builder; } /* * Generate bytecode for SystemModules */ - public ClassWriter build() { + public ClassWriter getClassWriter() { int numModules = builders.size(); int numPackages = 0; for (ModuleDescriptorBuilder builder : builders) { @@ -411,108 +434,79 @@ } class ModuleDescriptorBuilder { - static final String REQUIRES_MODIFIER_CLASSNAME = - "java/lang/module/ModuleDescriptor$Requires$Modifier"; - static final String REQUIRES_MODIFIER_TYPE = - "Ljava/lang/module/ModuleDescriptor$Requires$Modifier;"; static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;"; - static final String REQUIRES_MODIFIER_STRING_SIG = - "(" + REQUIRES_MODIFIER_TYPE + "Ljava/lang/String;)" + BUILDER_TYPE; - static final String STRING_SET_SIG = - "(Ljava/lang/String;Ljava/util/Set;)" + BUILDER_TYPE; - static final String SET_STRING_SIG = - "(Ljava/util/Set;Ljava/lang/String;)" + BUILDER_TYPE; - static final String SET_SIG = - "(Ljava/util/Set;)" + BUILDER_TYPE; + static final String EXPORTS_TYPE = + "Ljava/lang/module/ModuleDescriptor$Exports;"; + static final String OPENS_TYPE = + "Ljava/lang/module/ModuleDescriptor$Opens;"; + static final String PROVIDES_TYPE = + "Ljava/lang/module/ModuleDescriptor$Provides;"; + static final String REQUIRES_TYPE = + "Ljava/lang/module/ModuleDescriptor$Requires;"; + + // method signature for static Builder::newExports, newOpens, + // newProvides, newRequires methods + static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG = + "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)" + + EXPORTS_TYPE; + static final String EXPORTS_MODIFIER_SET_STRING_SIG = + "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE; + static final String OPENS_MODIFIER_SET_STRING_SET_SIG = + "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)" + + OPENS_TYPE; + static final String OPENS_MODIFIER_SET_STRING_SIG = + "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE; + static final String PROVIDES_STRING_LIST_SIG = + "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE; + static final String REQUIRES_SET_STRING_SIG = + "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE; + + // method signature for Builder instance methods that + // return this Builder instance + static final String EXPORTS_ARRAY_SIG = + "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE; + static final String OPENS_ARRAY_SIG = + "([" + OPENS_TYPE + ")" + BUILDER_TYPE; + static final String PROVIDES_ARRAY_SIG = + "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE; + static final String REQUIRES_ARRAY_SIG = + "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE; + static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE; static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE; - static final String STRING_STRING_SIG = - "(Ljava/lang/String;Ljava/lang/String;)" + BUILDER_TYPE; + static final String STRING_BYTE_ARRAY_SIG = + "(Ljava/lang/String;[B)" + BUILDER_TYPE; + static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE; + final ModuleDescriptor md; final Set packages; ModuleDescriptorBuilder(ModuleDescriptor md, Set packages) { + if (md.isAutomatic()) { + throw new InternalError("linking automatic module is not supported"); + } this.md = md; this.packages = packages; } - void newBuilder(String name, int reqs, int exports, int provides, - int packages) { - mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER); - mv.visitInsn(DUP); - mv.visitLdcInsn(name); - pushInt(initialCapacity(reqs)); - pushInt(initialCapacity(exports)); - pushInt(initialCapacity(provides)); - pushInt(initialCapacity(packages)); - mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER, - "", "(Ljava/lang/String;IIII)V", false); - mv.visitVarInsn(ASTORE, BUILDER_VAR); - mv.visitVarInsn(ALOAD, BUILDER_VAR); - } - - /* - * Returns the set of concealed packages from ModuleDescriptor, if present - * or compute it if the module does not have ConcealedPackages attribute - */ - Set conceals() { - Set conceals = md.conceals(); - if (conceals.isEmpty() && md.exports().size() != packages.size()) { - Set exports = md.exports().stream() - .map(Exports::source) - .collect(Collectors.toSet()); - conceals = packages.stream() - .filter(pn -> !exports.contains(pn)) - .collect(Collectors.toSet()); - } - - if (conceals.size() + md.exports().size() != packages.size() && - // jdk.localedata may have concealed packages that don't exist - !md.name().equals("jdk.localedata")) { - throw new AssertionError(md.name() + ": conceals=" + conceals.size() + - ", exports=" + md.exports().size() + ", packages=" + packages.size()); - } - return conceals; - } - void build() { - newBuilder(md.name(), md.requires().size(), - md.exports().size(), - md.provides().size(), - packages.size()); + // new jdk.internal.module.Builder + newBuilder(); // requires - for (ModuleDescriptor.Requires req : md.requires()) { - switch (req.modifiers().size()) { - case 0: - requires(req.name()); - break; - case 1: - ModuleDescriptor.Requires.Modifier mod = - req.modifiers().iterator().next(); - requires(mod, req.name()); - break; - default: - requires(req.modifiers(), req.name()); - } - } + requires(md.requires()); // exports - for (ModuleDescriptor.Exports e : md.exports()) { - if (e.isQualified()) { - exports(e.source(), e.targets()); - } else { - exports(e.source()); - } - } + exports(md.exports()); + + // opens + opens(md.opens()); // uses uses(md.uses()); // provides - for (ModuleDescriptor.Provides p : md.provides().values()) { - provides(p.service(), p.providers()); - } + provides(md.provides()); // all packages packages(packages); @@ -532,6 +526,38 @@ putModuleDescriptor(); } + void newBuilder() { + mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER); + mv.visitInsn(DUP); + mv.visitLdcInsn(md.name()); + mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER, + "", "(Ljava/lang/String;)V", false); + mv.visitVarInsn(ASTORE, BUILDER_VAR); + mv.visitVarInsn(ALOAD, BUILDER_VAR); + + if (md.isOpen()) { + setModuleBit("open", true); + } + if (md.isSynthetic()) { + setModuleBit("synthetic", true); + } + } + + /* + * Invoke Builder.(boolean value) + */ + void setModuleBit(String methodName, boolean value) { + mv.visitVarInsn(ALOAD, BUILDER_VAR); + if (value) { + mv.visitInsn(ICONST_1); + } else { + mv.visitInsn(ICONST_0); + } + mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, + methodName, BOOLEAN_SIG, false); + mv.visitInsn(POP); + } + /* * Put ModuleDescriptor into the modules array */ @@ -539,130 +565,220 @@ mv.visitVarInsn(ALOAD, MD_VAR); pushInt(nextModulesIndex++); mv.visitVarInsn(ALOAD, BUILDER_VAR); + mv.visitLdcInsn(md.hashCode()); mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "build", "()Ljava/lang/module/ModuleDescriptor;", false); + "build", "(I)Ljava/lang/module/ModuleDescriptor;", + false); mv.visitInsn(AASTORE); } /* - * Invoke Builder.requires(String mn) + * Call Builder::newRequires to create Requires instances and + * then pass it to the builder by calling: + * Builder.requires(Requires[]) + * */ - void requires(String name) { + void requires(Set requires) { mv.visitVarInsn(ALOAD, BUILDER_VAR); - mv.visitLdcInsn(name); + pushInt(requires.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires"); + int arrayIndex = 0; + for (Requires require : requires) { + mv.visitInsn(DUP); // arrayref + pushInt(arrayIndex++); + newRequires(require.modifiers(), require.name()); + mv.visitInsn(AASTORE); + } mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "requires", STRING_SIG, false); - mv.visitInsn(POP); - } - - /* - * Invoke Builder.requires(Modifier mod, String mn) - */ - void requires(ModuleDescriptor.Requires.Modifier mod, String name) { - mv.visitVarInsn(ALOAD, BUILDER_VAR); - mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, mod.name(), - REQUIRES_MODIFIER_TYPE); - mv.visitLdcInsn(name); - mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "requires", REQUIRES_MODIFIER_STRING_SIG, false); - mv.visitInsn(POP); + "requires", REQUIRES_ARRAY_SIG, false); } /* - * Invoke Builder.requires(Set mods, String mn) + * Invoke Builder.newRequires(Set mods, String mn) * - * EnumSet mods = EnumSet.of(mod,....); - * Buidler.requires(mods, mn); + * Set mods = ... + * Builder.newRequires(mods, mn); */ - void requires(Set mods, String name) { - mv.visitVarInsn(ALOAD, MODS_VAR); - String signature = "("; - for (ModuleDescriptor.Requires.Modifier m : mods) { - mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, m.name(), - REQUIRES_MODIFIER_TYPE); - signature += "Ljava/util/Enum;"; - } - signature += ")Ljava/util/EnumSet;"; - mv.visitMethodInsn(INVOKESTATIC, "java/util/EnumSet", "of", - signature, false); - mv.visitVarInsn(ASTORE, MODS_VAR); - mv.visitVarInsn(ALOAD, BUILDER_VAR); - mv.visitVarInsn(ALOAD, MODS_VAR); + void newRequires(Set mods, String name) { + int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods); + mv.visitVarInsn(ALOAD, varIndex); mv.visitLdcInsn(name); - mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "requires", SET_STRING_SIG, false); - mv.visitInsn(POP); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newRequires", REQUIRES_SET_STRING_SIG, false); } /* - * Invoke Builder.exports(String pn) + * Call Builder::newExports to create Exports instances and + * then pass it to the builder by calling: + * Builder.exports(Exports[]) + * */ - void exports(String pn) { + void exports(Set exports) { mv.visitVarInsn(ALOAD, BUILDER_VAR); - - mv.visitLdcInsn(pn); + pushInt(exports.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports"); + int arrayIndex = 0; + for (Exports export : exports) { + mv.visitInsn(DUP); // arrayref + pushInt(arrayIndex++); + newExports(export.modifiers(), export.source(), export.targets()); + mv.visitInsn(AASTORE); + } mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "exports", STRING_SIG, false); - mv.visitInsn(POP); + "exports", EXPORTS_ARRAY_SIG, false); } /* - * Invoke Builder.exports(String pn, Set targets) + * Invoke + * Builder.newExports(Set ms, String pn, + * Set targets) + * or + * Builder.newExports(Set ms, String pn) * * Set targets = new HashSet<>(); * targets.add(t); * : * : - * Builder.exports(pn, targets); + * + * Set mods = ... + * Builder.newExports(mods, pn, targets); */ - void exports(String pn, Set targets) { - int varIndex = stringSets.get(targets).build(); + void newExports(Set ms, String pn, Set targets) { + int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms); + if (!targets.isEmpty()) { + int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets); + mv.visitVarInsn(ALOAD, modifiersSetIndex); + mv.visitLdcInsn(pn); + mv.visitVarInsn(ALOAD, stringSetIndex); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false); + } else { + mv.visitVarInsn(ALOAD, modifiersSetIndex); + mv.visitLdcInsn(pn); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false); + } + } + + + /** + * Call Builder::newOpens to create Opens instances and + * then pass it to the builder by calling: + * Builder.opens(Opens[]) + * + */ + void opens(Set opens) { mv.visitVarInsn(ALOAD, BUILDER_VAR); - mv.visitLdcInsn(pn); - mv.visitVarInsn(ALOAD, varIndex); + pushInt(opens.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens"); + int arrayIndex = 0; + for (Opens open : opens) { + mv.visitInsn(DUP); // arrayref + pushInt(arrayIndex++); + newOpens(open.modifiers(), open.source(), open.targets()); + mv.visitInsn(AASTORE); + } mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "exports", STRING_SET_SIG, false); - mv.visitInsn(POP); + "opens", OPENS_ARRAY_SIG, false); } /* - * Invokes Builder.uses(Set uses) + * Invoke + * Builder.newOpens(Set ms, String pn, + * Set targets) + * or + * Builder.newOpens(Set ms, String pn) + * + * Set targets = new HashSet<>(); + * targets.add(t); + * : + * : + * + * Set mods = ... + * Builder.newOpens(mods, pn, targets); + */ + void newOpens(Set ms, String pn, Set targets) { + int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms); + if (!targets.isEmpty()) { + int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets); + mv.visitVarInsn(ALOAD, modifiersSetIndex); + mv.visitLdcInsn(pn); + mv.visitVarInsn(ALOAD, stringSetIndex); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false); + } else { + mv.visitVarInsn(ALOAD, modifiersSetIndex); + mv.visitLdcInsn(pn); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false); + } + } + + /* + * Invoke Builder.uses(Set uses) */ void uses(Set uses) { - int varIndex = stringSets.get(uses).build(); + int varIndex = dedupSetBuilder.indexOfStringSet(uses); mv.visitVarInsn(ALOAD, BUILDER_VAR); mv.visitVarInsn(ALOAD, varIndex); mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "uses", SET_SIG, false); + "uses", SET_SIG, false); mv.visitInsn(POP); } /* - * Invoke Builder.provides(String service, Set providers) + * Call Builder::newProvides to create Provides instances and + * then pass it to the builder by calling: + * Builder.provides(Provides[] provides) + * + */ + void provides(Collection provides) { + mv.visitVarInsn(ALOAD, BUILDER_VAR); + pushInt(provides.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides"); + int arrayIndex = 0; + for (Provides provide : provides) { + mv.visitInsn(DUP); // arrayref + pushInt(arrayIndex++); + newProvides(provide.service(), provide.providers()); + mv.visitInsn(AASTORE); + } + mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, + "provides", PROVIDES_ARRAY_SIG, false); + } + + /* + * Invoke Builder.newProvides(String service, Set providers) * - * Set providers = new LinkedHashSet<>(); + * Set providers = new HashSet<>(); * providers.add(impl); * : * : - * Builder.exports(service, providers); + * Builder.newProvides(service, providers); */ - void provides(String service, Set providers) { - int varIndex = stringSets.get(providers).build(); - mv.visitVarInsn(ALOAD, BUILDER_VAR); + void newProvides(String service, List providers) { mv.visitLdcInsn(service); - mv.visitVarInsn(ALOAD, varIndex); - mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "provides", STRING_SET_SIG, false); - mv.visitInsn(POP); + pushInt(providers.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); + int arrayIndex = 0; + for (String provider : providers) { + mv.visitInsn(DUP); // arrayref + pushInt(arrayIndex++); + mv.visitLdcInsn(provider); + mv.visitInsn(AASTORE); + } + mv.visitMethodInsn(INVOKESTATIC, "java/util/List", + "of", "([Ljava/lang/Object;)Ljava/util/List;", true); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newProvides", PROVIDES_STRING_LIST_SIG, false); } /* - * Invoke Builder.conceals(String pn) + * Invoke Builder.packages(String pn) */ void packages(Set packages) { + int varIndex = dedupSetBuilder.newStringSet(packages); mv.visitVarInsn(ALOAD, BUILDER_VAR); - int varIndex = new StringSetBuilder(packages).build(); - assert varIndex == STRING_SET_VAR; mv.visitVarInsn(ALOAD, varIndex); mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, "packages", SET_SIG, false); @@ -683,7 +799,7 @@ /* * Invoke Builder.version(Version v); */ - void version(ModuleDescriptor.Version v) { + void version(Version v) { mv.visitVarInsn(ALOAD, BUILDER_VAR); mv.visitLdcInsn(v.toString()); mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, @@ -691,99 +807,277 @@ mv.visitInsn(POP); } + /* + * Invoke Builder.algorithm(String a); + */ void algorithm(String alg) { mv.visitVarInsn(ALOAD, BUILDER_VAR); mv.visitLdcInsn(alg); mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "algorithm", STRING_SIG, false); + "algorithm", STRING_SIG, false); mv.visitInsn(POP); } - void moduleHash(String name, String hashString) { + /* + * Invoke Builder.moduleHash(String name, byte[] hash); + */ + void moduleHash(String name, byte[] hash) { mv.visitVarInsn(ALOAD, BUILDER_VAR); mv.visitLdcInsn(name); - mv.visitLdcInsn(hashString); + + // must exist + Integer index = modulesToHashIndex.get(name); + if (index != null) { + mv.visitFieldInsn(GETSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B"); + pushInt(index); + mv.visitInsn(AALOAD); + assert(Objects.equals(hash, modulesToHash.get(name))); + } else { + pushInt(hash.length); + mv.visitIntInsn(NEWARRAY, T_BYTE); + for (int i = 0; i < hash.length; i++) { + mv.visitInsn(DUP); // arrayref + pushInt(i); + mv.visitIntInsn(BIPUSH, hash[i]); + mv.visitInsn(BASTORE); + } + } mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "moduleHash", STRING_STRING_SIG, false); + "moduleHash", STRING_BYTE_ARRAY_SIG, false); mv.visitInsn(POP); } } /* - * StringSetBuilder generates bytecode to create one single instance - * of HashSet for a given set of names and assign to a local variable - * slot. When there is only one single reference to a Set, - * it will reuse STRING_SET_VAR for reference. For Set with - * multiple references, it will use a new local variable. + * Wraps set creation, ensuring identical sets are properly deduplicated. */ - class StringSetBuilder { - final Set names; - final boolean linked; - int refCount; - int localVarIndex; + class DedupSetBuilder { + // map Set to a specialized builder to allow them to be + // deduplicated as they are requested + final Map, SetBuilder> stringSets = new HashMap<>(); + + // map Set to a specialized builder to allow them to be + // deduplicated as they are requested + final Map, EnumSetBuilder> + requiresModifiersSets = new HashMap<>(); + + // map Set to a specialized builder to allow them to be + // deduplicated as they are requested + final Map, EnumSetBuilder> + exportsModifiersSets = new HashMap<>(); + + // map Set to a specialized builder to allow them to be + // deduplicated as they are requested + final Map, EnumSetBuilder> + opensModifiersSets = new HashMap<>(); + + private final int stringSetVar; + private final int enumSetVar; + private final IntSupplier localVarSupplier; - StringSetBuilder(Set names, boolean linked) { - this.names = names; - this.linked = linked; + DedupSetBuilder(IntSupplier localVarSupplier) { + this.stringSetVar = localVarSupplier.getAsInt(); + this.enumSetVar = localVarSupplier.getAsInt(); + this.localVarSupplier = localVarSupplier; + } + + /* + * Add the given set of strings to this builder. + */ + void stringSet(Set strings) { + stringSets.computeIfAbsent(strings, + s -> new SetBuilder<>(s, stringSetVar, localVarSupplier) + ).increment(); + } + + /* + * Add the given set of Exports.Modifiers + */ + void exportsModifiers(Set mods) { + exportsModifiersSets.computeIfAbsent(mods, s -> + new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME, + enumSetVar, localVarSupplier) + ).increment(); + } + + /* + * Add the given set of Opens.Modifiers + */ + void opensModifiers(Set mods) { + opensModifiersSets.computeIfAbsent(mods, s -> + new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME, + enumSetVar, localVarSupplier) + ).increment(); } - StringSetBuilder(Set names) { - this(names, false); + /* + * Add the given set of Requires.Modifiers + */ + void requiresModifiers(Set mods) { + requiresModifiersSets.computeIfAbsent(mods, s -> + new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME, + enumSetVar, localVarSupplier) + ).increment(); + } + + /* + * Retrieve the index to the given set of Strings. Emit code to + * generate it when SetBuilder::build is called. + */ + int indexOfStringSet(Set names) { + return stringSets.get(names).build(); + } + + /* + * Retrieve the index to the given set of Exports.Modifier. + * Emit code to generate it when EnumSetBuilder::build is called. + */ + int indexOfExportsModifiers(Set mods) { + return exportsModifiersSets.get(mods).build(); + } + + /** + * Retrieve the index to the given set of Opens.Modifier. + * Emit code to generate it when EnumSetBuilder::build is called. + */ + int indexOfOpensModifiers(Set mods) { + return opensModifiersSets.get(mods).build(); } - void increment() { + + /* + * Retrieve the index to the given set of Requires.Modifier. + * Emit code to generate it when EnumSetBuilder::build is called. + */ + int indexOfRequiresModifiers(Set mods) { + return requiresModifiersSets.get(mods).build(); + } + + /* + * Build a new string set without any attempt to deduplicate it. + */ + int newStringSet(Set names) { + int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build(); + assert index == stringSetVar; + return index; + } + } + + /* + * SetBuilder generates bytecode to create one single instance of Set + * for a given set of elements and assign to a local variable slot. + * When there is only one single reference to a Set, + * it will reuse defaultVarIndex. For a Set with multiple references, + * it will use a new local variable retrieved from the nextLocalVar + */ + class SetBuilder { + private final Set elements; + private final int defaultVarIndex; + private final IntSupplier nextLocalVar; + private int refCount; + private int localVarIndex; + + SetBuilder(Set elements, + int defaultVarIndex, + IntSupplier nextLocalVar) { + this.elements = elements; + this.defaultVarIndex = defaultVarIndex; + this.nextLocalVar = nextLocalVar; + } + + /* + * Increments the number of references to this particular set. + */ + final void increment() { refCount++; } + /** + * Generate the appropriate instructions to load an object reference + * to the element onto the stack. + */ + void visitElement(T element, MethodVisitor mv) { + mv.visitLdcInsn(element); + } + /* - * Build bytecode for the Set represented by this builder, + * Build bytecode for the Set represented by this builder, * or get the local variable index of a previously generated set * (in the local scope). * * @return local variable index of the generated set. */ - int build() { + final int build() { int index = localVarIndex; if (localVarIndex == 0) { // if non-empty and more than one set reference this builder, // emit to a unique local - index = refCount <= 1 ? STRING_SET_VAR - : nextLocalVar++; + index = refCount <= 1 ? defaultVarIndex + : nextLocalVar.getAsInt(); if (index < MAX_LOCAL_VARS) { localVarIndex = index; } else { - // overflow: disable optimization and keep localVarIndex = 0 - index = STRING_SET_VAR; + // overflow: disable optimization by using localVarIndex = 0 + index = defaultVarIndex; } - if (names.isEmpty()) { - mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections", - "emptySet", "()Ljava/util/Set;", false); - mv.visitVarInsn(ASTORE, index); - } else if (names.size() == 1) { - mv.visitLdcInsn(names.iterator().next()); - mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections", - "singleton", "(Ljava/lang/Object;)Ljava/util/Set;", false); - mv.visitVarInsn(ASTORE, index); - } else { - String cn = linked ? "java/util/LinkedHashSet" : "java/util/HashSet"; - mv.visitTypeInsn(NEW, cn); - mv.visitInsn(DUP); - pushInt(initialCapacity(names.size())); - mv.visitMethodInsn(INVOKESPECIAL, cn, "", "(I)V", false); - - mv.visitVarInsn(ASTORE, index); - for (String t : names) { - mv.visitVarInsn(ALOAD, index); - mv.visitLdcInsn(t); - mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", - "add", "(Ljava/lang/Object;)Z", true); - mv.visitInsn(POP); - } - } + generateSetOf(index); } return index; } + + private void generateSetOf(int index) { + if (elements.size() <= 10) { + // call Set.of(e1, e2, ...) + StringBuilder sb = new StringBuilder("("); + for (T t : elements) { + sb.append("Ljava/lang/Object;"); + visitElement(t, mv); + } + sb.append(")Ljava/util/Set;"); + mv.visitMethodInsn(INVOKESTATIC, "java/util/Set", + "of", sb.toString(), true); + } else { + // call Set.of(E... elements) + pushInt(elements.size()); + mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); + int arrayIndex = 0; + for (T t : elements) { + mv.visitInsn(DUP); // arrayref + pushInt(arrayIndex); + visitElement(t, mv); // value + mv.visitInsn(AASTORE); + arrayIndex++; + } + mv.visitMethodInsn(INVOKESTATIC, "java/util/Set", + "of", "([Ljava/lang/Object;)Ljava/util/Set;", true); + } + mv.visitVarInsn(ASTORE, index); + } + } + + /* + * Generates bytecode to create one single instance of EnumSet + * for a given set of modifiers and assign to a local variable slot. + */ + class EnumSetBuilder extends SetBuilder { + + private final String className; + + EnumSetBuilder(Set modifiers, String className, + int defaultVarIndex, + IntSupplier nextLocalVar) { + super(modifiers, defaultVarIndex, nextLocalVar); + this.className = className; + } + + /** + * Loads an Enum field. + */ + void visitElement(T t, MethodVisitor mv) { + mv.visitFieldInsn(GETSTATIC, className, t.toString(), + "L" + className + ";"); + } } } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties Thu Dec 01 08:57:53 2016 +0000 @@ -80,7 +80,7 @@ Takes a file hinting to jlink what java.lang.invoke classes to pre-generate. If\n\ this flag is not specified a default set of classes will be generated. -installed-modules.description=Fast loading of module descriptors (always enabled) +system-modules.description=Fast loading of module descriptors (always enabled) onoff.argument= diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java Thu Dec 01 08:57:53 2016 +0000 @@ -40,6 +40,7 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Version; @@ -83,6 +84,7 @@ import java.util.stream.Collectors; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; @@ -97,6 +99,7 @@ import jdk.internal.joptsimple.OptionSet; import jdk.internal.joptsimple.OptionSpec; import jdk.internal.joptsimple.ValueConverter; +import jdk.internal.loader.ResourceHelper; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ModuleHashes; @@ -261,9 +264,9 @@ } } - static String toString(Set set) { - if (set.isEmpty()) { return ""; } - return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT)) + static String toString(Collection c) { + if (c.isEmpty()) { return ""; } + return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT)) .collect(joining(" ")); } @@ -291,14 +294,21 @@ .sorted(Comparator.comparing(Exports::source)) .forEach(p -> sb.append("\n exports ").append(p)); - md.conceals().stream().sorted() - .forEach(p -> sb.append("\n conceals ").append(p)); + md.opens().stream() + .sorted(Comparator.comparing(Opens::source)) + .forEach(p -> sb.append("\n opens ").append(p)); - md.provides().values().stream() + Set concealed = new HashSet<>(md.packages()); + md.exports().stream().map(Exports::source).forEach(concealed::remove); + md.opens().stream().map(Opens::source).forEach(concealed::remove); + concealed.stream().sorted() + .forEach(p -> sb.append("\n contains ").append(p)); + + md.provides().stream() .sorted(Comparator.comparing(Provides::service)) .forEach(p -> sb.append("\n provides ").append(p.service()) - .append(" with ") - .append(toString(p.providers()))); + .append(" with ") + .append(toString(p.providers()))); md.mainClass().ifPresent(v -> sb.append("\n main-class " + v)); @@ -311,8 +321,8 @@ JLMA.hashes(md).ifPresent( hashes -> hashes.names().stream().sorted().forEach( mod -> sb.append("\n hashes ").append(mod).append(" ") - .append(hashes.algorithm()).append(" ") - .append(hashes.hashFor(mod)))); + .append(hashes.algorithm()).append(" ") + .append(hashes.hashFor(mod)))); out.println(sb.toString()); } @@ -414,7 +424,7 @@ /** * Writes the updated module-info.class to the ZIP output stream. * - * The updated module-info.class will have a ConcealedPackages attribute + * The updated module-info.class will have a Packages attribute * with the set of module-private/non-exported packages. * * If --module-version, --main-class, or other options were provided @@ -439,15 +449,9 @@ try (InputStream in = miSupplier.get()) { ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in); - // Add (or replace) the ConcealedPackages attribute + // Add (or replace) the Packages attribute if (packages != null) { - Set exported = descriptor.exports().stream() - .map(ModuleDescriptor.Exports::source) - .collect(Collectors.toSet()); - Set concealed = packages.stream() - .filter(p -> !exported.contains(p)) - .collect(Collectors.toSet()); - extender.conceals(concealed); + extender.packages(packages); } // --main-class @@ -556,10 +560,11 @@ Set findPackages(Path dir) { try { return Files.find(dir, Integer.MAX_VALUE, - ((path, attrs) -> attrs.isRegularFile() && - path.toString().endsWith(".class"))) - .map(path -> toPackageName(dir.relativize(path))) - .filter(pkg -> pkg.length() > 0) // module-info + ((path, attrs) -> attrs.isRegularFile())) + .map(dir::relativize) + .filter(path -> isResource(path.toString())) + .map(path -> toPackageName(path)) + .filter(pkg -> pkg.length() > 0) .distinct() .collect(Collectors.toSet()); } catch (IOException ioe) { @@ -572,21 +577,30 @@ */ Set findPackages(JarFile jf) { return jf.stream() - .filter(e -> e.getName().endsWith(".class")) + .filter(e -> !e.isDirectory() && isResource(e.getName())) .map(e -> toPackageName(e)) - .filter(pkg -> pkg.length() > 0) // module-info + .filter(pkg -> pkg.length() > 0) .distinct() .collect(Collectors.toSet()); } + /** + * Returns true if it's a .class or a resource with an effective + * package name. + */ + boolean isResource(String name) { + name = name.replace(File.separatorChar, '/'); + return name.endsWith(".class") || !ResourceHelper.isSimpleResource(name); + } + + String toPackageName(Path path) { String name = path.toString(); - assert name.endsWith(".class"); int index = name.lastIndexOf(File.separatorChar); if (index != -1) return name.substring(0, index).replace(File.separatorChar, '.'); - if (!name.equals(MODULE_INFO)) { + if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { IOException e = new IOException(name + " in the unnamed package"); throw new UncheckedIOException(e); } @@ -595,12 +609,15 @@ String toPackageName(ZipEntry entry) { String name = entry.getName(); - assert name.endsWith(".class"); int index = name.lastIndexOf("/"); if (index != -1) return name.substring(0, index).replace('/', '.'); - else - return ""; + + if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { + IOException e = new IOException(name + " in the unnamed package"); + throw new UncheckedIOException(e); + } + return ""; } void processClasses(JmodOutputStream out, List classpaths) diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jlink/share/classes/module-info.java --- a/jdk/src/jdk.jlink/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jlink/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -31,21 +31,23 @@ uses jdk.tools.jlink.plugin.Plugin; - provides java.util.spi.ToolProvider with jdk.tools.jmod.Main.JmodToolProvider; - provides java.util.spi.ToolProvider with jdk.tools.jlink.internal.Main.JlinkToolProvider; + provides java.util.spi.ToolProvider with + jdk.tools.jmod.Main.JmodToolProvider, + jdk.tools.jlink.internal.Main.JlinkToolProvider; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.FileCopierPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.StripDebugPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludePlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.OrderResourcesPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.DefaultCompressPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeVMPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin; - provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ClassForNamePlugin; + provides jdk.tools.jlink.plugin.Plugin with + jdk.tools.jlink.internal.plugins.FileCopierPlugin, + jdk.tools.jlink.internal.plugins.StripDebugPlugin, + jdk.tools.jlink.internal.plugins.ExcludePlugin, + jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin, + jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin, + jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin, + jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin, + jdk.tools.jlink.internal.plugins.OrderResourcesPlugin, + jdk.tools.jlink.internal.plugins.DefaultCompressPlugin, + jdk.tools.jlink.internal.plugins.ExcludeVMPlugin, + jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin, + jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin, + jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin, + jdk.tools.jlink.internal.plugins.ClassForNamePlugin; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.jvmstat/share/classes/module-info.java --- a/jdk/src/jdk.jvmstat/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.jvmstat/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -36,7 +36,8 @@ jdk.jstatd; uses sun.jvmstat.monitor.MonitoredHostService; - provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService; - provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService; + provides sun.jvmstat.monitor.MonitoredHostService with + sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService, + sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.localedata/share/classes/module-info.java --- a/jdk/src/jdk.localedata/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.localedata/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,8 +25,7 @@ module jdk.localedata { provides sun.util.locale.provider.LocaleDataMetaInfo with - sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo; - provides sun.util.locale.provider.LocaleDataMetaInfo with + sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo, sun.util.resources.provider.NonBaseLocaleDataMetaInfo; provides sun.util.resources.LocaleData.CommonResourceBundleProvider with sun.util.resources.provider.LocaleDataProvider; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java --- a/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java Thu Dec 01 08:57:53 2016 +0000 @@ -238,9 +238,4 @@ } } - - // for sun.management.MappedMXBeanType - static CompositeData toCompositeData(VMOption option) { - return VMOptionCompositeData.toCompositeData(option); - } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.management/share/classes/module-info.java --- a/jdk/src/jdk.management/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.management/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,7 @@ */ module jdk.management { - requires public java.management; + requires transitive java.management; exports com.sun.management; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.naming.dns/share/classes/module-info.java --- a/jdk/src/jdk.naming.dns/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.naming.dns/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,8 +26,8 @@ module jdk.naming.dns { requires java.naming; - exports com.sun.jndi.url.dns to - java.naming; + // temporary export until NamingManager.getURLContext uses services + exports com.sun.jndi.url.dns to java.naming; provides javax.naming.spi.InitialContextFactory with com.sun.jndi.dns.DnsContextFactory; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java Thu Dec 01 08:57:53 2016 +0000 @@ -54,14 +54,7 @@ private static final long serialVersionUID = 2345199581042573224L; private static final java.util.ResourceBundle rb = - java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction() { - public java.util.ResourceBundle run() { - return (java.util.ResourceBundle.getBundle - ("sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule())); - } - }); + java.util.ResourceBundle.getBundle("sun.security.util.AuthResources"); /** * @serial diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java Thu Dec 01 08:57:53 2016 +0000 @@ -53,15 +53,7 @@ private static final long serialVersionUID = -3178578484679887104L; private static final java.util.ResourceBundle rb = - java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction() { - public java.util.ResourceBundle run() { - return (java.util.ResourceBundle.getBundle - ("sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule())); - } - }); - + java.util.ResourceBundle.getBundle("sun.security.util.AuthResources"); /** * @serial diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java Thu Dec 01 08:57:53 2016 +0000 @@ -51,14 +51,7 @@ private static final long serialVersionUID = -7840670002439379038L; private static final java.util.ResourceBundle rb = - java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction() { - public java.util.ResourceBundle run() { - return (java.util.ResourceBundle.getBundle - ("sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule())); - } - }); + java.util.ResourceBundle.getBundle("sun.security.util.AuthResources"); /** diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java Thu Dec 01 08:57:53 2016 +0000 @@ -56,14 +56,7 @@ private static final long serialVersionUID = -8222422609431628648L; private static final java.util.ResourceBundle rb = - java.security.AccessController.doPrivileged - (new java.security.PrivilegedAction() { - public java.util.ResourceBundle run() { - return (java.util.ResourceBundle.getBundle - ("sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule())); - } - }); + java.util.ResourceBundle.getBundle("sun.security.util.AuthResources"); /** * @serial diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java Thu Dec 01 08:57:53 2016 +0000 @@ -153,15 +153,8 @@ */ public class JndiLoginModule implements LoginModule { - private static final ResourceBundle rb = AccessController.doPrivileged( - new PrivilegedAction() { - public ResourceBundle run() { - return ResourceBundle.getBundle( - "sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule()); - } - } - ); + private static final ResourceBundle rb = + ResourceBundle.getBundle("sun.security.util.AuthResources"); /** JNDI Provider */ public final String USER_PROVIDER = "user.provider.url"; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java Thu Dec 01 08:57:53 2016 +0000 @@ -112,15 +112,8 @@ */ public class KeyStoreLoginModule implements LoginModule { - private static final ResourceBundle rb = AccessController.doPrivileged( - new PrivilegedAction() { - public ResourceBundle run() { - return ResourceBundle.getBundle( - "sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule()); - } - } - ); + private static final ResourceBundle rb = + ResourceBundle.getBundle("sun.security.util.AuthResources"); /* -- Fields -- */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Thu Dec 01 08:57:53 2016 +0000 @@ -419,15 +419,8 @@ private static final String NAME = "javax.security.auth.login.name"; private static final String PWD = "javax.security.auth.login.password"; - private static final ResourceBundle rb = AccessController.doPrivileged( - new PrivilegedAction() { - public ResourceBundle run() { - return ResourceBundle.getBundle( - "sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule()); - } - } - ); + private static final ResourceBundle rb = + ResourceBundle.getBundle("sun.security.util.AuthResources"); /** * Initialize this {@code LoginModule}. diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java Thu Dec 01 08:57:53 2016 +0000 @@ -306,15 +306,8 @@ public class LdapLoginModule implements LoginModule { // Use the default classloader for this class to load the prompt strings. - private static final ResourceBundle rb = AccessController.doPrivileged( - new PrivilegedAction() { - public ResourceBundle run() { - return ResourceBundle.getBundle( - "sun.security.util.AuthResources", - sun.security.util.ResourcesMgr.class.getModule()); - } - } - ); + private static final ResourceBundle rb = + ResourceBundle.getBundle("sun.security.util.AuthResources"); // Keys to retrieve the stored username and password private static final String USERNAME_KEY = "javax.security.auth.login.name"; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.auth/share/classes/module-info.java --- a/jdk/src/jdk.security.auth/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.auth/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,24 +28,22 @@ * various authentication modules. */ module jdk.security.auth { - requires public java.naming; + requires transitive java.naming; requires java.security.jgss; exports com.sun.security.auth; exports com.sun.security.auth.callback; exports com.sun.security.auth.login; exports com.sun.security.auth.module; - provides javax.security.auth.spi.LoginModule with - com.sun.security.auth.module.Krb5LoginModule; - provides javax.security.auth.spi.LoginModule with - com.sun.security.auth.module.UnixLoginModule; + + uses sun.security.util.AuthResourcesProvider; + provides javax.security.auth.spi.LoginModule with - com.sun.security.auth.module.JndiLoginModule; - provides javax.security.auth.spi.LoginModule with - com.sun.security.auth.module.KeyStoreLoginModule; - provides javax.security.auth.spi.LoginModule with - com.sun.security.auth.module.LdapLoginModule; - provides javax.security.auth.spi.LoginModule with + com.sun.security.auth.module.Krb5LoginModule, + com.sun.security.auth.module.UnixLoginModule, + com.sun.security.auth.module.JndiLoginModule, + com.sun.security.auth.module.KeyStoreLoginModule, + com.sun.security.auth.module.LdapLoginModule, com.sun.security.auth.module.NTLoginModule; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.security.jgss/share/classes/module-info.java --- a/jdk/src/jdk.security.jgss/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,7 +28,7 @@ * GSSAPI mechanism. */ module jdk.security.jgss { - requires public java.security.jgss; + requires transitive java.security.jgss; requires java.logging; requires java.security.sasl; exports com.sun.security.jgss; diff -r 7a4a59859ac0 -r a60f280f803c jdk/src/jdk.unsupported/share/classes/module-info.java --- a/jdk/src/jdk.unsupported/share/classes/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/src/jdk.unsupported/share/classes/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,5 +27,8 @@ exports sun.misc; exports sun.reflect; exports com.sun.nio.file; + + opens sun.misc; + opens sun.reflect; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/ProblemList.txt Thu Dec 01 08:57:53 2016 +0000 @@ -145,10 +145,17 @@ ############################################################################ -# jdk_jmx +# jdk_management com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8030957 aix-all com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java 8030957 aix-all + +com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java 8169575 generic-all + +############################################################################ + +# jdk_jmx + javax/management/MBeanServer/OldMBeanServerTest.java 8030957 aix-all javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java 8042215 generic-all @@ -302,4 +309,6 @@ com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java 8141370 linux-i586,macosx-all +javax/xml/ws/clientjar/TestWsImport.java 8170370 generic-all + ############################################################################ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/TEST.ROOT --- a/jdk/test/TEST.ROOT Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/TEST.ROOT Thu Dec 01 08:57:53 2016 +0000 @@ -26,8 +26,8 @@ # Allow querying of various System properties in @requires clauses requires.properties=sun.arch.data.model java.runtime.name -# Tests using jtreg 4.2 b03 features -requiredVersion=4.2 b03 +# Tests using jtreg 4.2 b04 features +requiredVersion=4.2 b04 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/corba/serialization/ObjectStreamTest.java --- a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -62,9 +62,10 @@ * @test * @library /test/lib * @build jdk.test.lib.* - * @compile ObjectStreamTest.java ObjectStreamTest$_Echo_Stub.java - * ObjectStreamTest$_Server_Tie.java - * @modules java.corba/com.sun.corba.se.impl.io java.base/java.io + * @compile ObjectStreamTest.java ObjectStreamTest$_Echo_Stub.java + * ObjectStreamTest$_Server_Tie.java + * @modules java.base/java.io:open + * java.corba/com.sun.corba.se.impl.io:+open * java.corba/com.sun.corba.se.impl.activation * @summary Tests of ReflectionFactory use in IIOP Serialization * @run testng/othervm ObjectStreamTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,7 @@ /* * @test * @bug 8069072 - * @modules java.base/com.sun.crypto.provider + * @modules java.base/com.sun.crypto.provider:open * @summary Test vectors for com.sun.crypto.provider.GHASH. * * Single iteration to verify software-only GHASH algorithm. diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java --- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,8 @@ /** * @test * @bug 8151149 - * @modules java.base/com.sun.crypto.provider + * @modules java.base/javax.crypto:open + * java.base/com.sun.crypto.provider:+open */ import java.lang.reflect.*; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java --- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,6 +24,7 @@ /* * @test * @bug 8001596 + * @modules java.base/javax.crypto.spec:open * @summary Incorrect condition check in PBKDF2KeyImpl.java */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/jdi/ConstantPoolInfoGC.java --- a/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,7 +28,7 @@ * * @author Egor Ushakov * - * @modules jdk.jdi/com.sun.tools.jdi + * @modules jdk.jdi/com.sun.tools.jdi:+open * @run build TestScaffold VMConnection * @run compile -g ConstantPoolInfoGC.java * @run main/othervm ConstantPoolInfoGC diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/jdi/ModulesTest.java --- a/jdk/test/com/sun/jdi/ModulesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/jdi/ModulesTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -78,7 +78,6 @@ } // Sanity checks: make sure there is no crash or exception String otherName = other.name(); - boolean cond = module.canRead(other); return true; } @@ -159,8 +158,6 @@ } bootUnnamedModule = module; } - boolean cond = module.canRead(other); - println(" can read: " + cond); } // Check that the java.lang.String class was loaded by the java.base module. @@ -198,24 +195,6 @@ testFailed = true; println(FailPrefix + "unnamed module of PlatformClassLoader was not observed"); } - - for (ModuleReference module : modules) { - if (!bootUnnamedModule.canRead(module)) { - testFailed = true; - println(FailPrefix + "boot unnamed module must read any module" + - "but a non-readible module is found: " + module.name()); - } - if (!appUnnamedModule.canRead(module)) { - testFailed = true; - println(FailPrefix + "app unnamed module must read any module" + - "but a non-readible module is found: " + module.name()); - } - if (!extUnnamedModule.canRead(module)) { - testFailed = true; - println(FailPrefix + "ext unnamed module must read any module" + - "but a non-readible module is found: " + module.name()); - } - } } protected void runTests() throws Exception { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java --- a/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,8 +30,8 @@ * to encapsulate the transport. This tests that the connectors are * created and that they have an "address" argument. * - * @modules jdk.jdi - * @build GeneratedConnectors NullTransportService + * @modules jdk.jdi/com.sun.tools.jdi + * @build GeneratedConnectors NullTransportService SimpleLaunchingConnector * @run main/othervm GeneratedConnectors */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java --- a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -33,7 +33,7 @@ * with a lower-case letter * * @author Jaroslav Bachorik - * @modules java.management/com.sun.jmx.mbeanserver + * @modules java.management/com.sun.jmx.mbeanserver:open * @run clean SimpleIntrospectorTest * @run build SimpleIntrospectorTest BeanClass * @run main SimpleIntrospectorTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/jndi/dns/Parser.java --- a/jdk/test/com/sun/jndi/dns/Parser.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/jndi/dns/Parser.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,7 @@ * @test * @bug 8035105 * @summary DNS resource record parsing - * @modules jdk.naming.dns/com.sun.jndi.dns + * @modules jdk.naming.dns/com.sun.jndi.dns:+open * @compile --add-modules jdk.naming.dns Parser.java */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java --- a/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,7 @@ * @test * @bug 8158802 * @summary com.sun.jndi.ldap.SimpleClientId produces wrong hash code - * @modules java.naming/com.sun.jndi.ldap + * @modules java.naming/com.sun.jndi.ldap:open */ import java.io.OutputStream; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/com/sun/management/VMOptionOpenDataTest.java --- a/jdk/test/com/sun/management/VMOptionOpenDataTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/com/sun/management/VMOptionOpenDataTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,58 +21,77 @@ * questions. */ +import com.sun.management.HotSpotDiagnosticMXBean; import com.sun.management.VMOption; -import java.io.InvalidObjectException; -import java.util.Objects; -import javax.management.openmbean.OpenDataException; -import sun.management.MappedMXBeanType; +import java.lang.management.ManagementFactory; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import javax.management.MBeanServerConnection; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; + +import static javax.management.openmbean.SimpleType.*; /* * @test * @bug 8042901 * @summary Check that MappedMXBeanType.toOpenTypeData supports VMOption - * @modules java.management/sun.management - * jdk.management/com.sun.management + * @modules jdk.management/com.sun.management * @author Shanliang Jiang */ public class VMOptionOpenDataTest { - public static void main(String[] args) throws Exception { - System.out.println("--- VMOptionOpenDataTest-main: Checking that " - + "MappedMXBeanType.toOpenTypeData supports VMOption"); - Exception failed = null; - try { - VMOption vo = new VMOption("toto", "titi", true, VMOption.Origin.OTHER); - System.out.println("--- Construct a VMOption object: \"" + vo + "\""); + private static final String[] names = new String[] { + "name", "value", "origin", "writeable" + }; + private static final OpenType[] types = new OpenType[] { + STRING, STRING, STRING, BOOLEAN + }; - Object open = MappedMXBeanType.toOpenTypeData(vo, VMOption.class); - System.out.println("--- Map it to an open type: \"" + open +" \""); + public static void main(String... args) throws Exception { + MBeanServerConnection msc = ManagementFactory.getPlatformMBeanServer(); + HotSpotDiagnosticMXBean mxbean = + ManagementFactory.getPlatformMXBean(msc, HotSpotDiagnosticMXBean.class); + - Object back = MappedMXBeanType.toJavaTypeData(open, VMOption.class); - System.out.println("--- Map it back to java type: \"" + back +" \""); + String[] signatures = new String[] { + String.class.getName() + }; + Object obj = msc.invoke(mxbean.getObjectName(), "getVMOption", + new String[] { "PrintVMOptions"}, signatures); - if (back == null) { - failed = new RuntimeException("Failed, mapping back got null."); - } else if (!(back instanceof VMOption)) { - failed = new RuntimeException("Failed, not mapped back to a VMOption: " - +back.getClass()); - } else { - VMOption mapBack = (VMOption)back; - if (!Objects.equals(vo.getName(), mapBack.getName()) || - !Objects.equals(vo.getOrigin(), mapBack.getOrigin()) || - !Objects.equals(vo.getValue(), mapBack.getValue()) || - vo.isWriteable() != mapBack.isWriteable()) { - failed = new RuntimeException( - "Failed, failed to map back the original VMOtion."); - } + CompositeData data = (CompositeData)obj; + validateType(data); + + VMOption option = mxbean.getVMOption("PrintVMOptions"); + VMOption o = VMOption.from(data); + assertEquals(option, o); + } + + private static void validateType(CompositeData data) { + CompositeType type = data.getCompositeType(); + Set keys = Arrays.stream(names).collect(Collectors.toSet()); + if (!type.keySet().equals(keys)) { + throw new RuntimeException("key not matched: " + type.keySet().toString()); + } + for (int i=0; i < names.length; i++) { + OpenType t = type.getType(names[i]); + if (t != types[i]) { + throw new AssertionError(names[i] + ": type not matched: " + + t + " expected: " + types[i]); } - } catch (OpenDataException | InvalidObjectException ode) { - failed = ode; - } - if (failed == null) { - System.out.println("--- PASSED!"); - } else { - System.out.println("--- Failed: "+failed.getMessage()); - throw failed; } } + + private static void assertEquals(VMOption o1, VMOption o2) { + if (!o1.getName().equals(o2.getName()) || + !o1.getOrigin().equals(o2.getOrigin()) || + !o1.getValue().equals(o2.getValue()) || + o1.isWriteable() != o2.isWriteable()) { + throw new AssertionError(o1 + " != " + o2); + } + + } + } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java --- a/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,7 @@ @summary [macosx] TwentyThousandTest test intermittently hangs @author Oleg Pekhovskiy @modules java.desktop/sun.awt + @modules java.desktop/java.awt:open @run main EDTShutdownTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java --- a/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ @library ../../regtesthelpers @modules java.desktop/java.awt.peer java.desktop/sun.awt + java.desktop/java.awt:open @build Util @run main RequestOnCompWithNullParent1 */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html --- a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html Thu Dec 01 08:57:53 2016 +0000 @@ -30,7 +30,7 @@ @requires (os.family == "linux" | os.family == "solaris") @modules java.desktop/sun.awt java.desktop/java.awt.peer - java.desktop/sun.awt.X11 + java.desktop/sun.awt.X11:open @run applet FocusEmptyListTest.html --> diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java --- a/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,7 @@ @summary The test checks that Container's method startLWModal and stopLWModal work correctly. The test scenario is very close to JOptionPane.showInternal*Dialog methods + @modules java.desktop/java.awt:open @author artem.ananiev@...: area=awt.modal @library ../../regtesthelpers @build Util diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java --- a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,7 +34,7 @@ * @requires (os.family == "linux" | os.family == "solaris") * @modules java.desktop/sun.awt * java.desktop/java.awt.peer - * java.desktop/sun.awt.X11 + * java.desktop/sun.awt.X11:open * @author Sean Chou */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh --- a/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh Thu Dec 01 08:57:53 2016 +0000 @@ -154,16 +154,16 @@ case "$OS" in Windows* | CYGWIN* ) ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - --add-exports java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \ + --add-opens java.desktop/sun.awt=ALL-UNNAMED \ + --add-opens java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \ TestWrapped sun.awt.windows.WToolkit status=$? if [ ! $status -eq "0" ]; then fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.windows.WToolkit"; fi ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - --add-exports java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \ + --add-opens java.desktop/sun.awt=ALL-UNNAMED \ + --add-opens java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \ -Dawt.toolkit=sun.awt.windows.WToolkit \ TestWrapped sun.awt.windows.WToolkit status=$? @@ -174,8 +174,8 @@ SunOS | Linux ) ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - --add-exports java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \ + --add-opens java.desktop/sun.awt=ALL-UNNAMED \ + --add-opens java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \ -Dawt.toolkit=sun.awt.X11.XToolkit \ TestWrapped sun.awt.X11.XToolkit status=$? @@ -183,8 +183,8 @@ fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.xawt.XToolkit"; fi AWT_TOOLKIT=XToolkit ${TESTJAVA}/bin/java ${TESTVMOPTS} \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - --add-exports java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \ + --add-opens java.desktop/sun.awt=ALL-UNNAMED \ + --add-opens java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \ -Djava.awt.headless=true \ TestWrapped sun.awt.X11.XToolkit status=$? @@ -195,16 +195,16 @@ Darwin) ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \ + --add-opens java.desktop/sun.awt=ALL-UNNAMED \ + --add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \ TestWrapped sun.lwawt.macosx.LWCToolkit status=$? if [ ! $status -eq "0" ]; then fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.lwawt.macosx.LWCToolkit"; fi ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \ - --add-exports java.desktop/sun.awt=ALL-UNNAMED \ - --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \ + --add-opens java.desktop/sun.awt=ALL-UNNAMED \ + --add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \ -Dawt.toolkit=sun.lwawt.macosx.LWCToolkit \ TestWrapped sun.lwawt.macosx.LWCToolkit status=$? diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java --- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,7 @@ * of the ActionEvent triggered when TrayIcon is double clicked * (single clicked, on Mac) * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library ../../../../lib/testlibrary ../ * @library /java/awt/patchlib * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java --- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java Thu Dec 01 08:57:53 2016 +0000 @@ -33,6 +33,7 @@ * triggered when multiple AWTEventListeners and ActionListeners * are added. * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java --- a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,8 @@ * @test * @bug 6191390 8154328 * @summary Verify that ActionEvent is received with correct modifiers set. + * @modules java.desktop/java.awt:open + * @modules java.desktop/java.awt.peer * @library ../../../../lib/testlibrary ../ * @library /java/awt/patchlib * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java --- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * @test * @summary Check for MouseEvents with all mouse buttons * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build ExtendedRobot SystemTrayIconHelper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java --- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,6 +32,7 @@ * checks if all listeners are triggered when AWTEventListeners * and MouseListeners are added. * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java --- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * @test * @summary Check for MouseEvents with all mouse buttons * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../../lib/testlibrary ../../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java --- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -39,6 +39,7 @@ * @key headful * @summary Check if MouseEvent has the proper modifiers when * TrayIcon is clicked pressing the modifier keys + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java --- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,7 @@ * @test * @summary Check for MouseEvents with all mouse buttons * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java --- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,6 +34,7 @@ * it is double clicked with mouse button 1 on windows * or single clicked with button 3 on Mac OS X * or single clicked with button 1 on rest. + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java --- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * @summary Check if a JPopupMenu can be displayed when TrayIcon is * right clicked. It uses a JWindow as the parent of the JPopupMenu * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) + * @modules java.desktop/java.awt:open * @library /java/awt/patchlib * @library ../../../../lib/testlibrary ../ * @build java.desktop/java.awt.Helper diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java --- a/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,7 @@ @key headful @bug 6758673 @summary Tests that windows are removed from owner's child windows list + @modules java.desktop/java.awt:open @author art: area=awt.toplevel @run main/othervm -mx128m OwnedWindowsLeak */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java --- a/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,7 @@ @bug 6315717 @summary verifies that InputEvents button masks arrays are the same @author Andrei Dmitriev : area=awt.event + @modules java.desktop/java.awt.event:open @run main ButtonArraysEquality */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java --- a/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ @test %I% %E% @key headful @bug 6315717 + @modules java.desktop/java.awt.event:open @summary verifies that InputEvent.getMaskForButton() returns the same values as in InputEvent.BUTTON_DOWN_MASK @author Andrei Dmitriev : area=awt.event @run main CheckGetMaskForButton diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java --- a/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,7 @@ /* * @test * @bug 4351212 - * @modules java.desktop/sun.font + * @modules java.desktop/sun.font:open * @summary Verify that new getLCIDFromLocale method works */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/image/MultiResolutionImageTest.java --- a/jdk/test/java/awt/image/MultiResolutionImageTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/image/MultiResolutionImageTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -48,7 +48,7 @@ * @requires (os.family == "mac") * @modules java.desktop/sun.awt * java.desktop/sun.awt.image - * java.desktop/sun.lwawt.macosx + * java.desktop/sun.lwawt.macosx:open * @run main MultiResolutionImageTest TOOLKIT_PREPARE * @run main MultiResolutionImageTest TOOLKIT_LOAD * @run main MultiResolutionImageTest TOOLKIT diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java --- a/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,6 @@ public class Helper { private Helper() { } public static void addExports(String pn, Module target) { - java.awt.Component.class.getModule().addExports(pn, target); + java.awt.Component.class.getModule().addOpens(pn, target); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java --- a/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 6380849 * @summary Tests BeanInfo finder + * @modules java.desktop/java.beans:open * @author Sergey Malenkov */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java --- a/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8007458 * @summary Tests CardLayout encoding + * @modules java.desktop/java.awt:open * @author Sergey Malenkov */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java --- a/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8007458 * @summary Tests GridBagLayout encoding + * @modules java.desktop/java.awt:open * @author Sergey Malenkov */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/io/FilePermission/Correctness.java --- a/jdk/test/java/io/FilePermission/Correctness.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/io/FilePermission/Correctness.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * * @test * @bug 8164705 + * @modules java.base/java.io:open * @summary Remove pathname canonicalization from FilePermission */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java --- a/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,7 @@ /* * @test * @bug 8067870 + * @modules java.base/java.io:open * @summary verifies java.io.ObjectInputStream.PeekInputStream.skip works * as intended */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java --- a/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,8 @@ * @bug 8080535 * @summary Expected size of Character.UnicodeBlock.map is not optimal * @library /lib/testlibrary + * @modules java.base/java.lang:open + * java.base/java.util:open * @build jdk.testlibrary.OptimalCapacity * @run main OptimalMapSize */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/GetModuleTest.java --- a/jdk/test/java/lang/Class/GetModuleTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/GetModuleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -31,7 +31,6 @@ */ import java.awt.Component; -import java.lang.reflect.Field; import java.lang.reflect.Module; import jdk.internal.org.objectweb.asm.ClassWriter; @@ -44,16 +43,7 @@ public class GetModuleTest { - static final Unsafe U; - static { - try { - Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - U = (Unsafe) theUnsafe.get(null); - } catch (Exception e) { - throw new AssertionError(e); - } - } + private static final Unsafe U = Unsafe.getUnsafe(); private static final Module TEST_MODULE = GetModuleTest.class.getModule(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java --- a/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -44,7 +44,7 @@ try { Class c = findClass(m1, "p1.internal.B"); c.newInstance(); - throw new RuntimeException(c.getName() + " is not exported to m2"); + throw new RuntimeException(c.getName() + " should not be exported to m2"); } catch (IllegalAccessException e) {} } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java --- a/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -40,6 +40,7 @@ * set accessible if the right permission is granted; this test * also verifies that Class.classLoader final private field is * hidden from reflection access. + * @modules java.base/java.lang:open * @run main/othervm ClassDeclaredFieldsTest UNSECURE * @run main/othervm ClassDeclaredFieldsTest SECURE * diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java --- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -58,9 +58,9 @@ /** * @test * @bug 8065552 - * @summary test that all fields returned by getDeclaredFields() can be - * set accessible if the right permission is granted; this test - * loads all the classes in the BCL, get their declared fields, + * @summary test that all public fields returned by getDeclaredFields() can + * be set accessible if the right permission is granted; this test + * loads all classes and get their declared fields * and call setAccessible(false) followed by setAccessible(true); * @modules java.base/jdk.internal.module * @run main/othervm --add-modules=ALL-SYSTEM FieldSetAccessibleTest UNSECURE @@ -81,24 +81,30 @@ // Test that all fields for any given class can be made accessibles - static void testSetFieldsAccessible(Class c, boolean expectException) { + static void testSetFieldsAccessible(Class c) { + Module self = FieldSetAccessibleTest.class.getModule(); + Module target = c.getModule(); + String pn = c.getPackageName(); + boolean exported = self.canRead(target) && target.isExported(pn, self); for (Field f : c.getDeclaredFields()) { fieldCount.incrementAndGet(); - boolean expect = expectException; - if ((c == Module.class || c == AccessibleObject.class) && - !Modifier.isPublic(f.getModifiers())) { - expect = true; - } + + // setAccessible succeeds only if it's exported and the member + // is public and of a public class, or it's opened + // otherwise it would fail. + boolean isPublic = Modifier.isPublic(f.getModifiers()) && + Modifier.isPublic(c.getModifiers()); + boolean access = (exported && isPublic) || target.isOpen(pn, self); try { f.setAccessible(false); f.setAccessible(true); - if (expect) { + if (!access) { throw new RuntimeException( String.format("Expected InaccessibleObjectException is not thrown " + "for field %s in class %s%n", f.getName(), c.getName())); } } catch (InaccessibleObjectException expected) { - if (!expect) { + if (access) { throw new RuntimeException(expected); } } @@ -110,18 +116,17 @@ public static boolean test(Class c, boolean addExports) { Module self = FieldSetAccessibleTest.class.getModule(); Module target = c.getModule(); - String pn = c.getPackage().getName(); + String pn = c.getPackageName(); boolean exported = self.canRead(target) && target.isExported(pn, self); if (addExports && !exported) { Modules.addExports(target, pn, self); exported = true; } - boolean expectException = !exported; classCount.incrementAndGet(); // Call getDeclaredFields() and try to set their accessible flag. - testSetFieldsAccessible(c, expectException); + testSetFieldsAccessible(c); // add more tests here... diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/Main.java --- a/jdk/test/java/lang/Class/getResource/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getResource/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,6 @@ import java.lang.module.Configuration; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -33,8 +32,8 @@ import java.nio.file.Paths; /** - * Basic test of Class getResource and getResourceAsStream when invoked from - * code in named modules. + * Basic test of Class getResource and getResourceAsStream to locate/read + * resources in named modules. */ public class Main { @@ -43,62 +42,192 @@ public static void main(String[] args) throws IOException { - // create m1/myresource containing "m1" - Path file = directoryFor("m1").resolve(NAME); - Files.write(file, "m1".getBytes("UTF-8")); + // create resources in m1 + createResource("m1", Paths.get("."), "m1"); + createResource("m1", Paths.get("p1"), "m1/p1"); + createResource("m1", Paths.get("p1", "impl"), "m1/p1.impl"); + createResource("m1", Paths.get("p1", "resources"), "m1/p1.resources"); + + // create resources in m2 + createResource("m2", Paths.get("."), "m2"); + createResource("m2", Paths.get("p2"), "m2/p2"); + createResource("m2", Paths.get("p2", "impl"), "m2/p2.impl"); + createResource("m2", Paths.get("p2", "resources"), "m2/p2.resources"); + + + // invoke Class getResource from an unnamed module. + URL url = Main.class.getResource("/" + NAME); + assertNotNull(url); + + url = Main.class.getResource("/p1/" + NAME); + assertNull(url); - // create m2/myresource containing "m2" - file = directoryFor("m2").resolve(NAME); - Files.write(file, "m2".getBytes("UTF-8")); + url = Main.class.getResource("/p1/impl/" + NAME); + assertNull(url); + + url = Main.class.getResource("/p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); + + url = Main.class.getResource("/p2/" + NAME); + assertNull(url); + + url = Main.class.getResource("/p2/impl/" + NAME); + assertNull(url); - // check that m3/myresource does not exist - assertTrue(Files.notExists(directoryFor("m3").resolve(NAME))); + // m1: exports private p1.resources + url = Main.class.getResource("/p2/resources/" + NAME); + assertNull(url); + + + // invoke Class getResource from module m1 + url = p1.Main.getResource("/" + NAME); + assertEquals(readAllAsString(url), "m1"); + + url = p1.Main.getResource("/p1/" + NAME); + assertEquals(readAllAsString(url), "m1/p1"); - // invoke Class getResource from the unnamed module - URL url0 = Main.class.getResource("/" + NAME); - assertNull(url0); + url = p1.Main.getResource("/p1/impl/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.impl"); + + url = p1.Main.getResource("/p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); + + // m2: not a named package + url = p1.Main.getResource(p2.Main.class, "/" + NAME); + assertEquals(readAllAsString(url), "m2"); + + url = p1.Main.getResource(p2.Main.class, "/p2/" + NAME); + assertNull(url); + + // m2: exports p2.impl to m1 + url = p1.Main.getResource(p2.Main.class, "/p2/impl/" + NAME); + assertNull(url); + + // m2: exports private p2.resources to m1; + url = p1.Main.getResource(p2.Main.class, "/p2/resources/" + NAME); + assertEquals(readAllAsString(url), "m2/p2.resources"); + - // invoke Class getResource from modules m1-m3 - URL url1 = p1.Main.getResource("/" + NAME); - URL url2 = p2.Main.getResource("/" + NAME); - URL url3 = p3.Main.getResource("/" + NAME); - assertNotNull(url1); - assertNotNull(url2); - assertNull(url3); + // invoke Class getResource from module m2 + url = p2.Main.getResource("/" + NAME); + assertEquals(readAllAsString(url), "m2"); + + url = p2.Main.getResource("/p2/" + NAME); + assertEquals(readAllAsString(url), "m2/p2"); + + url = p2.Main.getResource("/p2/impl/" + NAME); + assertEquals(readAllAsString(url), "m2/p2.impl"); + + url = p2.Main.getResource("/p2/resources/" + NAME); + assertEquals(readAllAsString(url), "m2/p2.resources"); - // check contents of resurces at url1 and url2 - assertEquals(new String(readAll(url1), "UTF-8"), "m1"); - assertEquals(new String(readAll(url2), "UTF-8"), "m2"); + // m1: not a named package + url = p2.Main.getResource(p1.Main.class, "/" + NAME); + assertEquals(readAllAsString(url), "m1"); + + url = p2.Main.getResource(p1.Main.class, "/p1/" + NAME); + assertNull(url); + + url = p2.Main.getResource(p1.Main.class, "/p1/impl/" + NAME); + assertNull(url); + + // m1: exports private p1.resources; + url = p2.Main.getResource(p1.Main.class, "/p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); - // invoke Class getResourceAsStream from the unnamed module - InputStream in0 = Main.class.getResourceAsStream("/" + NAME); - assertNull(in0); + + // invoke Class getResourceAsStream from an unnamed module. + InputStream in = Main.class.getResourceAsStream("/" + NAME); + assertNotNull(in); + + in = Main.class.getResourceAsStream("/p1/" + NAME); + assertNull(in); + + in = Main.class.getResourceAsStream("/p1/impl/" + NAME); + assertNull(in); + + in = Main.class.getResourceAsStream("/p1/resources/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.resources"); + + in = Main.class.getResourceAsStream("/p2/" + NAME); + assertNull(in); + + in = Main.class.getResourceAsStream("/p2/impl/" + NAME); + assertNull(in); + + in = Main.class.getResourceAsStream("/p2/resources/" + NAME); + assertNull(in); + + + // invoke Class getResourceAsStream from module m1 + in = p1.Main.getResourceAsStream("/" + NAME); + assertEquals(readAllAsString(in), "m1"); + + in = p1.Main.getResourceAsStream("/p1/" + NAME); + assertEquals(readAllAsString(in), "m1/p1"); + + in = p1.Main.getResourceAsStream("/p1/impl/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.impl"); + + in = p1.Main.getResourceAsStream("/p1/resources/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.resources"); + + in = p1.Main.getResourceAsStream(p2.Main.class, "/" + NAME); + assertEquals(readAllAsString(in), "m2"); + + in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/" + NAME); + assertNull(in); + + in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/impl/" + NAME); + assertNull(in); - // invoke Class getResourceAsStream from modules m1-m3 - try (InputStream in = p1.Main.getResourceAsStream("/" + NAME)) { - String s = new String(in.readAllBytes(), "UTF-8"); - assertEquals(s, "m1"); - } - try (InputStream in = p2.Main.getResourceAsStream("/" + NAME)) { - String s = new String(in.readAllBytes(), "UTF-8"); - assertEquals(s, "m2"); - } - InputStream in3 = p3.Main.getResourceAsStream("/" + NAME); - assertNull(in3); + in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/resources/" + NAME); + assertEquals(readAllAsString(in), "m2/p2.resources"); + + + // invoke Class getResourceAsStream from module m2 + in = p2.Main.getResourceAsStream("/" + NAME); + assertEquals(readAllAsString(in), "m2"); + + in = p2.Main.getResourceAsStream("/p2/" + NAME); + assertEquals(readAllAsString(in), "m2/p2"); + + in = p2.Main.getResourceAsStream("/p2/impl/" + NAME); + assertEquals(readAllAsString(in), "m2/p2.impl"); + + in = p2.Main.getResourceAsStream("/p2/resources/" + NAME); + assertEquals(readAllAsString(in), "m2/p2.resources"); + + in = p2.Main.getResourceAsStream(p1.Main.class, "/" + NAME); + assertEquals(readAllAsString(in), "m1"); + + in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/" + NAME); + assertNull(in); - // invoke Module getResources on modules m1-m3 - InputStream in1 = p1.Main.class.getModule().getResourceAsStream("/" + NAME); - InputStream in2 = p2.Main.class.getModule().getResourceAsStream("/" + NAME); - in3 = p3.Main.class.getModule().getResourceAsStream("/" + NAME); - assertNotNull(in1); - assertNotNull(in2); - assertNull(in3); + in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/impl/" + NAME); + assertNull(in); + + in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/resources/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.resources"); + - // check the content of in1 and in2 - String s1 = new String(in1.readAllBytes(), "UTF-8"); - String s2 = new String(in2.readAllBytes(), "UTF-8"); - assertEquals(s1, "m1"); - assertEquals(s2, "m2"); + // Nulls + try { + Main.class.getResource(null); + assertTrue(false); + } catch (NullPointerException expected) { } + try { + Main.class.getResourceAsStream(null); + assertTrue(false); + } catch (NullPointerException expected) { } + try { + p1.Main.class.getResource(null); + assertTrue(false); + } catch (NullPointerException expected) { } + try { + p1.Main.class.getResourceAsStream(null); + assertTrue(false); + } catch (NullPointerException expected) { } // SecurityManager case System.setSecurityManager(new SecurityManager()); @@ -106,17 +235,24 @@ assertNull(Main.class.getResource("/" + NAME)); assertNull(p1.Main.getResource("/" + NAME)); assertNull(p2.Main.getResource("/" + NAME)); - assertNull(p3.Main.getResource("/" + NAME)); assertNull(Main.class.getResourceAsStream("/" + NAME)); assertNull(p1.Main.getResourceAsStream("/" + NAME)); assertNull(p2.Main.getResourceAsStream("/" + NAME)); - assertNull(p3.Main.getResourceAsStream("/" + NAME)); System.out.println("Success!"); } /** + * Create a resource in the sub-directory of the given exploded module + */ + static void createResource(String mn, Path subdir, String msg) throws IOException { + Path dir = directoryFor(mn).resolve(subdir); + Path file = dir.resolve(NAME); + Files.write(file, msg.getBytes("UTF-8")); + } + + /** * Returns the directory for the given module (by name). */ static Path directoryFor(String name) { @@ -130,12 +266,21 @@ return dir; } - static byte[] readAll(URL url) throws IOException { - try (InputStream in = url.openStream()) { - return in.readAllBytes(); + static String readAllAsString(InputStream in) throws IOException { + if (in == null) + return null; + try (in) { + return new String(in.readAllBytes(), "UTF-8"); } } + static String readAllAsString(URL url) throws IOException { + if (url == null) + return null; + InputStream in = url.openStream(); + return readAllAsString(url.openStream()); + } + static void assertTrue(boolean condition) { if (!condition) throw new RuntimeException(); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/ResourcesTest.java --- a/jdk/test/java/lang/Class/getResource/ResourcesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getResource/ResourcesTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -68,7 +68,7 @@ .compile(Paths.get(TEST_SRC, "Main.java"), CLASSES_DIR, "--module-path", MODS_DIR.toString(), - "--add-modules", "m1,m2,m3"); + "--add-modules", "m1,m2"); assertTrue(compiled); } @@ -80,7 +80,7 @@ int exitValue = executeTestJava("--module-path", MODS_DIR.toString(), - "--add-modules", "m1,m2,m3", + "--add-modules", "m1,m2", "-cp", CLASSES_DIR.toString(), "Main") .outputTo(System.out) diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m1/module-info.java --- a/jdk/test/java/lang/Class/getResource/src/m1/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,4 +23,5 @@ module m1 { exports p1; + opens p1.resources; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java --- a/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -36,4 +36,12 @@ public static InputStream getResourceAsStream(String name) { return Main.class.getResourceAsStream(name); } + + public static URL getResource(Class c, String name) { + return c.getResource(name); + } + + public static InputStream getResourceAsStream(Class c, String name) { + return c.getResourceAsStream(name); + } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1.impl; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1.resources; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m2/module-info.java --- a/jdk/test/java/lang/Class/getResource/src/m2/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,4 +23,6 @@ module m2 { exports p2; + exports p2.impl to m1; + opens p2.resources to m1; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java --- a/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -36,4 +36,12 @@ public static InputStream getResourceAsStream(String name) { return Main.class.getResourceAsStream(name); } + + public static URL getResource(Class c, String name) { + return c.getResource(name); + } + + public static InputStream getResourceAsStream(Class c, String name) { + return c.getResourceAsStream(name); + } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p2.impl; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p2.resources; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m3/module-info.java --- a/jdk/test/java/lang/Class/getResource/src/m3/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m3 { - exports p3; -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java --- a/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p3; - -import java.io.InputStream; -import java.net.URL; - -public class Main { - private Main() { } - - public static URL getResource(String name) { - return Main.class.getResource(name); - } - - public static InputStream getResourceAsStream(String name) { - return Main.class.getResourceAsStream(name); - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/LibraryPathProperty.java --- a/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,7 @@ * Quoted entries should get unquoted on Windows. * Empty entries should be replaced with dot. * @library /lib/testlibrary + * @modules java.base/java.lang:open * @build jdk.testlibrary.Platform * @run main LibraryPathProperty */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh --- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Thu Dec 01 08:57:53 2016 +0000 @@ -106,6 +106,7 @@ # run test ${TESTJAVA}${FS}bin${FS}java \ ${TESTVMOPTS} \ + --add-opens java.base/java.lang=ALL-UNNAMED \ -verbose:class -Xlog:class+load -cp . \ -Dtest.classes=${TESTCLASSES} \ Starter cross diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh --- a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh Thu Dec 01 08:57:53 2016 +0000 @@ -102,6 +102,7 @@ # run test ${TESTJAVA}${FS}bin${FS}java \ ${TESTVMOPTS} \ + --add-opens java.base/java.lang=ALL-UNNAMED \ -verbose:class -Xlog:class+load -cp . \ -Dtest.classes=${TESTCLASSES} \ Starter one-way diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/Main.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -21,13 +21,18 @@ * questions. */ +import java.io.InputStream; import java.lang.module.Configuration; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.io.IOException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; /** * Basic test of ClassLoader getResource and getResourceAsStream when @@ -40,36 +45,242 @@ public static void main(String[] args) throws IOException { - // create m1/myresource containing "m1" - Path file = directoryFor("m1").resolve(NAME); - Files.write(file, "m1".getBytes("UTF-8")); + // create resources in m1 + createResource("m1", Paths.get("."), "m1"); + createResource("m1", Paths.get("p1"), "m1/p1"); + createResource("m1", Paths.get("p1", "impl"), "m1/p1.impl"); + createResource("m1", Paths.get("p1", "resources"), "m1/p1.resources"); - // create m2/myresource containing "m2" - file = directoryFor("m2").resolve(NAME); - Files.write(file, "m2".getBytes("UTF-8")); + // create resources in m2 + createResource("m2", Paths.get("."), "m2"); + createResource("m2", Paths.get("p2"), "m2/p2"); + createResource("m2", Paths.get("p2", "impl"), "m2/p2.impl"); + createResource("m2", Paths.get("p2", "resources"), "m2/p2.resources"); - // check that m3/myresource does not exist - assertTrue(Files.notExists(directoryFor("m3").resolve(NAME))); // invoke ClassLoader getResource from the unnamed module - assertNull(Main.class.getClassLoader().getResource("/" + NAME)); + ClassLoader thisLoader = Main.class.getClassLoader(); + + URL url = thisLoader.getResource(NAME); + assertNotNull(url); + + url = thisLoader.getResource("p1/" + NAME); + assertNull(url); + + url = thisLoader.getResource("p1/impl/" + NAME); + assertNull(url); + + url = thisLoader.getResource("p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); + + url = thisLoader.getResource("p2/" + NAME); + assertNull(url); + + url = thisLoader.getResource("p2/impl/" + NAME); + assertNull(url); + + url = thisLoader.getResource("p2/resources/" + NAME); + assertNull(url); + + + // invoke ClassLoader getResource from module m1 + url = p1.Main.getResourceInClassLoader(NAME); + assertNotNull(url); + + url = p1.Main.getResourceInClassLoader("p1/" + NAME); + assertNull(url); + + url = p1.Main.getResourceInClassLoader("p1/impl/" + NAME); + assertNull(url); + + url = p1.Main.getResourceInClassLoader("p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); + + url = p1.Main.getResourceInClassLoader("p2/" + NAME); + assertNull(url); + + url = p1.Main.getResourceInClassLoader("p2/impl/" + NAME); + assertNull(url); + + url = p1.Main.getResourceInClassLoader("p2/resources/" + NAME); + assertNull(url); + + + // invoke ClassLoader getResource from module m2 + url = p2.Main.getResourceInClassLoader(NAME); + assertNotNull(url); + + url = p2.Main.getResourceInClassLoader("p1/" + NAME); + assertNull(url); + + url = p2.Main.getResourceInClassLoader("p1/impl/" + NAME); + assertNull(url); + + url = p2.Main.getResourceInClassLoader("p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); + + url = p2.Main.getResourceInClassLoader("p2/" + NAME); + assertNull(url); + + url = p2.Main.getResourceInClassLoader("p2/impl/" + NAME); + assertNull(url); + + url = p2.Main.getResourceInClassLoader("p2/resources/" + NAME); + assertNull(url); + + + // invoke ClassLoader getResources from the unnamed module + Enumeration urls = thisLoader.getResources(NAME); + List resources = readAllAsStrings(urls); + assertTrue(resources.size() == 2); + assertTrue(resources.contains("m1")); + assertTrue(resources.contains("m2")); - // invoke ClassLoader getResource from modules m1-m3 - // Resources in a named module are private to that module. - // ClassLoader.getResource should not find resource in named modules. - assertNull(p1.Main.getResourceInClassLoader("/" + NAME)); - assertNull(p2.Main.getResourceInClassLoader("/" + NAME)); - assertNull(p3.Main.getResourceInClassLoader("/" + NAME)); + urls = thisLoader.getResources("p1/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = thisLoader.getResources("p1/impl/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = thisLoader.getResources("p1/resources/" + NAME); + resources = readAllAsStrings(urls); + assertTrue(resources.size() == 1); + assertTrue(resources.contains("m1/p1.resources")); + + urls = thisLoader.getResources("p2/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = thisLoader.getResources("p2/impl/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = thisLoader.getResources("p2/resources/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + + // invoke ClassLoader getResources from m1 + urls = p1.Main.getResourcesInClassLoader(NAME); + resources = readAllAsStrings(urls); + assertTrue(resources.size() == 2); + assertTrue(resources.contains("m1")); + assertTrue(resources.contains("m2")); + + urls = p1.Main.getResourcesInClassLoader("p1/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p1.Main.getResourcesInClassLoader("p1/impl/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p1.Main.getResourcesInClassLoader("p1/resources/" + NAME); + resources = readAllAsStrings(urls); + assertTrue(resources.size() == 1); + assertTrue(resources.contains("m1/p1.resources")); + + urls = p1.Main.getResourcesInClassLoader("p2/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p1.Main.getResourcesInClassLoader("p2/impl/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p1.Main.getResourcesInClassLoader("p2/resources/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + + // invoke ClassLoader getResources from m2 + urls = p2.Main.getResourcesInClassLoader(NAME); + resources = readAllAsStrings(urls); + assertTrue(resources.size() == 2); + assertTrue(resources.contains("m1")); + assertTrue(resources.contains("m2")); + + urls = p2.Main.getResourcesInClassLoader("p1/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p2.Main.getResourcesInClassLoader("p1/impl/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p2.Main.getResourcesInClassLoader("p1/resources/" + NAME); + resources = readAllAsStrings(urls); + assertTrue(resources.size() == 1); + assertTrue(resources.contains("m1/p1.resources")); + + urls = p2.Main.getResourcesInClassLoader("p2/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p2.Main.getResourcesInClassLoader("p2/impl/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + + urls = p2.Main.getResourcesInClassLoader("p2/resources/" + NAME); + assertTrue(readAllAsStrings(urls).isEmpty()); + // invoke ClassLoader getResourceAsStream from the unnamed module - assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME)); + InputStream in = thisLoader.getResourceAsStream(NAME); + assertNotNull(in); + + in = thisLoader.getResourceAsStream("p1/" + NAME); + assertNull(in); + + in = thisLoader.getResourceAsStream("p1/impl/" + NAME); + assertNull(in); + + in = thisLoader.getResourceAsStream("p1/resources/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.resources"); + + in = thisLoader.getResourceAsStream("p2/" + NAME); + assertNull(in); + + in = thisLoader.getResourceAsStream("p2/impl/" + NAME); + assertNull(in); + + in = thisLoader.getResourceAsStream("p2/resources/" + NAME); + assertNull(in); + + + // invoke ClassLoader getResource from modules m1 + in = p1.Main.getResourceAsStreamInClassLoader(NAME); + assertNotNull(in); + + in = p1.Main.getResourceAsStreamInClassLoader("p1/" + NAME); + assertNull(in); + + in = p1.Main.getResourceAsStreamInClassLoader("p1/impl/" + NAME); + assertNull(in); - // invoke ClassLoader getResourceAsStream from modules m1-m3 - // Resources in a named module are private to that module. - // ClassLoader.getResourceAsStream should not find resource in named modules. - assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME)); - assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME)); - assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME)); + in = p1.Main.getResourceAsStreamInClassLoader("p1/resources/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.resources"); + + in = p1.Main.getResourceAsStreamInClassLoader("p2/" + NAME); + assertNull(in); + + in = p1.Main.getResourceAsStreamInClassLoader("p2/impl/" + NAME); + assertNull(in); + + in = p1.Main.getResourceAsStreamInClassLoader("p2/resources/" + NAME); + assertNull(in); + + + // invoke ClassLoader getResource from modules m2 + in = p2.Main.getResourceAsStreamInClassLoader(NAME); + assertNotNull(in); + + in = p2.Main.getResourceAsStreamInClassLoader("p1/" + NAME); + assertNull(in); + + in = p2.Main.getResourceAsStreamInClassLoader("p1/impl/" + NAME); + assertNull(in); + + in = p2.Main.getResourceAsStreamInClassLoader("p1/resources/" + NAME); + assertEquals(readAllAsString(in), "m1/p1.resources"); + + in = p2.Main.getResourceAsStreamInClassLoader("p2/" + NAME); + assertNull(in); + + in = p2.Main.getResourceAsStreamInClassLoader("p2/impl/" + NAME); + assertNull(in); + + in = p2.Main.getResourceAsStreamInClassLoader("p2/resources/" + NAME); + assertNull(in); + // SecurityManager case System.setSecurityManager(new SecurityManager()); @@ -77,17 +288,24 @@ assertNull(Main.class.getClassLoader().getResource("/" + NAME)); assertNull(p1.Main.getResourceInClassLoader("/" + NAME)); assertNull(p2.Main.getResourceInClassLoader("/" + NAME)); - assertNull(p3.Main.getResourceInClassLoader("/" + NAME)); assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME)); assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME)); assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME)); - assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME)); System.out.println("Success!"); } /** + * Create a resource in the sub-directory of the given exploded module + */ + static void createResource(String mn, Path subdir, String msg) throws IOException { + Path dir = directoryFor(mn).resolve(subdir); + Path file = dir.resolve(NAME); + Files.write(file, msg.getBytes("UTF-8")); + } + + /** * Returns the directory for the given module (by name). */ static Path directoryFor(String mn) { @@ -101,12 +319,60 @@ return dir; } + static String readAllAsString(InputStream in) throws IOException { + if (in == null) + return null; + try (in) { + return new String(in.readAllBytes(), "UTF-8"); + } + } + + static String readAllAsString(URL url) throws IOException { + if (url == null) + return null; + InputStream in = url.openStream(); + return readAllAsString(url.openStream()); + } + + static List readAllAsStrings(Enumeration urls) throws IOException { + List result = new ArrayList<>(); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + result.add(readAllAsString(url)); + } + return result; + } + static void assertTrue(boolean condition) { if (!condition) throw new RuntimeException(); } + static void assertFalse(boolean condition) { + if (condition) throw new RuntimeException(); + } + static void assertNull(Object o) { assertTrue(o == null); } + + static void assertNotNull(Object o) { + assertTrue(o != null); + } + + static void assertEquals(Object actual, Object expected) { + if (expected == null) { + assertNull(actual); + } else { + assertTrue(expected.equals(actual)); + } + } + + static void assertNotEquals(Object actual, Object expected) { + if (expected == null) { + assertNotNull(actual); + } else { + assertTrue(!expected.equals(actual)); + } + } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -68,7 +68,7 @@ .compile(Paths.get(TEST_SRC, "Main.java"), CLASSES_DIR, "--module-path", MODS_DIR.toString(), - "--add-modules", "m1,m2,m3"); + "--add-modules", "m1,m2"); assertTrue(compiled); } @@ -78,7 +78,7 @@ public void runTest() throws Exception { int exitValue = executeTestJava("--module-path", MODS_DIR.toString(), - "--add-modules", "m1,m2,m3", + "--add-modules", "m1,m2", "-cp", CLASSES_DIR.toString(), "Main") .outputTo(System.out) diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,4 +23,5 @@ module m1 { exports p1; + opens p1.resources; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,9 @@ package p1; import java.io.InputStream; +import java.io.IOException; import java.net.URL; +import java.util.Enumeration; public class Main { private Main() { } @@ -33,6 +35,10 @@ return Main.class.getClassLoader().getResource(name); } + public static Enumeration getResourcesInClassLoader(String name) throws IOException { + return Main.class.getClassLoader().getResources(name); + } + public static InputStream getResourceAsStreamInClassLoader(String name) { return Main.class.getClassLoader().getResourceAsStream(name); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1.impl; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1.resources; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,4 +23,6 @@ module m2 { exports p2; + exports p2.impl to m1; + opens p2.resources to m1; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,9 @@ package p2; import java.io.InputStream; +import java.io.IOException; import java.net.URL; +import java.util.Enumeration; public class Main { private Main() { } @@ -33,6 +35,10 @@ return Main.class.getClassLoader().getResource(name); } + public static Enumeration getResourcesInClassLoader(String name) throws IOException { + return Main.class.getClassLoader().getResources(name); + } + public static InputStream getResourceAsStreamInClassLoader(String name) { return Main.class.getClassLoader().getResourceAsStream(name); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p2.impl; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p2.resources; + +public class Type { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m3 { - exports p3; -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p3; - -import java.io.InputStream; -import java.net.URL; - -public class Main { - private Main() { } - - public static URL getResourceInClassLoader(String name) { - return Main.class.getClassLoader().getResource(name); - } - - public static InputStream getResourceAsStreamInClassLoader(String name) { - return Main.class.getClassLoader().getResourceAsStream(name); - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ProcessBuilder/Basic.java --- a/jdk/test/java/lang/ProcessBuilder/Basic.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * 4947220 7018606 7034570 4244896 5049299 8003488 8054494 8058464 * 8067796 * @summary Basic tests for Process and Environment Variable code + * @modules java.base/java.lang:open * @run main/othervm/timeout=300 Basic * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic * @author Martin Buchholz diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/Runtime/Version/VersionProps.java --- a/jdk/test/java/lang/Runtime/Version/VersionProps.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/Runtime/Version/VersionProps.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8160564 * @summary check the implementation of VersionProps.versionNumbers() + * @modules java.base/java.lang:open * @run main VersionProps * @author Volker Simonis */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/StackWalker/CountLocalSlots.java --- a/jdk/test/java/lang/StackWalker/CountLocalSlots.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/StackWalker/CountLocalSlots.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8147039 * @summary Confirm locals[] always has expected length, even for "dead" locals + * @modules java.base/java.lang:open * @compile LocalsAndOperands.java * @run testng/othervm -Xcomp CountLocalSlots */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/StackWalker/LocalsAndOperands.java --- a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8020968 8147039 * @summary Tests for locals and operands + * @modules java.base/java.lang:open * @run testng LocalsAndOperands */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/StackWalker/LocalsCrash.java --- a/jdk/test/java/lang/StackWalker/LocalsCrash.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/StackWalker/LocalsCrash.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8147039 * @summary Test for -Xcomp crash that happened before 8147039 fix + * @modules java.base/java.lang:open * @run testng/othervm -Xcomp LocalsCrash */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/String/CompactString/VMOptionsTest.java --- a/jdk/test/java/lang/String/CompactString/VMOptionsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/String/CompactString/VMOptionsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -37,6 +37,7 @@ * if Compact String enable/disable VM Options is indeed working in String class, * it's verified by testing if the VM option affect coder and * COMPACT_STRINGS field in String class. + * @modules java.base/java.lang:open * @run testng/othervm -XX:+CompactStrings -DCompactStringEnabled=true VMOptionsTest * @run testng/othervm -XX:-CompactStrings -DCompactStringEnabled=false VMOptionsTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -39,7 +39,7 @@ * @bug 8144460 8144214 * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger * and logXX APIs of SimpleConsoleLogger. - * @modules java.base/jdk.internal.logger + * @modules java.base/jdk.internal.logger:+open * java.base/sun.util.logging * @build BootstrapLoggerUtils LogStream * @run main/othervm BootstrapLoggerAPIsTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -52,7 +52,7 @@ * @summary JDK implementation specific unit test for JDK internal artifacts. Tests the behavior of bootstrap loggers (and SimpleConsoleLoggers * too). - * @modules java.base/jdk.internal.logger + * @modules java.base/jdk.internal.logger:+open * java.logging * @build BootstrapLoggerUtils LogStream * @run main/othervm BootstrapLoggerTest NO_SECURITY diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java --- a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,6 +34,7 @@ * @test 8163162 * @summary Checks that LazyLoggers are returned for System.Logger instances * created by modules in the platform class loader. + * @modules java.base/java.lang:open * @build systempkg.log.SystemLoggerAccessor SystemLoggerInPlatformLoader * @run main/othervm SystemLoggerInPlatformLoader * @author danielfuchs diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java --- a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -38,7 +38,8 @@ * It calls both the {@link java.lang.System} factory methods and * {@link jdk.internal.logger.LazyLoggers} to obtains those loggers, * and configure them with all possible known levels. - * @modules java.base/sun.util.logging + * @modules java.base/java.lang:open + * java.base/sun.util.logging * java.base/jdk.internal.logger * java.logging/sun.util.logging.internal * @build LoggerFinderBackendTest SystemClassLoader diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java --- a/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,8 @@ * @summary Test inheritance, order and class redefinition behaviour of RUNTIME * class annotations * @author plevart - * @modules java.base/sun.reflect.annotation + * @modules java.base/java.lang:open + * java.base/sun.reflect.annotation */ import sun.reflect.annotation.AnnotationParser; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/instrument/RedefineModuleAgent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/RedefineModuleAgent.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Module; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Agent used by RedefineModuleTest + */ + +public class RedefineModuleAgent { + + private static Instrumentation inst; + + public static void premain(String args, Instrumentation inst) throws Exception { + RedefineModuleAgent.inst = inst; + } + + static void redefineModule(Module module, + Set extraReads, + Map> extraExports, + Map> extraOpens, + Set> extraUses, + Map, List>> extraProvides) { + inst.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/instrument/RedefineModuleTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/RedefineModuleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Basic test for redefineModule + * @modules java.instrument + * @build java.base/java.lang.TestProvider + * java.base/jdk.internal.test.TestProviderImpl1 + * java.base/jdk.internal.test.TestProviderImpl2 + * @run shell MakeJAR3.sh RedefineModuleAgent + * @run testng/othervm -javaagent:RedefineModuleAgent.jar RedefineModuleTest + */ + +import java.lang.TestProvider; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.net.URLStreamHandler; +import java.net.spi.URLStreamHandlerProvider; +import java.nio.file.FileSystems; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.Set; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class RedefineModuleTest { + + static void redefineModule(Module module, + Set extraReads, + Map> extraExports, + Map> extraOpens, + Set> extraUses, + Map, List>> extraProvides) { + RedefineModuleAgent.redefineModule(module, + extraReads, + extraExports, + extraOpens, + extraUses, + extraProvides); + } + + + /** + * Use redefineModule to update java.base to read java.instrument + */ + public void testAddReads() { + Module baseModule = Object.class.getModule(); + Module instrumentModule = Instrumentation.class.getModule(); + + // pre-conditions + assertFalse(baseModule.canRead(instrumentModule)); + + // update java.base to read java.instrument + Set extraReads = Set.of(instrumentModule); + redefineModule(baseModule, extraReads, Map.of(), Map.of(), Set.of(), Map.of()); + assertTrue(baseModule.canRead(instrumentModule)); + } + + /** + * Use redefineModule to update java.base to export jdk.internal.misc + */ + public void testAddExports() { + Module baseModule = Object.class.getModule(); + Module thisModule = this.getClass().getClassLoader().getUnnamedModule(); + String pkg = "jdk.internal.misc"; + + // pre-conditions + assertFalse(baseModule.isExported(pkg)); + assertFalse(baseModule.isExported(pkg, thisModule)); + + // update java.base to export jdk.internal.misc to an unnamed module + Map> extraExports = Map.of(pkg, Set.of(thisModule)); + redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); + assertFalse(baseModule.isExported(pkg)); + assertTrue(baseModule.isExported(pkg, thisModule)); + assertFalse(baseModule.isOpen(pkg)); + assertFalse(baseModule.isOpen(pkg, thisModule)); + } + + /** + * Use redefineModule to update java.base to open jdk.internal.loader + */ + public void testAddOpens() { + Module baseModule = Object.class.getModule(); + Module thisModule = this.getClass().getClassLoader().getUnnamedModule(); + String pkg = "jdk.internal.loader"; + + // pre-conditions + assertFalse(baseModule.isOpen(pkg)); + assertFalse(baseModule.isOpen(pkg, thisModule)); + + // update java.base to open dk.internal.loader to an unnamed module + Map> extraExports = Map.of(pkg, Set.of(thisModule)); + redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of()); + assertFalse(baseModule.isExported(pkg)); + assertTrue(baseModule.isExported(pkg, thisModule)); + assertFalse(baseModule.isOpen(pkg)); + assertTrue(baseModule.isOpen(pkg, thisModule)); + } + + /** + * Use redefineModule to update java.base to use TestProvider and + * provide implementations of TestProvider. + */ + public void testAddUsesAndProvides() throws Exception { + Module baseModule = Object.class.getModule(); + Class service = TestProvider.class; + + // pre-conditions + assertFalse(baseModule.canUse(service)); + assertTrue(collect(ServiceLoader.load(service)).isEmpty()); + assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty()); + + // update java.base to use TestProvider + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(service), Map.of()); + assertTrue(baseModule.canUse(service)); + assertTrue(collect(ServiceLoader.load(service)).isEmpty()); + assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty()); + + // update java.base to provide an implementation of TestProvider + Class type1 = Class.forName("jdk.internal.test.TestProviderImpl1"); + Map, List>> extraProvides = Map.of(service, List.of(type1)); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + + // invoke ServiceLoader from java.base to find providers + Set providers = collect(TestProvider.providers()); + assertTrue(providers.size() == 1); + assertTrue(containsInstanceOf(providers, type1)); + + // use ServiceLoader to load implementations visible via TCCL + providers = collect(ServiceLoader.load(service)); + assertTrue(collect(providers).size() == 1); + assertTrue(containsInstanceOf(collect(providers), type1)); + + // use ServiceLoader to load implementations in the boot layer + providers = collect(ServiceLoader.load(Layer.boot(), service)); + assertTrue(collect(providers).size() == 1); + assertTrue(containsInstanceOf(collect(providers), type1)); + + // update java.base to provide a second implementation of TestProvider + Class type2 = Class.forName("jdk.internal.test.TestProviderImpl2"); + extraProvides = Map.of(service, List.of(type2)); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + + // invoke ServiceLoader from java.base to find providers + providers = collect(TestProvider.providers()); + assertTrue(providers.size() == 2); + assertTrue(containsInstanceOf(providers, type1)); + assertTrue(containsInstanceOf(providers, type2)); + + // use ServiceLoader to load implementations visible via TCCL + providers = collect(ServiceLoader.load(service)); + assertTrue(collect(providers).size() == 2); + assertTrue(containsInstanceOf(providers, type1)); + assertTrue(containsInstanceOf(providers, type2)); + + // use ServiceLoader to load implementations in the boot layer + providers = collect(ServiceLoader.load(Layer.boot(), service)); + assertTrue(collect(providers).size() == 2); + assertTrue(containsInstanceOf(providers, type1)); + assertTrue(containsInstanceOf(providers, type2)); + } + + private Set collect(Iterable sl) { + Set providers = new HashSet<>(); + sl.forEach(providers::add); + return providers; + } + + private boolean containsInstanceOf(Collection c, Class type) { + for (Object o : c) { + if (type.isInstance(o)) return true; + } + return false; + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testExportPackageToEmptySet() { + // attempt to update java.base to export jdk.internal.misc to nobody + Module baseModule = Object.class.getModule(); + Map> extraExports = Map.of("jdk.internal.misc", Set.of()); + redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testOpenPackageToEmptySet() { + // attempt to update java.base to open jdk.internal.misc to nobody + Module baseModule = Object.class.getModule(); + Map> extraOpens = Map.of("jdk.internal.misc", Set.of()); + redefineModule(baseModule, Set.of(), Map.of(), extraOpens, Set.of(), Map.of()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testProvideServiceWithEmptyList() throws Exception { + // update java.base to provide an empty list of TestProvider + Module baseModule = Object.class.getModule(); + Class service = TestProvider.class; + Map, List>> extraProvides = Map.of(service, List.of()); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + } + + /** + * Test redefineClass by attempting to update java.base to export a package + * that it does not contain. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testExportPackageNotInModule() { + Module baseModule = Object.class.getModule(); + String pkg = "jdk.doesnotexist"; + + // attempt to update java.base to export jdk.doesnotexist + Map> extraExports = Map.of(pkg, Set.of()); + redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); + } + + /** + * Test redefineClass by attempting to update java.base to provide a service + * where the service provider class is not in the module. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testProvideServiceNotInModule() { + Module baseModule = Object.class.getModule(); + class MyProvider extends URLStreamHandlerProvider { + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + return null; + } + } + + // attempt to update java.base to provide MyProvider + Map, List>> extraProvides + = Map.of(URLStreamHandlerProvider.class, List.of(MyProvider.class)); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + } + + /** + * Test redefineClass by attempting to update java.base to provide a + * service where the service provider class is not a sub-type. + */ + @Test(expectedExceptions = IllegalArgumentException.class) + public void testProvideServiceNotSubtype() { + Module baseModule = Object.class.getModule(); + + Class service = TestProvider.class; + Class impl = FileSystems.getDefault().provider().getClass(); + + // attempt to update java.base to provide an implementation of TestProvider + Map, List>> extraProvides = Map.of(service, List.of(impl)); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + } + + /** + * Test redefineClass with null + */ + public void testNulls() { + Module baseModule = Object.class.getModule(); + + try { + redefineModule(null, Set.of(), Map.of(), Map.of(), Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + redefineModule(baseModule, null, Map.of(), Map.of(), Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + redefineModule(baseModule, Set.of(), null, Map.of(), Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + redefineModule(baseModule, Set.of(), Map.of(), null, Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), null, Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), null); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + Set containsNull = new HashSet<>(); + containsNull.add(null); + redefineModule(baseModule, containsNull, Map.of(), Map.of(), Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + Map> extraExports = new HashMap<>(); + extraExports.put(null, Set.of()); + redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + Map> extraExports = new HashMap<>(); + extraExports.put(null, Set.of()); + redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + Set containsNull = new HashSet<>(); + containsNull.add(null); + Map> extraExports = Map.of("java.lang", containsNull); + redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + Set> containsNull = new HashSet<>(); + containsNull.add(null); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), containsNull, Map.of()); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + Map, List>> extraProvides = new HashMap<>(); + extraProvides.put(null, List.of()); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + assertTrue(false); + } catch (NullPointerException e) { } + + try { + List> containsNull = new ArrayList<>(); + containsNull.add(null); + Map, List>> extraProvides = Map.of(TestProvider.class, containsNull); + redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides); + assertTrue(false); + } catch (NullPointerException e) { } + } + +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/instrument/TestAgentWithLimitMods.java --- a/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,7 +28,7 @@ * the module graph * @modules java.instrument * @run shell MakeJAR3.sh SimpleAgent - * @run main/othervm -javaagent:SimpleAgent.jar -limitmods java.base TestAgentWithLimitMods + * @run main/othervm -javaagent:SimpleAgent.jar --limit-modules java.base TestAgentWithLimitMods * */ public class TestAgentWithLimitMods { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.util.ServiceLoader; + +public interface TestProvider { + public static Iterable providers() { + return ServiceLoader.load(TestProvider.class); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.test; + +import java.lang.TestProvider; + +public class TestProviderImpl1 implements TestProvider { + public TestProviderImpl1() { } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.test; + +import java.lang.TestProvider; + +public class TestProviderImpl2 implements TestProvider { + public TestProviderImpl2() { } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java --- a/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,7 +28,9 @@ * @summary Test verifies that lambda forms are cached when run with multiple threads * @author kshefov * @library /lib/testlibrary/jsr292 /lib/testlibrary - * @modules jdk.management + * @modules java.base/java.lang.invoke:open + * java.base/java.lang.ref:open + * jdk.management * @build TestMethods * @build LambdaFormTestCase * @build LFCachingTestCase diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java --- a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,8 @@ * @summary Test verifies that lambda forms are cached when run with single thread * @author kshefov * @library /lib/testlibrary/jsr292 /lib/testlibrary + * @modules java.base/java.lang.ref:open + * java.base/java.lang.invoke:open * @build TestMethods * @build LambdaFormTestCase * @build LFCachingTestCase diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/LambdaFormTest.java --- a/jdk/test/java/lang/invoke/LambdaFormTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/invoke/LambdaFormTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,7 @@ /* @test * @summary unit tests for java.lang.invoke.LambdaForm + * @modules java.base/java.lang.invoke:open * @run junit/othervm test.java.lang.invoke.LambdaFormTest */ package test.java.lang.invoke; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @build test/* m1/* m2/* m3/* + * @run testng/othervm test/p.PrivateLookupInTests + * @summary Unit tests for MethodHandles.privateLookupIn + */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +open module m1 { +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p1; + +class Type { + private static final Object obj = new Object(); +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module m2 { + opens p2 to test; +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p2; + +class Type { + private static final Object obj = new Object(); +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module m3 { +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p3; + +class Type { + private static final Object obj = new Object(); +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module test { + requires testng; + exports p to testng; // TestNG invokes the public methods +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.reflect.Modifier; +import java.lang.reflect.Module; + +import static java.lang.invoke.MethodHandles.Lookup.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Unit tests for MethodHandles.privateLookupIn + */ + +@Test +public class PrivateLookupInTests { + + /** + * A public and non-public types in the test module but in a different + * package to the test class. + * + * package p.internal; + * public class PublicType { + * } + * + * package p.internal; + * class NonPublicType { + * private static final Object obj = ... + * } + */ + private Class publicType; + private Class nonPublicType; + + // initialize and sanity check publicType/nonPublicType + @BeforeTest + public void init() throws Exception { + publicType = Class.forName("p.internal.PublicType"); + assertTrue(this.getClass().getModule() == publicType.getModule()); + assertNotEquals(this.getClass().getPackageName(), publicType.getPackageName()); + assertTrue(Modifier.isPublic(publicType.getModifiers())); + + nonPublicType = Class.forName("p.internal.NonPublicType"); + assertTrue(this.getClass().getModule() == nonPublicType.getModule()); + assertNotEquals(this.getClass().getPackageName(), nonPublicType.getPackageName()); + assertFalse(Modifier.isPublic(nonPublicType.getModifiers())); + } + + // Invoke MethodHandles.privateLookupIn with a full-power caller + public void testAllAccessCallerSameModule() throws Throwable { + Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, MethodHandles.lookup()); + assertTrue(lookup.lookupClass() == nonPublicType); + assertTrue(lookup.hasPrivateAccess()); + + // get obj field + MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class); + Object obj = mh.invokeExact(); + } + + // Invoke MethodHandles.privateLookupIn with a reduced-power caller + public void testReducedAccessCallerSameModule() throws Throwable { + // drop access + Lookup caller = MethodHandles.lookup().in(publicType); + assertTrue((caller.lookupModes() & PRIVATE) == 0); + assertTrue((caller.lookupModes() & PACKAGE) == 0); + assertTrue((caller.lookupModes() & MODULE) != 0); + + Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller); + assertTrue(lookup.lookupClass() == nonPublicType); + assertTrue(lookup.hasPrivateAccess()); + + // use it + MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class); + Object obj = mh.invokeExact(); + } + + // Invoke MethodHandles.privateLookupIn with the public lookup as caller + @Test(expectedExceptions = {IllegalAccessException.class}) + public void testPublicLookupSameModule() throws Exception { + Lookup caller = MethodHandles.publicLookup(); + Lookup lookup = MethodHandles.privateLookupIn(publicType, caller); + } + + // test reads m1, open module m1 containing p1 + public void testTargetClassInOpenModule() throws Throwable { + // m1/p1.Type + Class clazz = Class.forName("p1.Type"); + assertEquals(clazz.getModule().getName(), "m1"); + + // ensure that this module reads m1 + Module thisModule = getClass().getModule(); + Module m1 = clazz.getModule(); + thisModule.addReads(clazz.getModule()); + assertTrue(m1.isOpen("p1", thisModule)); + + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(lookup.lookupClass() == clazz); + assertTrue(lookup.hasPrivateAccess()); + + // get obj field + MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class); + Object obj = mh.invokeExact(); + } + + // test does not read m2, m2 opens p2 to test + @Test(expectedExceptions = {IllegalAccessException.class}) + public void testCallerDoesNotRead() throws Throwable { + // m2/p2.Type + Class clazz = Class.forName("p2.Type"); + assertEquals(clazz.getModule().getName(), "m2"); + + Module thisModule = getClass().getModule(); + Module m2 = clazz.getModule(); + assertFalse(thisModule.canRead(m2)); + assertTrue(m2.isOpen("p2", thisModule)); + + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + } + + // test reads m3, m3 does not open p3 to test + @Test(expectedExceptions = {IllegalAccessException.class}) + public void testNotOpenToCaller() throws Throwable { + // m3/p2.Type + Class clazz = Class.forName("p3.Type"); + assertEquals(clazz.getModule().getName(), "m3"); + + Module thisModule = getClass().getModule(); + Module m3 = clazz.getModule(); + thisModule.addReads(clazz.getModule()); + assertFalse(m3.isOpen("p3", thisModule)); + + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + } + + // Invoke MethodHandles.privateLookupIn with a primitive class + @Test(expectedExceptions = {IllegalArgumentException.class}) + public void testPrimitiveClassAsTargetClass() throws Exception { + MethodHandles.privateLookupIn(int.class, MethodHandles.lookup()); + } + + // Invoke MethodHandles.privateLookupIn with an array class + @Test(expectedExceptions = {IllegalArgumentException.class}) + public void testArrayClassAsTargetClass() throws Exception { + MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup()); + } + + // Invoke MethodHandles.privateLookupIn with a primitive array class + @Test(expectedExceptions = {IllegalArgumentException.class}) + public void testPrimitiveArrayClassAsTargetClass() throws Exception { + MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup()); + } + + // Invoke MethodHandles.privateLookupIn with null + @Test(expectedExceptions = {NullPointerException.class}) + public void testNullTargetClass() throws Exception { + MethodHandles.privateLookupIn(null, MethodHandles.lookup()); + } + + // Invoke MethodHandles.privateLookupIn with null + @Test(expectedExceptions = {NullPointerException.class}) + public void testNullCaller() throws Exception { + MethodHandles.privateLookupIn(getClass(), null); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.internal; + +class NonPublicType { + private static final Object obj = new Object(); +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.internal; + +public class PublicType { +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/PrivateInvokeTest.java --- a/jdk/test/java/lang/invoke/PrivateInvokeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/invoke/PrivateInvokeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,7 @@ /* @test * @summary white-box testing of method handle sub-primitives + * @modules java.base/java.lang.invoke:open * @run junit test.java.lang.invoke.PrivateInvokeTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/invoke/VMAnonymousClass.java --- a/jdk/test/java/lang/invoke/VMAnonymousClass.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/invoke/VMAnonymousClass.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,7 +32,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.reflect.Field; import org.junit.Test; import jdk.internal.misc.Unsafe; import jdk.internal.org.objectweb.asm.*; @@ -64,7 +63,7 @@ throw new RuntimeException("Expected SecurityException"); } - private static Unsafe unsafe = getUnsafe(); + private static Unsafe unsafe = Unsafe.getUnsafe(); private static void test(String pkg) throws Throwable { byte[] bytes = dumpClass(pkg); @@ -130,14 +129,4 @@ cw.visitEnd(); return cw.toByteArray(); } - - private static synchronized Unsafe getUnsafe() { - try { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - return (Unsafe) f.get(null); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/module/AutomaticModulesTest.java --- a/jdk/test/java/lang/module/AutomaticModulesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -67,6 +67,15 @@ // JAR file name module-name[/version] { "foo.jar", "foo" }, + { "foo4j.jar", "foo4j", }, + + { "foo1.jar", "foo" }, + { "foo1.2.jar", "foo" }, + { "foo1.2.3.jar", "foo" }, + + { "foo10.jar", "foo" }, + { "foo10.20.jar", "foo" }, + { "foo10.20.30.jar", "foo" }, { "foo-1.jar", "foo/1" }, { "foo-1.2.jar", "foo/1.2" }, @@ -258,8 +267,8 @@ ModuleDescriptor descriptor = mref.get().descriptor(); assertTrue(descriptor.provides().size() == 1); - assertTrue(descriptor.provides().containsKey(service)); - ModuleDescriptor.Provides provides = descriptor.provides().get(service); + ModuleDescriptor.Provides provides = descriptor.provides().iterator().next(); + assertEquals(provides.service(), service); assertTrue(provides.providers().size() == 1); assertTrue(provides.providers().contains((provider))); } @@ -343,17 +352,17 @@ attrs.put(Attributes.Name.MAIN_CLASS, mainClass); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m1.jar"), man); + createDummyJarFile(dir.resolve("m.jar"), man); ModuleFinder finder = ModuleFinder.of(dir); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1"); + Configuration cf = resolve(parent, finder, "m"); - ModuleDescriptor m1 = findDescriptor(cf, "m1"); + ModuleDescriptor descriptor = findDescriptor(cf, "m"); - assertTrue(m1.mainClass().isPresent()); - assertEquals(m1.mainClass().get(), mainClass); + assertTrue(descriptor.mainClass().isPresent()); + assertEquals(descriptor.mainClass().get(), mainClass); } @@ -380,7 +389,7 @@ attrs.put(Attributes.Name.MAIN_CLASS, mainClass); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m1.jar"), man); + createDummyJarFile(dir.resolve("m.jar"), man); // should throw FindException ModuleFinder.of(dir).findAll(); @@ -389,213 +398,213 @@ /** * Basic test of a configuration created with automatic modules. - * m1 requires m2* - * m1 requires m3* - * m2* - * m3* + * a requires b* + * a requires c* + * b* + * c* */ public void testConfiguration1() throws Exception { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .requires("m2") - .requires("m3") + = ModuleDescriptor.module("a") + .requires("b") + .requires("c") .requires("java.base") .build(); - // m2 and m3 are automatic modules + // b and c are automatic modules Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m2.jar"), "p/T.class"); - createDummyJarFile(dir.resolve("m3.jar"), "q/T.class"); + createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); + createDummyJarFile(dir.resolve("c.jar"), "q/T.class"); - // module finder locates m1 and the modules in the directory + // module finder locates a and the modules in the directory ModuleFinder finder = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1), ModuleFinder.of(dir)); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1"); + Configuration cf = resolve(parent, finder, "a"); assertTrue(cf.modules().size() == 3); - assertTrue(cf.findModule("m1").isPresent()); - assertTrue(cf.findModule("m2").isPresent()); - assertTrue(cf.findModule("m3").isPresent()); + assertTrue(cf.findModule("a").isPresent()); + assertTrue(cf.findModule("b").isPresent()); + assertTrue(cf.findModule("c").isPresent()); ResolvedModule base = cf.findModule("java.base").get(); assertTrue(base.configuration() == Layer.boot().configuration()); - ResolvedModule m1 = cf.findModule("m1").get(); - ResolvedModule m2 = cf.findModule("m2").get(); - ResolvedModule m3 = cf.findModule("m3").get(); + ResolvedModule a = cf.findModule("a").get(); + ResolvedModule b = cf.findModule("b").get(); + ResolvedModule c = cf.findModule("c").get(); - // m2 && m3 only require java.base - assertTrue(m2.reference().descriptor().requires().size() == 1); - assertTrue(m3.reference().descriptor().requires().size() == 1); + // b && c only require java.base + assertTrue(b.reference().descriptor().requires().size() == 1); + assertTrue(c.reference().descriptor().requires().size() == 1); // readability - assertTrue(m1.reads().size() == 3); - assertTrue(m1.reads().contains(base)); - assertTrue(m1.reads().contains(m2)); - assertTrue(m1.reads().contains(m3)); + assertTrue(a.reads().size() == 3); + assertTrue(a.reads().contains(base)); + assertTrue(a.reads().contains(b)); + assertTrue(a.reads().contains(c)); - assertTrue(m2.reads().contains(m1)); - assertTrue(m2.reads().contains(m3)); - testReadAllBootModules(cf, "m2"); // m2 reads all modules in boot layer + assertTrue(b.reads().contains(a)); + assertTrue(b.reads().contains(c)); + testReadAllBootModules(cf, "b"); // b reads all modules in boot layer - assertTrue(m3.reads().contains(m1)); - assertTrue(m3.reads().contains(m2)); - testReadAllBootModules(cf, "m3"); // m3 reads all modules in boot layer + assertTrue(c.reads().contains(a)); + assertTrue(c.reads().contains(b)); + testReadAllBootModules(cf, "c"); // c reads all modules in boot layer } /** * Basic test of a configuration created with automatic modules - * m1 requires m2 - * m2 requires m3* - * m3* - * m4* + * a requires b + * b requires c* + * c* + * d* */ public void testInConfiguration2() throws IOException { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .requires("m2") + = ModuleDescriptor.module("a") + .requires("b") .requires("java.base") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires("m3") + = ModuleDescriptor.module("b") + .requires("c") .requires("java.base") .build(); - // m3 and m4 are automatic modules + // c and d are automatic modules Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m3.jar"), "p/T.class"); - createDummyJarFile(dir.resolve("m4.jar"), "q/T.class"); + createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); + createDummyJarFile(dir.resolve("d.jar"), "q/T.class"); - // module finder locates m1 and the modules in the directory + // module finder locates a and the modules in the directory ModuleFinder finder = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), ModuleFinder.of(dir)); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1", "m4"); + Configuration cf = resolve(parent, finder, "a", "d"); assertTrue(cf.modules().size() == 4); - assertTrue(cf.findModule("m1").isPresent()); - assertTrue(cf.findModule("m2").isPresent()); - assertTrue(cf.findModule("m3").isPresent()); - assertTrue(cf.findModule("m4").isPresent()); + assertTrue(cf.findModule("a").isPresent()); + assertTrue(cf.findModule("b").isPresent()); + assertTrue(cf.findModule("c").isPresent()); + assertTrue(cf.findModule("d").isPresent()); - // m3 && m4 should only require java.base - assertTrue(findDescriptor(cf, "m3").requires().size() == 1); - assertTrue(findDescriptor(cf, "m4").requires().size() == 1); + // c && d should only require java.base + assertTrue(findDescriptor(cf, "c").requires().size() == 1); + assertTrue(findDescriptor(cf, "d").requires().size() == 1); // readability ResolvedModule base = cf.findModule("java.base").get(); assertTrue(base.configuration() == Layer.boot().configuration()); - ResolvedModule m1 = cf.findModule("m1").get(); - ResolvedModule m2 = cf.findModule("m2").get(); - ResolvedModule m3 = cf.findModule("m3").get(); - ResolvedModule m4 = cf.findModule("m4").get(); + ResolvedModule a = cf.findModule("a").get(); + ResolvedModule b = cf.findModule("b").get(); + ResolvedModule c = cf.findModule("c").get(); + ResolvedModule d = cf.findModule("d").get(); - assertTrue(m1.reads().size() == 2); - assertTrue(m1.reads().contains(m2)); - assertTrue(m1.reads().contains(base)); + assertTrue(a.reads().size() == 2); + assertTrue(a.reads().contains(b)); + assertTrue(a.reads().contains(base)); - assertTrue(m2.reads().size() == 3); - assertTrue(m2.reads().contains(m3)); - assertTrue(m2.reads().contains(m4)); - assertTrue(m2.reads().contains(base)); + assertTrue(b.reads().size() == 3); + assertTrue(b.reads().contains(c)); + assertTrue(b.reads().contains(d)); + assertTrue(b.reads().contains(base)); - assertTrue(m3.reads().contains(m1)); - assertTrue(m3.reads().contains(m2)); - assertTrue(m3.reads().contains(m4)); - testReadAllBootModules(cf, "m3"); // m3 reads all modules in boot layer + assertTrue(c.reads().contains(a)); + assertTrue(c.reads().contains(b)); + assertTrue(c.reads().contains(d)); + testReadAllBootModules(cf, "c"); // c reads all modules in boot layer - assertTrue(m4.reads().contains(m1)); - assertTrue(m4.reads().contains(m2)); - assertTrue(m4.reads().contains(m3)); - testReadAllBootModules(cf, "m4"); // m4 reads all modules in boot layer + assertTrue(d.reads().contains(a)); + assertTrue(d.reads().contains(b)); + assertTrue(d.reads().contains(c)); + testReadAllBootModules(cf, "d"); // d reads all modules in boot layer } /** * Basic test of a configuration created with automatic modules - * m1 requires m2 - * m2 requires public m3* - * m3* - * m4* + * a requires b + * b requires transitive c* + * c* + * d* */ public void testInConfiguration3() throws IOException { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .requires("m2") + = ModuleDescriptor.module("a") + .requires("b") .requires("java.base") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m3") + = ModuleDescriptor.module("b") + .requires(Set.of(Modifier.TRANSITIVE), "c") .requires("java.base") .build(); - // m3 and m4 are automatic modules + // c and d are automatic modules Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m3.jar"), "p/T.class"); - createDummyJarFile(dir.resolve("m4.jar"), "q/T.class"); + createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); + createDummyJarFile(dir.resolve("d.jar"), "q/T.class"); - // module finder locates m1 and the modules in the directory + // module finder locates a and the modules in the directory ModuleFinder finder = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), ModuleFinder.of(dir)); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1", "m4"); + Configuration cf = resolve(parent, finder, "a", "d"); assertTrue(cf.modules().size() == 4); - assertTrue(cf.findModule("m1").isPresent()); - assertTrue(cf.findModule("m2").isPresent()); - assertTrue(cf.findModule("m3").isPresent()); - assertTrue(cf.findModule("m4").isPresent()); + assertTrue(cf.findModule("a").isPresent()); + assertTrue(cf.findModule("b").isPresent()); + assertTrue(cf.findModule("c").isPresent()); + assertTrue(cf.findModule("d").isPresent()); ResolvedModule base = cf.findModule("java.base").get(); assertTrue(base.configuration() == Layer.boot().configuration()); - ResolvedModule m1 = cf.findModule("m1").get(); - ResolvedModule m2 = cf.findModule("m2").get(); - ResolvedModule m3 = cf.findModule("m3").get(); - ResolvedModule m4 = cf.findModule("m4").get(); + ResolvedModule a = cf.findModule("a").get(); + ResolvedModule b = cf.findModule("b").get(); + ResolvedModule c = cf.findModule("c").get(); + ResolvedModule d = cf.findModule("d").get(); - // m3 && m4 should only require java.base - assertTrue(findDescriptor(cf, "m3").requires().size() == 1); - assertTrue(findDescriptor(cf, "m4").requires().size() == 1); + // c && d should only require java.base + assertTrue(findDescriptor(cf, "c").requires().size() == 1); + assertTrue(findDescriptor(cf, "d").requires().size() == 1); // readability - assertTrue(m1.reads().size() == 4); - assertTrue(m1.reads().contains(m2)); - assertTrue(m1.reads().contains(m3)); - assertTrue(m1.reads().contains(m4)); - assertTrue(m1.reads().contains(base)); + assertTrue(a.reads().size() == 4); + assertTrue(a.reads().contains(b)); + assertTrue(a.reads().contains(c)); + assertTrue(a.reads().contains(d)); + assertTrue(a.reads().contains(base)); - assertTrue(m2.reads().size() == 3); - assertTrue(m2.reads().contains(m3)); - assertTrue(m2.reads().contains(m4)); - assertTrue(m2.reads().contains(base)); + assertTrue(b.reads().size() == 3); + assertTrue(b.reads().contains(c)); + assertTrue(b.reads().contains(d)); + assertTrue(b.reads().contains(base)); - assertTrue(reads(cf, "m2", "m3")); - assertTrue(reads(cf, "m2", "m4")); - assertTrue(reads(cf, "m2", "java.base")); + assertTrue(reads(cf, "b", "c")); + assertTrue(reads(cf, "b", "d")); + assertTrue(reads(cf, "b", "java.base")); - assertTrue(m3.reads().contains(m1)); - assertTrue(m3.reads().contains(m2)); - assertTrue(m3.reads().contains(m4)); - testReadAllBootModules(cf, "m3"); // m3 reads all modules in boot layer + assertTrue(c.reads().contains(a)); + assertTrue(c.reads().contains(b)); + assertTrue(c.reads().contains(d)); + testReadAllBootModules(cf, "c"); // c reads all modules in boot layer - assertTrue(m4.reads().contains(m1)); - assertTrue(m4.reads().contains(m2)); - assertTrue(m4.reads().contains(m3)); - testReadAllBootModules(cf, "m4"); // m4 reads all modules in boot layer + assertTrue(d.reads().contains(a)); + assertTrue(d.reads().contains(b)); + assertTrue(d.reads().contains(c)); + testReadAllBootModules(cf, "d"); // d reads all modules in boot layer } @@ -604,23 +613,23 @@ */ public void testInLayer() throws IOException { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m1") - .requires("m2") - .requires("m3") + = ModuleDescriptor.module("a") + .requires("b") + .requires("c") .build(); - // m2 and m3 are simple JAR files + // b and c are simple JAR files Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m2.jar"), "p/T.class"); - createDummyJarFile(dir.resolve("m3.jar"), "q/T2.class"); + createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); + createDummyJarFile(dir.resolve("c.jar"), "q/T2.class"); - // module finder locates m1 and the modules in the directory + // module finder locates a and the modules in the directory ModuleFinder finder = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), ModuleFinder.of(dir)); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1"); + Configuration cf = resolve(parent, finder, "a"); assertTrue(cf.modules().size() == 3); // each module gets its own loader @@ -629,15 +638,15 @@ // an unnamed module Module unnamed = (new ClassLoader() { }).getUnnamedModule(); - Module m2 = layer.findModule("m2").get(); - assertTrue(m2.isNamed()); - assertTrue(m2.canRead(unnamed)); - testsReadsAll(m2, layer); + Module b = layer.findModule("b").get(); + assertTrue(b.isNamed()); + assertTrue(b.canRead(unnamed)); + testsReadsAll(b, layer); - Module m3 = layer.findModule("m3").get(); - assertTrue(m3.isNamed()); - assertTrue(m2.canRead(unnamed)); - testsReadsAll(m3, layer); + Module c = layer.findModule("c").get(); + assertTrue(c.isNamed()); + assertTrue(b.canRead(unnamed)); + testsReadsAll(c, layer); } @@ -646,19 +655,19 @@ */ public void testMisc() throws IOException { Path dir = Files.createTempDirectory(USER_DIR, "mods"); - Path m1_jar = createDummyJarFile(dir.resolve("m1.jar"), "p/T.class"); + Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class"); - ModuleFinder finder = ModuleFinder.of(m1_jar); + ModuleFinder finder = ModuleFinder.of(m_jar); - assertTrue(finder.find("m1").isPresent()); - ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + assertTrue(finder.find("m").isPresent()); + ModuleDescriptor m = finder.find("m").get().descriptor(); // test miscellaneous methods - assertTrue(m1.isAutomatic()); - assertFalse(m1.isSynthetic()); - assertFalse(m1.osName().isPresent()); - assertFalse(m1.osArch().isPresent()); - assertFalse(m1.osVersion().isPresent()); + assertTrue(m.isAutomatic()); + assertFalse(m.isSynthetic()); + assertFalse(m.osName().isPresent()); + assertFalse(m.osArch().isPresent()); + assertFalse(m.osVersion().isPresent()); } @@ -703,17 +712,15 @@ * and its parent Layers. */ static void testsReadsAll(Module m, Layer layer) { - while (layer != Layer.empty()) { + // check that m reads all modules in the layer + layer.configuration().modules().stream() + .map(ResolvedModule::name) + .map(layer::findModule) + .map(Optional::get) + .forEach(other -> assertTrue(m.canRead(other))); - // check that m reads all module in the layer - layer.configuration().modules().stream() - .map(ResolvedModule::name) - .map(layer::findModule) - .map(Optional::get) - .forEach(m2 -> assertTrue(m.canRead(m2))); - - layer = layer.parent().get(); - } + // also check parent layers + layer.parents().forEach(l -> testsReadsAll(m, l)); } /** @@ -721,11 +728,11 @@ * that reads module mn2. */ static boolean reads(Configuration cf, String mn1, String mn2) { - Optional om1 = cf.findModule(mn1); - if (!om1.isPresent()) + Optional om = cf.findModule(mn1); + if (!om.isPresent()) return false; - return om1.get().reads().stream() + return om.get().reads().stream() .map(ResolvedModule::name) .anyMatch(mn2::equals); } @@ -757,7 +764,7 @@ * in the resulting JAR file. */ static Path createDummyJarFile(Path jarfile, String... entries) - throws IOException + throws IOException { return createDummyJarFile(jarfile, null, entries); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/module/ConfigurationTest.java --- a/jdk/test/java/lang/module/ConfigurationTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/module/ConfigurationTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -31,11 +31,13 @@ import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleFinder; import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; +import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -53,17 +55,17 @@ */ public void testBasic() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m3") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .build(); ModuleFinder finder @@ -77,7 +79,8 @@ assertTrue(cf.findModule("m2").isPresent()); assertTrue(cf.findModule("m3").isPresent()); - assertTrue(cf.parent().get() == Configuration.empty()); + assertTrue(cf.parents().size() == 1); + assertTrue(cf.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf.findModule("m1").get(); ResolvedModule m2 = cf.findModule("m2").get(); @@ -102,23 +105,23 @@ /** - * Basic test of "requires public": - * m1 requires m2, m2 requires public m3 + * Basic test of "requires transitive": + * m1 requires m2, m2 requires transitive m3 */ - public void testRequiresPublic1() { - // m1 requires m2, m2 requires public m3 + public void testRequiresTransitive1() { + // m1 requires m2, m2 requires transitive m3 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m3") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .build(); ModuleFinder finder @@ -132,7 +135,8 @@ assertTrue(cf.findModule("m2").isPresent()); assertTrue(cf.findModule("m3").isPresent()); - assertTrue(cf.parent().get() == Configuration.empty()); + assertTrue(cf.parents().size() == 1); + assertTrue(cf.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf.findModule("m1").get(); ResolvedModule m2 = cf.findModule("m2").get(); @@ -153,23 +157,23 @@ /** - * Basic test of "requires public" with configurations. + * Basic test of "requires transitive" with configurations. * * The test consists of three configurations: - * - Configuration cf1: m1, m2 requires public m1 + * - Configuration cf1: m1, m2 requires transitive m1 * - Configuration cf2: m3 requires m2 */ - public void testRequiresPublic2() { - - // cf1: m1 and m2, m2 requires public m1 + public void testRequiresTransitive2() { + + // cf1: m1 and m2, m2 requires transitive m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -179,7 +183,8 @@ assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); - assertTrue(cf1.parent().get() == Configuration.empty()); + assertTrue(cf1.parents().size() == 1); + assertTrue(cf1.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf1.findModule("m1").get(); ResolvedModule m2 = cf1.findModule("m2").get(); @@ -192,7 +197,7 @@ // cf2: m3, m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -204,7 +209,8 @@ assertTrue(cf2.findModule("m1").isPresent()); // in parent assertTrue(cf2.findModule("m2").isPresent()); // in parent assertTrue(cf2.findModule("m3").isPresent()); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); ResolvedModule m3 = cf2.findModule("m3").get(); assertTrue(m3.configuration() == cf2); @@ -215,18 +221,18 @@ /** - * Basic test of "requires public" with configurations. + * Basic test of "requires transitive" with configurations. * * The test consists of three configurations: * - Configuration cf1: m1 - * - Configuration cf2: m2 requires public m1, m3 requires m2 + * - Configuration cf2: m2 requires transitive m1, m3 requires m2 */ - public void testRequiresPublic3() { + public void testRequiresTransitive3() { // cf1: m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -235,21 +241,22 @@ assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - assertTrue(cf1.parent().get() == Configuration.empty()); + assertTrue(cf1.parents().size() == 1); + assertTrue(cf1.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf1.findModule("m1").get(); assertTrue(m1.reads().size() == 0); - // cf2: m2, m3: m2 requires public m1, m3 requires m2 + // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -261,7 +268,8 @@ assertTrue(cf2.findModule("m1").isPresent()); // in parent assertTrue(cf2.findModule("m2").isPresent()); assertTrue(cf2.findModule("m3").isPresent()); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); ResolvedModule m2 = cf2.findModule("m2").get(); ResolvedModule m3 = cf2.findModule("m3").get(); @@ -278,19 +286,19 @@ /** - * Basic test of "requires public" with configurations. + * Basic test of "requires transitive" with configurations. * * The test consists of three configurations: * - Configuration cf1: m1 - * - Configuration cf2: m2 requires public m1 + * - Configuration cf2: m2 requires transitive m1 * - Configuraiton cf3: m3 requires m2 */ - public void testRequiresPublic4() { + public void testRequiresTransitive4() { // cf1: m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -299,17 +307,18 @@ assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - assertTrue(cf1.parent().get() == Configuration.empty()); + assertTrue(cf1.parents().size() == 1); + assertTrue(cf1.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf1.findModule("m1").get(); assertTrue(m1.reads().size() == 0); - // cf2: m2 requires public m1 + // cf2: m2 requires transitive m1 ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); @@ -319,7 +328,8 @@ assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); // in parent assertTrue(cf2.findModule("m2").isPresent()); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); ResolvedModule m2 = cf2.findModule("m2").get(); @@ -331,7 +341,7 @@ // cf3: m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -343,7 +353,8 @@ assertTrue(cf3.findModule("m1").isPresent()); // in parent assertTrue(cf3.findModule("m2").isPresent()); // in parent assertTrue(cf3.findModule("m3").isPresent()); - assertTrue(cf3.parent().get() == cf2); + assertTrue(cf3.parents().size() == 1); + assertTrue(cf3.parents().get(0) == cf2); ResolvedModule m3 = cf3.findModule("m3").get(); @@ -355,23 +366,23 @@ /** - * Basic test of "requires public" with configurations. + * Basic test of "requires transitive" with configurations. * * The test consists of two configurations: - * - Configuration cf1: m1, m2 requires public m1 - * - Configuration cf2: m3 requires public m2, m4 requires m3 + * - Configuration cf1: m1, m2 requires transitive m1 + * - Configuration cf2: m3 requires transitive m2, m4 requires m3 */ - public void testRequiresPublic5() { - - // cf1: m1, m2 requires public m1 + public void testRequiresTransitive5() { + + // cf1: m1, m2 requires transitive m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -381,7 +392,8 @@ assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); - assertTrue(cf1.parent().get() == Configuration.empty()); + assertTrue(cf1.parents().size() == 1); + assertTrue(cf1.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf1.findModule("m1").get(); ResolvedModule m2 = cf1.findModule("m2").get(); @@ -394,15 +406,15 @@ assertTrue(m2.reads().contains(m1)); - // cf2: m3 requires public m2, m4 requires m3 + // cf2: m3 requires transitive m2, m4 requires m3 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") - .requires(Modifier.PUBLIC, "m2") + = ModuleDescriptor.module("m3") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") .build(); ModuleDescriptor descriptor4 - = new ModuleDescriptor.Builder("m4") + = ModuleDescriptor.module("m4") .requires("m3") .build(); @@ -416,7 +428,8 @@ assertTrue(cf2.findModule("m2").isPresent()); // in parent assertTrue(cf2.findModule("m3").isPresent()); assertTrue(cf2.findModule("m4").isPresent()); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); ResolvedModule m3 = cf2.findModule("m3").get(); ResolvedModule m4 = cf2.findModule("m4").get(); @@ -435,6 +448,362 @@ /** + * Basic test of "requires transitive" with configurations. + * + * The test consists of three configurations: + * - Configuration cf1: m1, m2 requires transitive m1 + * - Configuration cf2: m1, m3 requires transitive m1 + * - Configuration cf3(cf1,cf2): m4 requires m2, m3 + */ + public void testRequiresTransitive6() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + + ModuleDescriptor descriptor4 + = ModuleDescriptor.module("m4") + .requires("m2") + .requires("m3") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + Configuration cf1 = resolveRequires(finder1, "m2"); + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("m2").isPresent()); + assertTrue(cf1.parents().size() == 1); + assertTrue(cf1.parents().get(0) == Configuration.empty()); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); + Configuration cf2 = resolveRequires(finder2, "m3"); + assertTrue(cf2.modules().size() == 2); + assertTrue(cf2.findModule("m3").isPresent()); + assertTrue(cf2.findModule("m1").isPresent()); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == Configuration.empty()); + + ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4); + Configuration cf3 = Configuration.resolveRequires(finder3, + List.of(cf1, cf2), + ModuleFinder.of(), + Set.of("m4")); + assertTrue(cf3.modules().size() == 1); + assertTrue(cf3.findModule("m4").isPresent()); + + ResolvedModule m1_l = cf1.findModule("m1").get(); + ResolvedModule m1_r = cf2.findModule("m1").get(); + ResolvedModule m2 = cf1.findModule("m2").get(); + ResolvedModule m3 = cf2.findModule("m3").get(); + ResolvedModule m4 = cf3.findModule("m4").get(); + assertTrue(m4.configuration() == cf3); + + assertTrue(m4.reads().size() == 4); + assertTrue(m4.reads().contains(m1_l)); + assertTrue(m4.reads().contains(m1_r)); + assertTrue(m4.reads().contains(m2)); + assertTrue(m4.reads().contains(m3)); + } + + + /** + * Basic test of "requires static": + * m1 requires static m2 + * m2 is not observable + * resolve m1 + */ + public void testRequiresStatic1() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .requires(Set.of(Requires.Modifier.STATIC), "m2") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 1); + + ResolvedModule m1 = cf.findModule("m1").get(); + assertTrue(m1.reads().size() == 0); + } + + + /** + * Basic test of "requires static": + * m1 requires static m2 + * m2 + * resolve m1 + */ + public void testRequiresStatic2() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .requires(Set.of(Requires.Modifier.STATIC), "m2") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 1); + + ResolvedModule m1 = cf.findModule("m1").get(); + assertTrue(m1.reads().size() == 0); + } + + + /** + * Basic test of "requires static": + * m1 requires static m2 + * m2 + * resolve m1, m2 + */ + public void testRequiresStatic3() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .requires(Set.of(Requires.Modifier.STATIC), "m2") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolveRequires(finder, "m1", "m2"); + + assertTrue(cf.modules().size() == 2); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + + assertTrue(m1.reads().size() == 1); + assertTrue(m1.reads().contains(m2)); + + assertTrue(m2.reads().size() == 0); + } + + + /** + * Basic test of "requires static": + * m1 requires m2, m3 + * m2 requires static m2 + * m3 + */ + public void testRequiresStatic4() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .requires("m2") + .requires("m3") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.STATIC), "m3") + .build(); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 3); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + + assertTrue(m1.reads().size() == 2); + assertTrue(m1.reads().contains(m2)); + assertTrue(m1.reads().contains(m3)); + + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m3)); + + assertTrue(m3.reads().size() == 0); + } + + + /** + * Basic test of "requires static": + * The test consists of three configurations: + * - Configuration cf1: m1, m2 + * - Configuration cf2: m3 requires m1, requires static m2 + */ + public void testRequiresStatic5() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m1", "m2"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("m2").isPresent()); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires("m1") + .requires(Set.of(Requires.Modifier.STATIC), "m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m3").isPresent()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + ResolvedModule m2 = cf1.findModule("m2").get(); + ResolvedModule m3 = cf2.findModule("m3").get(); + + assertTrue(m3.reads().size() == 2); + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + } + + + /** + * Basic test of "requires static": + * The test consists of three configurations: + * - Configuration cf1: m1 + * - Configuration cf2: m3 requires m1, requires static m2 + */ + public void testRequiresStatic6() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires("m1") + .requires(Set.of(Requires.Modifier.STATIC), "m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m3").isPresent()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + ResolvedModule m3 = cf2.findModule("m3").get(); + + assertTrue(m3.reads().size() == 1); + assertTrue(m3.reads().contains(m1)); + } + + + /** + * Basic test of "requires static": + * (m1 not observable) + * m2 requires transitive static m1 + * m3 requires m2 + */ + public void testRequiresStatic7() { + ModuleDescriptor descriptor1 = null; // not observable + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE, + Requires.Modifier.STATIC), + "m1") + .build(); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires("m2") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3); + + Configuration cf = resolveRequires(finder, "m3"); + + assertTrue(cf.modules().size() == 2); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + assertTrue(m2.reads().isEmpty()); + assertTrue(m3.reads().size() == 1); + assertTrue(m3.reads().contains(m2)); + } + + + /** + * Basic test of "requires static": + * - Configuration cf1: m2 requires transitive static m1 + * - Configuration cf2: m3 requires m2 + */ + public void testRequiresStatic8() { + ModuleDescriptor descriptor1 = null; // not observable + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE, + Requires.Modifier.STATIC), + "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m2"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m2").isPresent()); + ResolvedModule m2 = cf1.findModule("m2").get(); + assertTrue(m2.reads().isEmpty()); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m3").isPresent()); + ResolvedModule m3 = cf2.findModule("m3").get(); + assertTrue(m3.reads().size() == 1); + assertTrue(m3.reads().contains(m2)); + } + + + /** * Basic test of binding services * m1 uses p.S * m2 provides p.S @@ -442,15 +811,15 @@ public void testServiceBinding1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); @@ -461,7 +830,8 @@ assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); assertTrue(cf.findModule("m2").isPresent()); - assertTrue(cf.parent().get() == Configuration.empty()); + assertTrue(cf.parents().size() == 1); + assertTrue(cf.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf.findModule("m1").get(); ResolvedModule m2 = cf.findModule("m2").get(); @@ -484,23 +854,23 @@ public void testServiceBinding2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .uses("p.S2") - .conceals("q") + .contains("q") .provides("p.S1", "q.Service1Impl") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m1") - .conceals("q") + .contains("q") .provides("p.S2", "q.Service2Impl") .build(); @@ -513,7 +883,8 @@ assertTrue(cf.findModule("m1").isPresent()); assertTrue(cf.findModule("m2").isPresent()); assertTrue(cf.findModule("m3").isPresent()); - assertTrue(cf.parent().get() == Configuration.empty()); + assertTrue(cf.parents().size() == 1); + assertTrue(cf.parents().get(0) == Configuration.empty()); ResolvedModule m1 = cf.findModule("m1").get(); ResolvedModule m2 = cf.findModule("m2").get(); @@ -542,7 +913,7 @@ public void testServiceBindingWithConfigurations1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") .build(); @@ -555,9 +926,9 @@ assertTrue(cf1.findModule("m1").isPresent()); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); @@ -565,7 +936,9 @@ Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); + assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m2").isPresent()); @@ -589,17 +962,17 @@ public void testServiceBindingWithConfigurations2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") - .conceals("p1") + .contains("p1") .provides("p.S", "p1.ServiceImpl") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") - .conceals("p2") + .contains("p2") .provides("p.S", "p2.ServiceImpl") .build(); @@ -613,16 +986,16 @@ ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m1") - .conceals("p3") + .contains("p3") .provides("p.S", "p3.ServiceImpl") .build(); ModuleDescriptor descriptor4 - = new ModuleDescriptor.Builder("m4") + = ModuleDescriptor.module("m4") .requires("m1") - .conceals("p4") + .contains("p4") .provides("p.S", "p4.ServiceImpl") .build(); @@ -630,7 +1003,9 @@ Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); + assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m3").isPresent()); assertTrue(cf2.findModule("m4").isPresent()); @@ -663,15 +1038,15 @@ public void testServiceBindingWithConfigurations3() { ModuleDescriptor service - = new ModuleDescriptor.Builder("s") + = ModuleDescriptor.module("s") .exports("p") .build(); ModuleDescriptor provider_v1 - = new ModuleDescriptor.Builder("p") + = ModuleDescriptor.module("p") .version("1.0") .requires("s") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); @@ -689,16 +1064,16 @@ ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("s") .uses("p.S") .build(); ModuleDescriptor provider_v2 - = new ModuleDescriptor.Builder("p") + = ModuleDescriptor.module("p") .version("2.0") .requires("s") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); @@ -709,7 +1084,8 @@ Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1"); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); assertTrue(cf2.modules().size() == 2); // p should be found in cf2 @@ -723,7 +1099,8 @@ cf2 = resolveRequiresAndUses(cf1, ModuleFinder.of(), finder2, "m1"); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); assertTrue(cf2.modules().size() == 1); // p should be found in cf1 @@ -741,17 +1118,17 @@ public void testWithTwoFinders1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .build(); ModuleDescriptor descriptor2_v1 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .version("1.0") .build(); ModuleDescriptor descriptor2_v2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .version("2.0") .build(); @@ -781,22 +1158,22 @@ public void testWithTwoFinders2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2_v1 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); ModuleDescriptor descriptor2_v2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); @@ -824,7 +1201,7 @@ public void testResolvedInParent1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); @@ -847,7 +1224,7 @@ public void testResolvedInParent2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -859,7 +1236,7 @@ ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .build(); @@ -880,12 +1257,221 @@ /** - * Basic test of using the beforeFinder to override a module in the parent + * Basic test of resolving a module that depends on modules in two parent + * configurations. + * + * The test consists of three configurations: + * - Configuration cf1: m1 + * - Configuration cf2: m2 + * - Configuration cf3(cf1,cf2): m3 requires m1, m2 + */ + public void testResolvedInMultipleParents1() { + + // Configuration cf1: m1 + ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); + Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + assertEquals(cf1.parents(), List.of(Configuration.empty())); + assertTrue(cf1.findModule("m1").isPresent()); + ResolvedModule m1 = cf1.findModule("m1").get(); + assertTrue(m1.configuration() == cf1); + + // Configuration cf2: m2 + ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build(); + Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2"); + assertEquals(cf2.parents(), List.of(Configuration.empty())); + assertTrue(cf2.findModule("m2").isPresent()); + ResolvedModule m2 = cf2.findModule("m2").get(); + assertTrue(m2.configuration() == cf2); + + // Configuration cf3(cf1,cf2): m3 requires m1 and m2 + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires("m1") + .requires("m2") + .build(); + ModuleFinder finder = ModuleUtils.finderOf(descriptor3); + Configuration cf3 = Configuration.resolveRequires( + finder, + List.of(cf1, cf2), // parents + ModuleFinder.of(), + Set.of("m3")); + assertEquals(cf3.parents(), List.of(cf1, cf2)); + assertTrue(cf3.findModule("m3").isPresent()); + ResolvedModule m3 = cf3.findModule("m3").get(); + assertTrue(m3.configuration() == cf3); + + // check readability + assertTrue(m1.reads().isEmpty()); + assertTrue(m2.reads().isEmpty()); + assertEquals(m3.reads(), Set.of(m1, m2)); + } + + + /** + * Basic test of resolving a module that depends on modules in three parent + * configurations arranged in a diamond (two direct parents). + * + * The test consists of four configurations: + * - Configuration cf1: m1 + * - Configuration cf2(cf1): m2 requires m1 + * - Configuration cf3(cf3): m3 requires m1 + * - Configuration cf4(cf2,cf3): m4 requires m1,m2,m3 + */ + public void testResolvedInMultipleParents2() { + // Configuration cf1: m1 + ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); + Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + assertEquals(cf1.parents(), List.of(Configuration.empty())); + assertTrue(cf1.findModule("m1").isPresent()); + ResolvedModule m1 = cf1.findModule("m1").get(); + assertTrue(m1.configuration() == cf1); + + // Configuration cf2(cf1): m2 requires m1 + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .requires("m1") + .build(); + Configuration cf2 = Configuration.resolveRequires( + ModuleUtils.finderOf(descriptor2), + List.of(cf1), // parents + ModuleFinder.of(), + Set.of("m2")); + assertEquals(cf2.parents(), List.of(cf1)); + assertTrue(cf2.findModule("m2").isPresent()); + ResolvedModule m2 = cf2.findModule("m2").get(); + assertTrue(m2.configuration() == cf2); + + // Configuration cf3(cf1): m3 requires m1 + ModuleDescriptor descriptor3 + = ModuleDescriptor.module("m3") + .requires("m1") + .build(); + Configuration cf3 = Configuration.resolveRequires( + ModuleUtils.finderOf(descriptor3), + List.of(cf1), // parents + ModuleFinder.of(), + Set.of("m3")); + assertEquals(cf3.parents(), List.of(cf1)); + assertTrue(cf3.findModule("m3").isPresent()); + ResolvedModule m3 = cf3.findModule("m3").get(); + assertTrue(m3.configuration() == cf3); + + // Configuration cf4(cf2,cf3): m4 requires m1,m2,m3 + ModuleDescriptor descriptor4 + = ModuleDescriptor.module("m4") + .requires("m1") + .requires("m2") + .requires("m3") + .build(); + Configuration cf4 = Configuration.resolveRequires( + ModuleUtils.finderOf(descriptor4), + List.of(cf2, cf3), // parents + ModuleFinder.of(), + Set.of("m4")); + assertEquals(cf4.parents(), List.of(cf2, cf3)); + assertTrue(cf4.findModule("m4").isPresent()); + ResolvedModule m4 = cf4.findModule("m4").get(); + assertTrue(m4.configuration() == cf4); + + // check readability + assertTrue(m1.reads().isEmpty()); + assertEquals(m2.reads(), Set.of(m1)); + assertEquals(m3.reads(), Set.of(m1)); + assertEquals(m4.reads(), Set.of(m1, m2, m3)); + } + + + /** + * Basic test of resolving a module that depends on modules in three parent + * configurations arranged in a diamond (two direct parents). + * + * The test consists of four configurations: + * - Configuration cf1: m1@1 + * - Configuration cf2: m1@2, m2@2 + * - Configuration cf3: m1@3, m2@3, m3@3 + * - Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3 + */ + public void testResolvedInMultipleParents3() { + ModuleDescriptor descriptor1, descriptor2, descriptor3; + + // Configuration cf1: m1@1 + descriptor1 = ModuleDescriptor.module("m1").version("1").build(); + Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + assertEquals(cf1.parents(), List.of(Configuration.empty())); + + // Configuration cf2: m1@2, m2@2 + descriptor1 = ModuleDescriptor.module("m1").version("2").build(); + descriptor2 = ModuleDescriptor.module("m2").version("2").build(); + Configuration cf2 = resolveRequires( + ModuleUtils.finderOf(descriptor1, descriptor2), + "m1", "m2"); + assertEquals(cf2.parents(), List.of(Configuration.empty())); + + // Configuration cf3: m1@3, m2@3, m3@3 + descriptor1 = ModuleDescriptor.module("m1").version("3").build(); + descriptor2 = ModuleDescriptor.module("m2").version("3").build(); + descriptor3 = ModuleDescriptor.module("m3").version("3").build(); + Configuration cf3 = resolveRequires( + ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3), + "m1", "m2", "m3"); + assertEquals(cf3.parents(), List.of(Configuration.empty())); + + // Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3 + ModuleDescriptor descriptor4 + = ModuleDescriptor.module("m4") + .requires("m1") + .requires("m2") + .requires("m3") + .build(); + Configuration cf4 = Configuration.resolveRequires( + ModuleUtils.finderOf(descriptor4), + List.of(cf1, cf2, cf3), // parents + ModuleFinder.of(), + Set.of("m4")); + assertEquals(cf4.parents(), List.of(cf1, cf2, cf3)); + + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf2.findModule("m1").isPresent()); + assertTrue(cf2.findModule("m2").isPresent()); + assertTrue(cf3.findModule("m1").isPresent()); + assertTrue(cf3.findModule("m2").isPresent()); + assertTrue(cf3.findModule("m3").isPresent()); + assertTrue(cf4.findModule("m4").isPresent()); + + ResolvedModule m1_1 = cf1.findModule("m1").get(); + ResolvedModule m1_2 = cf2.findModule("m1").get(); + ResolvedModule m2_2 = cf2.findModule("m2").get(); + ResolvedModule m1_3 = cf3.findModule("m1").get(); + ResolvedModule m2_3 = cf3.findModule("m2").get(); + ResolvedModule m3_3 = cf3.findModule("m3").get(); + ResolvedModule m4 = cf4.findModule("m4").get(); + + assertTrue(m1_1.configuration() == cf1); + assertTrue(m1_2.configuration() == cf2); + assertTrue(m2_2.configuration() == cf2); + assertTrue(m1_3.configuration() == cf3); + assertTrue(m2_3.configuration() == cf3); + assertTrue(m3_3.configuration() == cf3); + assertTrue(m4.configuration() == cf4); + + // check readability + assertTrue(m1_1.reads().isEmpty()); + assertTrue(m1_2.reads().isEmpty()); + assertTrue(m2_2.reads().isEmpty()); + assertTrue(m1_3.reads().isEmpty()); + assertTrue(m2_3.reads().isEmpty()); + assertTrue(m3_3.reads().isEmpty()); + assertEquals(m4.reads(), Set.of(m1_1, m2_2, m3_3)); + } + + + /** + * Basic test of using the beforeFinder to override a module in a parent * configuration. */ public void testOverriding1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); @@ -899,6 +1485,39 @@ assertTrue(cf2.findModule("m1").isPresent()); } + /** + * Basic test of using the beforeFinder to override a module in a parent + * configuration. + */ + public void testOverriding2() { + ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); + Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + + ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build(); + Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2"); + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m2").isPresent()); + + ModuleDescriptor descriptor3 = ModuleDescriptor.module("m3").build(); + Configuration cf3 = resolveRequires(ModuleUtils.finderOf(descriptor3), "m3"); + assertTrue(cf3.modules().size() == 1); + assertTrue(cf3.findModule("m3").isPresent()); + + // override m2, m1 and m3 should be found in parent configurations + ModuleFinder finder = ModuleUtils.finderOf(descriptor2); + Configuration cf4 = Configuration.resolveRequires( + finder, + List.of(cf1, cf2, cf3), + ModuleFinder.of(), + Set.of("m1", "m2", "m3")); + assertTrue(cf4.modules().size() == 1); + assertTrue(cf4.findModule("m2").isPresent()); + ResolvedModule m2 = cf4.findModule("m2").get(); + assertTrue(m2.configuration() == cf4); + } + /** * Basic test of using the beforeFinder to override a module in the parent @@ -906,18 +1525,18 @@ * module in the parent is read. * * The test consists of two configurations: - * - Configuration cf1: m1, m2 requires public m1 + * - Configuration cf1: m1, m2 requires transitive m1 * - Configuration cf2: m1, m3 requires m2 */ - public void testOverriding2() { + public void testOverriding3() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -931,7 +1550,7 @@ // cf2: m3 requires m2, m1 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -939,7 +1558,8 @@ Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3"); - assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.parents().size() == 1); + assertTrue(cf2.parents().get(0) == cf1); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m1").isPresent()); @@ -977,7 +1597,7 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testDirectDependencyNotFound() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1").requires("m2").build(); + = ModuleDescriptor.module("m1").requires("m2").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); resolveRequires(finder, "m1"); } @@ -989,9 +1609,9 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testTransitiveDependencyNotFound() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1").requires("m2").build(); + = ModuleDescriptor.module("m1").requires("m2").build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2").requires("m3").build(); + = ModuleDescriptor.module("m2").requires("m3").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); resolveRequires(finder, "m1"); } @@ -1006,16 +1626,16 @@ // service provider dependency (on m3) not found ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .requires("m3") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); @@ -1032,11 +1652,11 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testSimpleCycle() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1").requires("m2").build(); + = ModuleDescriptor.module("m1").requires("m2").build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2").requires("m3").build(); + = ModuleDescriptor.module("m2").requires("m3").build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3").requires("m1").build(); + = ModuleDescriptor.module("m3").requires("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); resolveRequires(finder, "m1"); @@ -1049,19 +1669,19 @@ public void testCycleInProvider() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .requires("m3") - .conceals("q") + .contains("q") .provides("p.S", "q.T") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -1080,19 +1700,19 @@ public void testPackageSuppliedByTwoOthers() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .requires("m3") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .exports("p") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") - .exports("p", "m1") + = ModuleDescriptor.module("m3") + .exports("p", Set.of("m1")) .build(); ModuleFinder finder @@ -1104,45 +1724,44 @@ /** - * Test the scenario where a module has a concealed package p and reads + * Test the scenario where a module contains a package p and reads * a module that exports package p. */ @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedBySelfAndOther() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") - .conceals("p") + .contains("p") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .exports("p") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - // m1 contains package p, module m2 exports package p to m1 + // m1 contains package p, module m2 exports package p to m1 resolveRequires(finder, "m1"); } /** - * Test the scenario where a module has a concealed package p and reads - * a module that also has a concealed package p. + * Test the scenario where a module contains a package p and reads + * a module that also contains a package p. */ - public void testPackagePrivateToSelfAndOther() { - + public void testContainsPackageInSelfAndOther() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") - .conceals("p") + .contains("p") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .conceals("p") + = ModuleDescriptor.module("m2") + .contains("p") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -1169,7 +1788,7 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testExportSamePackageAsBootLayer() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("java.base") .exports("java.lang") .build(); @@ -1184,12 +1803,12 @@ /** - * Test "uses p.S" where p is a concealed package in the same module. + * Test "uses p.S" where p is contained in the same module. */ - public void testConcealedService1() { + public void testContainsService1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .conceals("p") + = ModuleDescriptor.module("m1") + .contains("p") .uses("p.S") .build(); @@ -1203,17 +1822,17 @@ /** - * Test "uses p.S" where p is a concealed package in a different module. + * Test "uses p.S" where p is contained in a different module. */ @Test(expectedExceptions = { ResolutionException.class }) - public void testConcealedService2() { + public void testContainsService2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .conceals("p") + = ModuleDescriptor.module("m1") + .contains("p") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .uses("p.S") .build(); @@ -1226,13 +1845,13 @@ /** - * Test "provides p.S" where p is a concealed package in the same module. + * Test "provides p.S" where p is contained in the same module. */ - public void testConcealedService3() { + public void testContainsService3() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .conceals("p") - .conceals("q") + = ModuleDescriptor.module("m1") + .contains("p") + .contains("q") .provides("p.S", "q.S1") .build(); @@ -1246,19 +1865,19 @@ /** - * Test "provides p.S" where p is a concealed package in a different module. + * Test "provides p.S" where p is contained in a different module. */ @Test(expectedExceptions = { ResolutionException.class }) - public void testConcealedService4() { + public void testContainsService4() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .conceals("p") + = ModuleDescriptor.module("m1") + .contains("p") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") - .conceals("q") + .contains("q") .provides("p.S", "q.S1") .build(); @@ -1275,7 +1894,7 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .uses("p.S") .build(); @@ -1292,8 +1911,8 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") - .conceals("q") + = ModuleDescriptor.module("m1") + .contains("q") .provides("p.S", "q.T") .build(); @@ -1310,13 +1929,13 @@ @Test(expectedExceptions = { ResolutionException.class }) public void testProviderPackageNotLocal() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .exports("q") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .provides("p.S", "q.T") .build(); @@ -1334,7 +1953,7 @@ public void testEmptyConfiguration() { Configuration cf = Configuration.empty(); - assertFalse(cf.parent().isPresent()); + assertTrue(cf.parents().isEmpty()); assertTrue(cf.modules().isEmpty()); assertFalse(cf.findModule("java.base").isPresent()); @@ -1389,7 +2008,7 @@ public void testPlatformMatch(String s1, String s2) { ModuleDescriptor.Builder builder - = new ModuleDescriptor.Builder("m1").requires("m2"); + = ModuleDescriptor.module("m1").requires("m2"); String[] s = s1.split("-"); if (!s[0].equals("*")) @@ -1401,7 +2020,7 @@ ModuleDescriptor descriptor1 = builder.build(); - builder = new ModuleDescriptor.Builder("m2"); + builder = ModuleDescriptor.module("m2"); s = s2.split("-"); if (!s[0].equals("*")) @@ -1433,6 +2052,21 @@ } + // no parents + + @Test(expectedExceptions = { IllegalArgumentException.class }) + public void testResolveRequiresWithNoParents() { + ModuleFinder empty = ModuleFinder.of(); + Configuration.resolveRequires(empty, List.of(), empty, Set.of()); + } + + @Test(expectedExceptions = { IllegalArgumentException.class }) + public void testResolveRequiresAndUsesWithNoParents() { + ModuleFinder empty = ModuleFinder.of(); + Configuration.resolveRequiresAndUses(empty, List.of(), empty, Set.of()); + } + + // null handling // finder1, finder2, roots @@ -1449,6 +2083,31 @@ } @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresWithNull3() { + Configuration empty = Configuration.empty(); + Configuration.resolveRequires(null, List.of(empty), ModuleFinder.of(), Set.of()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresWithNull4() { + ModuleFinder empty = ModuleFinder.of(); + Configuration.resolveRequires(empty, null, empty, Set.of()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresWithNull5() { + Configuration cf = Layer.boot().configuration(); + Configuration.resolveRequires(ModuleFinder.of(), List.of(cf), null, Set.of()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresWithNull6() { + ModuleFinder empty = ModuleFinder.of(); + Configuration cf = Layer.boot().configuration(); + Configuration.resolveRequires(empty, List.of(cf), empty, null); + } + + @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull1() { resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.of()); } @@ -1459,6 +2118,31 @@ } @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresAndUsesWithNull3() { + Configuration empty = Configuration.empty(); + Configuration.resolveRequiresAndUses(null, List.of(empty), ModuleFinder.of(), Set.of()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresAndUsesWithNull4() { + ModuleFinder empty = ModuleFinder.of(); + Configuration.resolveRequiresAndUses(empty, null, empty, Set.of()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresAndUsesWithNull5() { + Configuration cf = Layer.boot().configuration(); + Configuration.resolveRequiresAndUses(ModuleFinder.of(), List.of(cf), null, Set.of()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresAndUsesWithNull6() { + ModuleFinder empty = ModuleFinder.of(); + Configuration cf = Layer.boot().configuration(); + Configuration.resolveRequiresAndUses(empty, List.of(cf), empty, null); + } + + @Test(expectedExceptions = { NullPointerException.class }) public void testFindModuleWithNull() { Configuration.empty().findModule(null); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/module/ModuleDescriptorTest.java --- a/jdk/test/java/lang/module/ModuleDescriptorTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,28 +23,34 @@ /** * @test - * @modules java.base/jdk.internal.module + * @modules java.base/java.lang.module:open + * java.base/jdk.internal.module * @run testng ModuleDescriptorTest * @summary Basic test for java.lang.module.ModuleDescriptor and its builder */ +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.module.InvalidModuleDescriptorException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleDescriptor.Version; +import java.lang.reflect.Constructor; import java.lang.reflect.Module; import java.nio.ByteBuffer; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; @@ -72,7 +78,7 @@ // requires private Requires requires(Set mods, String mn) { - return new Builder("m") + return ModuleDescriptor.module("m") .requires(mods, mn) .build() .requires() @@ -80,19 +86,15 @@ .next(); } - public void testRequiresWithRequires() { - Requires r1 = requires(null, "foo"); - ModuleDescriptor descriptor = new Builder("m").requires(r1).build(); - Requires r2 = descriptor.requires().iterator().next(); - assertEquals(r1, r2); + private Requires requires(String mn) { + return requires(Collections.emptySet(), mn); } - public void testRequiresWithNullModifiers() { - Requires r = requires(null, "foo"); - assertEquals(r, r); - assertTrue(r.compareTo(r) == 0); - assertTrue(r.modifiers().isEmpty()); - assertEquals(r.name(), "foo"); + public void testRequiresWithRequires() { + Requires r1 = requires("foo"); + ModuleDescriptor descriptor = ModuleDescriptor.module("m").requires(r1).build(); + Requires r2 = descriptor.requires().iterator().next(); + assertEquals(r1, r2); } public void testRequiresWithNoModifiers() { @@ -104,18 +106,18 @@ } public void testRequiresWithOneModifier() { - Requires r = requires(EnumSet.of(PUBLIC), "foo"); + Requires r = requires(EnumSet.of(TRANSITIVE), "foo"); assertEquals(r, r); assertTrue(r.compareTo(r) == 0); - assertEquals(r.modifiers(), EnumSet.of(PUBLIC)); + assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE)); assertEquals(r.name(), "foo"); } public void testRequiresWithTwoModifiers() { - Requires r = requires(EnumSet.of(PUBLIC, SYNTHETIC), "foo"); + Requires r = requires(EnumSet.of(TRANSITIVE, SYNTHETIC), "foo"); assertEquals(r, r); assertTrue(r.compareTo(r) == 0); - assertEquals(r.modifiers(), EnumSet.of(PUBLIC, SYNTHETIC)); + assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC)); assertEquals(r.name(), "foo"); } @@ -123,35 +125,35 @@ Requires r = requires(EnumSet.allOf(Modifier.class), "foo"); assertEquals(r, r); assertTrue(r.compareTo(r) == 0); - assertEquals(r.modifiers(), EnumSet.allOf(Modifier.class)); + assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED)); assertEquals(r.name(), "foo"); } @Test(expectedExceptions = IllegalStateException.class) public void testRequiresWithDuplicatesRequires() { - Requires r = requires(null, "foo"); - new Builder("m").requires(r).requires(r); + Requires r = requires("foo"); + ModuleDescriptor.module("m").requires(r).requires(r); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithRequires() { - Requires r = requires(null, "foo"); - new Builder("foo").requires(r); + Requires r = requires("foo"); + ModuleDescriptor.module("foo").requires(r); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithNoModifier() { - new Builder("m").requires("m"); + ModuleDescriptor.module("m").requires("m"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithOneModifier() { - new Builder("m").requires(PUBLIC, "m"); + ModuleDescriptor.module("m").requires(Set.of(TRANSITIVE), "m"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithAllModifiers() { - new Builder("m").requires(EnumSet.allOf(Modifier.class), "m"); + ModuleDescriptor.module("m").requires(EnumSet.allOf(Modifier.class), "m"); } @Test(dataProvider = "invalidjavaidentifiers", @@ -162,7 +164,7 @@ @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullRequires() { - new Builder("m").requires((Requires) null); + ModuleDescriptor.module("m").requires((Requires) null); } public void testRequiresCompare() { @@ -174,9 +176,9 @@ } public void testRequiresCompareWithDifferentModifiers() { - Requires r1 = requires(EnumSet.of(PUBLIC), "foo"); + Requires r1 = requires(EnumSet.of(TRANSITIVE), "foo"); Requires r2 = requires(EnumSet.of(SYNTHETIC), "foo"); - int n = Integer.compare(1 << PUBLIC.ordinal(), 1 << SYNTHETIC.ordinal()); + int n = Integer.compare(1 << TRANSITIVE.ordinal(), 1 << SYNTHETIC.ordinal()); assertTrue(r1.compareTo(r2) == n); assertTrue(r2.compareTo(r1) == -n); } @@ -188,6 +190,26 @@ assertTrue(r2.compareTo(r1) == 0); } + public void testRequiresEqualsAndHashCode() { + Requires r1 = requires("foo"); + Requires r2 = requires("foo"); + assertEquals(r1, r2); + assertTrue(r1.hashCode() == r2.hashCode()); + + r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo"); + r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo"); + assertEquals(r1, r2); + assertTrue(r1.hashCode() == r2.hashCode()); + + r1 = requires("foo"); + r2 = requires("bar"); + assertNotEquals(r1, r2); + + r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo"); + r2 = requires(Set.of(), "foo"); + assertNotEquals(r1, r2); + } + public void testRequiresToString() { Requires r = requires(EnumSet.noneOf(Modifier.class), "foo"); assertTrue(r.toString().contains("foo")); @@ -196,9 +218,22 @@ // exports + private Exports exports(Set mods, String pn) { + return ModuleDescriptor.module("foo") + .exports(mods, pn) + .build() + .exports() + .iterator() + .next(); + } + private Exports exports(String pn) { - return new Builder("foo") - .exports(pn) + return exports(Set.of(), pn); + } + + private Exports exports(Set mods, String pn, String target) { + return ModuleDescriptor.module("foo") + .exports(mods, pn, Set.of(target)) .build() .exports() .iterator() @@ -206,17 +241,13 @@ } private Exports exports(String pn, String target) { - return new Builder("foo") - .exports(pn, target) - .build() - .exports() - .iterator() - .next(); + return exports(Set.of(), pn, target); } + public void testExportsExports() { Exports e1 = exports("p"); - ModuleDescriptor descriptor = new Builder("m").exports(e1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.module("m").exports(e1).build(); Exports e2 = descriptor.exports().iterator().next(); assertEquals(e1, e2); } @@ -224,6 +255,7 @@ public void testExportsToAll() { Exports e = exports("p"); assertEquals(e, e); + assertTrue(e.modifiers().isEmpty()); assertEquals(e.source(), "p"); assertFalse(e.isQualified()); assertTrue(e.targets().isEmpty()); @@ -232,6 +264,7 @@ public void testExportsToTarget() { Exports e = exports("p", "bar"); assertEquals(e, e); + assertTrue(e.modifiers().isEmpty()); assertEquals(e.source(), "p"); assertTrue(e.isQualified()); assertTrue(e.targets().size() == 1); @@ -243,13 +276,14 @@ targets.add("bar"); targets.add("gus"); Exports e - = new Builder("foo") + = ModuleDescriptor.module("foo") .exports("p", targets) .build() .exports() .iterator() .next(); assertEquals(e, e); + assertTrue(e.modifiers().isEmpty()); assertEquals(e.source(), "p"); assertTrue(e.isQualified()); assertTrue(e.targets().size() == 2); @@ -257,56 +291,94 @@ assertTrue(e.targets().contains("gus")); } + public void testExportsToAllWithModifier() { + Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + assertEquals(e, e); + assertTrue(e.modifiers().size() == 1); + assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); + assertEquals(e.source(), "p"); + assertFalse(e.isQualified()); + assertTrue(e.targets().isEmpty()); + } + + public void testExportsToTargetWithModifier() { + Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", "bar"); + assertEquals(e, e); + assertTrue(e.modifiers().size() == 1); + assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); + assertEquals(e.source(), "p"); + assertTrue(e.isQualified()); + assertTrue(e.targets().size() == 1); + assertTrue(e.targets().contains("bar")); + } + @Test(expectedExceptions = IllegalStateException.class) public void testExportsWithDuplicate1() { Exports e = exports("p"); - new Builder("foo").exports(e).exports(e); + ModuleDescriptor.module("foo").exports(e).exports(e); } @Test(expectedExceptions = IllegalStateException.class) public void testExportsWithDuplicate2() { - new Builder("foo").exports("p").exports("p"); + ModuleDescriptor.module("foo").exports("p").exports("p"); } @Test(expectedExceptions = IllegalStateException.class) - public void testExportsWithConcealedPackage() { - new Builder("foo").conceals("p").exports("p"); + public void testExportsOnContainedPackage() { + ModuleDescriptor.module("foo").contains("p").exports("p"); } @Test(expectedExceptions = IllegalStateException.class) - public void testExportsToTargetWithConcealedPackage() { - new Builder("foo").conceals("p").exports("p", "bar"); + public void testExportsToTargetOnContainedPackage() { + ModuleDescriptor.module("foo").contains("p").exports("p", Set.of("bar")); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testExportsWithEmptySet() { - new Builder("foo").exports("p", Collections.emptySet()); + ModuleDescriptor.module("foo").exports("p", Collections.emptySet()); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testExportsWithBadName(String pn, String ignore) { - new Builder("foo").exports(pn); + ModuleDescriptor.module("foo").exports(pn); } @Test(expectedExceptions = NullPointerException.class ) public void testExportsWithNullExports() { - new Builder("foo").exports((Exports)null); - } - - @Test(expectedExceptions = IllegalArgumentException.class ) - public void testExportsWithNullTarget() { - new Builder("foo").exports("p", (String) null); + ModuleDescriptor.module("foo").exports((Exports) null); } @Test(expectedExceptions = NullPointerException.class ) public void testExportsWithNullTargets() { - new Builder("foo").exports("p", (Set) null); + ModuleDescriptor.module("foo").exports("p", (Set) null); + } + + public void testExportsEqualsAndHashCode() { + Exports e1, e2; + + e1 = exports("p"); + e2 = exports("p"); + assertEquals(e1, e2); + assertTrue(e1.hashCode() == e2.hashCode()); + + e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + assertEquals(e1, e2); + assertTrue(e1.hashCode() == e2.hashCode()); + + e1 = exports("p"); + e2 = exports("q"); + assertNotEquals(e1, e2); + + e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + e2 = exports(Set.of(), "p"); + assertNotEquals(e1, e2); } public void testExportsToString() { - String s = new Builder("foo") - .exports("p1", "bar") + String s = ModuleDescriptor.module("foo") + .exports("p1", Set.of("bar")) .build() .exports() .iterator() @@ -317,11 +389,188 @@ } + // opens + + private Opens opens(Set mods, String pn) { + return ModuleDescriptor.module("foo") + .opens(mods, pn) + .build() + .opens() + .iterator() + .next(); + } + + private Opens opens(String pn) { + return opens(Set.of(), pn); + } + + private Opens opens(Set mods, String pn, String target) { + return ModuleDescriptor.module("foo") + .opens(mods, pn, Set.of(target)) + .build() + .opens() + .iterator() + .next(); + } + + private Opens opens(String pn, String target) { + return opens(Set.of(), pn, target); + } + + public void testOpensOpens() { + Opens o1 = opens("p"); + ModuleDescriptor descriptor = ModuleDescriptor.module("m").opens(o1).build(); + Opens o2 = descriptor.opens().iterator().next(); + assertEquals(o1, o2); + } + + public void testOpensToAll() { + Opens o = opens("p"); + assertEquals(o, o); + assertTrue(o.modifiers().isEmpty()); + assertEquals(o.source(), "p"); + assertFalse(o.isQualified()); + assertTrue(o.targets().isEmpty()); + } + + + public void testOpensToTarget() { + Opens o = opens("p", "bar"); + assertEquals(o, o); + assertTrue(o.modifiers().isEmpty()); + assertEquals(o.source(), "p"); + assertTrue(o.isQualified()); + assertTrue(o.targets().size() == 1); + assertTrue(o.targets().contains("bar")); + } + + public void testOpensToTargets() { + Set targets = new HashSet<>(); + targets.add("bar"); + targets.add("gus"); + Opens o = ModuleDescriptor.module("foo") + .opens("p", targets) + .build() + .opens() + .iterator() + .next(); + assertEquals(o, o); + assertTrue(o.modifiers().isEmpty()); + assertEquals(o.source(), "p"); + assertTrue(o.isQualified()); + assertTrue(o.targets().size() == 2); + assertTrue(o.targets().contains("bar")); + assertTrue(o.targets().contains("gus")); + } + + /* + + public void testOpensToAllWithModifier() { + Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + assertEquals(e, e); + assertTrue(e.modifiers().size() == 1); + assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); + assertEquals(e.source(), "p"); + assertFalse(e.isQualified()); + assertTrue(e.targets().isEmpty()); + } + + public void testOpensToTargetWithModifier() { + Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", Set.of("bar")); + assertEquals(e, e); + assertTrue(e.modifiers().size() == 1); + assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); + assertEquals(e.source(), "p"); + assertTrue(e.isQualified()); + assertTrue(e.targets().size() == 1); + assertTrue(e.targets().contains("bar")); + } + + + */ + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensWithDuplicate1() { + Opens o = opens("p"); + ModuleDescriptor.module("foo").opens(o).opens(o); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensWithDuplicate2() { + ModuleDescriptor.module("foo").opens("p").opens("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnContainedPackage() { + ModuleDescriptor.module("foo").contains("p").opens("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensToTargetOnContainedPackage() { + ModuleDescriptor.module("foo").contains("p").opens("p", Set.of("bar")); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testOpensWithEmptySet() { + ModuleDescriptor.module("foo").opens("p", Collections.emptySet()); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testOpensWithBadName(String pn, String ignore) { + ModuleDescriptor.module("foo").opens(pn); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testOpensWithNullExports() { + ModuleDescriptor.module("foo").opens((Opens) null); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testOpensWithNullTargets() { + ModuleDescriptor.module("foo").opens("p", (Set) null); + } + + public void testOpensEqualsAndHashCode() { + Opens o1, o2; + + o1 = opens("p"); + o2 = opens("p"); + assertEquals(o1, o2); + assertTrue(o1.hashCode() == o1.hashCode()); + + o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + assertEquals(o1, o2); + assertTrue(o1.hashCode() == o2.hashCode()); + + o1 = opens("p"); + o2 = opens("q"); + assertNotEquals(o1, o2); + + o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + o2 = opens(Set.of(), "p"); + assertNotEquals(o1, o2); + } + + public void testOpensToString() { + String s = ModuleDescriptor.module("foo") + .opens("p1", Set.of("bar")) + .build() + .opens() + .iterator() + .next() + .toString(); + assertTrue(s.contains("p1")); + assertTrue(s.contains("bar")); + } + + // uses public void testUses() { Set uses - = new Builder("foo") + = ModuleDescriptor.module("foo") .uses("p.S") .uses("q.S") .build() @@ -333,126 +582,148 @@ @Test(expectedExceptions = IllegalStateException.class) public void testUsesWithDuplicate() { - new Builder("foo").uses("p.S").uses("p.S"); + ModuleDescriptor.module("foo").uses("p.S").uses("p.S"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testUsesWithBadName(String service, String ignore) { - new Builder("foo").uses(service); + ModuleDescriptor.module("foo").uses(service); } // provides private Provides provides(String st, String pc) { - return new Builder("foo") + return ModuleDescriptor.module("foo") .provides(st, pc) .build() .provides() - .values() .iterator() .next(); } public void testProvidesWithProvides() { Provides p1 = provides("p.S", "q.S1"); - ModuleDescriptor descriptor = new Builder("m").provides(p1).build(); - Provides p2 = descriptor.provides().get("p.S"); + ModuleDescriptor descriptor = ModuleDescriptor.module("m") + .provides(p1) + .build(); + Provides p2 = descriptor.provides().iterator().next(); assertEquals(p1, p2); } + public void testProvides() { - Set pns = new HashSet<>(); - pns.add("q.P1"); - pns.add("q.P2"); - - Map map - = new Builder("foo") - .provides("p.S", pns) + Set set = ModuleDescriptor.module("foo") + .provides("p.S", List.of("q.P1", "q.P2")) .build() .provides(); - assertTrue(map.size() == 1); + assertTrue(set.size() == 1); - Provides p = map.values().iterator().next(); + Provides p = set.iterator().next(); assertEquals(p, p); + assertEquals(p.service(), "p.S"); assertTrue(p.providers().size() == 2); - assertTrue(p.providers().contains("q.P1")); - assertTrue(p.providers().contains("q.P2")); + assertEquals(p.providers().get(0), "q.P1"); + assertEquals(p.providers().get(1), "q.P2"); } @Test(expectedExceptions = IllegalStateException.class ) public void testProvidesWithDuplicateProvides() { Provides p = provides("p.S", "q.S2"); - new Builder("m").provides("p.S", "q.S1").provides(p); + ModuleDescriptor.module("m").provides("p.S", "q.S1").provides(p); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithEmptySet() { - new Builder("foo").provides("p.Service", Collections.emptySet()); + ModuleDescriptor.module("foo").provides("p.Service", Collections.emptyList()); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithBadService(String service, String ignore) { - new Builder("foo").provides(service, "p.Provider"); + ModuleDescriptor.module("foo").provides(service, "p.Provider"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithBadProvider(String provider, String ignore) { - new Builder("foo").provides("p.Service", provider); + ModuleDescriptor.module("foo").provides("p.Service", provider); } @Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProvides() { - new Builder("foo").provides((Provides)null); + ModuleDescriptor.module("foo").provides((Provides) null); } @Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProviders() { - new Builder("foo").provides("p.S", (Set) null); + ModuleDescriptor.module("foo").provides("p.S", (List) null); + } + + public void testProvidesEqualsAndHashCode() { + Provides p1, p2; + + p1 = provides("p.S", "q.S1"); + p2 = provides("p.S", "q.S1"); + assertEquals(p1, p2); + assertTrue(p1.hashCode() == p2.hashCode()); + + p1 = provides("p.S", "q.S1"); + p2 = provides("p.S", "q.S2"); + assertNotEquals(p1, p2); + + p1 = provides("p.S", "q.S1"); + p2 = provides("p.S2", "q.S1"); + assertNotEquals(p1, p2); } - - // conceals + // contains - public void testConceals() { - Set conceals - = new Builder("foo").conceals("p").conceals("q").build().conceals(); - assertTrue(conceals.size() == 2); - assertTrue(conceals.contains("p")); - assertTrue(conceals.contains("q")); + public void testContains() { + Set packages = ModuleDescriptor.module("foo") + .contains("p") + .contains("q") + .build() + .packages(); + assertTrue(packages.size() == 2); + assertTrue(packages.contains("p")); + assertTrue(packages.contains("q")); } - public void testConcealsWithEmptySet() { - Set conceals - = new Builder("foo").conceals(Collections.emptySet()).build().conceals(); - assertTrue(conceals.size() == 0); + public void testContainsWithEmptySet() { + Set packages = ModuleDescriptor.module("foo") + .contains(Collections.emptySet()) + .build() + .packages(); + assertTrue(packages.size() == 0); } @Test(expectedExceptions = IllegalStateException.class) - public void testConcealsWithDuplicate() { - new Builder("foo").conceals("p").conceals("p"); + public void testContainsWithDuplicate() { + ModuleDescriptor.module("foo").contains("p").contains("p"); } @Test(expectedExceptions = IllegalStateException.class) - public void testConcealsWithExportedPackage() { - new Builder("foo").exports("p").conceals("p"); + public void testContainsWithExportedPackage() { + ModuleDescriptor.module("foo").exports("p").contains("p"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) - public void testConcealsWithBadName(String pn, String ignore) { - new Builder("foo").conceals(pn); + public void testContainsWithBadName(String pn, String ignore) { + ModuleDescriptor.module("foo").contains(pn); } // packages public void testPackages() { - Set packages - = new Builder("foo").exports("p").conceals("q").build().packages(); + Set packages = ModuleDescriptor.module("foo") + .exports("p") + .contains("q") + .build() + .packages(); assertTrue(packages.size() == 2); assertTrue(packages.contains("p")); assertTrue(packages.contains("q")); @@ -462,14 +733,14 @@ // name public void testModuleName() { - String mn = new Builder("foo").build().name(); + String mn = ModuleDescriptor.module("foo").build().name(); assertEquals(mn, "foo"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testBadModuleName(String mn, String ignore) { - new Builder(mn); + ModuleDescriptor.module(mn); } @@ -477,67 +748,107 @@ public void testVersion1() { Version v1 = Version.parse("1.0"); - Version v2 = new Builder("foo").version(v1).build().version().get(); + Version v2 = ModuleDescriptor.module("foo") + .version(v1) + .build() + .version() + .get(); assertEquals(v1, v2); } public void testVersion2() { String vs = "1.0"; - Version v1 = new Builder("foo").version(vs).build().version().get(); + Version v1 = ModuleDescriptor.module("foo") + .version(vs) + .build() + .version() + .get(); Version v2 = Version.parse(vs); assertEquals(v1, v2); } @Test(expectedExceptions = NullPointerException.class ) public void testNullVersion1() { - new Builder("foo").version((Version)null); + ModuleDescriptor.module("foo").version((Version) null); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testNullVersion2() { - new Builder("foo").version((String)null); + ModuleDescriptor.module("foo").version((String) null); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testEmptyVersion() { - new Builder("foo").version(""); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testDuplicateVersion1() { - Version v = Version.parse("2.0"); - new Builder("foo").version("1.0").version(v); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testDuplicateVersion2() { - new Builder("foo").version("1.0").version("2.0"); + ModuleDescriptor.module("foo").version(""); } // toNameAndVersion public void testToNameAndVersion() { - ModuleDescriptor md1 = new Builder("foo").build(); + ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); assertEquals(md1.toNameAndVersion(), "foo"); - ModuleDescriptor md2 = new Builder("foo").version("1.0").build(); + ModuleDescriptor md2 = ModuleDescriptor.module("foo").version("1.0").build(); assertEquals(md2.toNameAndVersion(), "foo@1.0"); } - // isAutomatic + // open modules + + public void testOpenModules() { + ModuleDescriptor descriptor = ModuleDescriptor.openModule("m") + .requires("java.base") + .contains("p") + .build(); + assertTrue(descriptor.isOpen()); + assertTrue(descriptor.packages().size() == 1); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.exports().isEmpty()); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnWeakModule1() { + ModuleDescriptor.openModule("foo").opens("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnWeakModule2() { + ModuleDescriptor.openModule("foo").opens("p", Set.of("bar")); + } + + public void testIsOpen() { + assertFalse(ModuleDescriptor.module("m").build().isOpen()); + assertFalse(ModuleDescriptor.automaticModule("m").build().isOpen()); + assertTrue(ModuleDescriptor.openModule("m").build().isOpen()); + } + + + // automatic modules + public void testIsAutomatic() { - ModuleDescriptor descriptor = new Builder("foo").build(); - assertFalse(descriptor.isAutomatic()); + ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build(); + assertFalse(descriptor1.isAutomatic()); + + ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build(); + assertFalse(descriptor2.isAutomatic()); + + ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build(); + assertTrue(descriptor3.isAutomatic()); } // isSynthetic public void testIsSynthetic() { assertFalse(Object.class.getModule().getDescriptor().isSynthetic()); - ModuleDescriptor descriptor = new Builder("foo").build(); - assertFalse(descriptor.isSynthetic()); + ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build(); + assertFalse(descriptor1.isSynthetic()); + + ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build(); + assertFalse(descriptor2.isSynthetic()); + + ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build(); + assertFalse(descriptor3.isSynthetic()); } @@ -545,92 +856,71 @@ public void testMainClass() { String mainClass - = new Builder("foo").mainClass("p.Main").build().mainClass().get(); + = ModuleDescriptor.module("foo").mainClass("p.Main").build().mainClass().get(); assertEquals(mainClass, "p.Main"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testMainClassWithBadName(String mainClass, String ignore) { - Builder builder = new Builder("foo"); + Builder builder = ModuleDescriptor.module("foo"); builder.mainClass(mainClass); } - @Test(expectedExceptions = IllegalStateException.class) - public void testDuplicateMainClass() { - new Builder("foo").mainClass("p.Main").mainClass("p.Main"); - } - // osName public void testOsName() { - String osName = new Builder("foo").osName("Linux").build().osName().get(); + String osName = ModuleDescriptor.module("foo").osName("Linux").build().osName().get(); assertEquals(osName, "Linux"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsName() { - new Builder("foo").osName(null); + ModuleDescriptor.module("foo").osName(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsName() { - new Builder("foo").osName(""); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testDuplicateOsName() { - new Builder("foo").osName("Linux").osName("Linux"); + ModuleDescriptor.module("foo").osName(""); } // osArch public void testOsArch() { - String osArch = new Builder("foo").osName("arm").build().osName().get(); + String osArch = ModuleDescriptor.module("foo").osName("arm").build().osName().get(); assertEquals(osArch, "arm"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsArch() { - new Builder("foo").osArch(null); + ModuleDescriptor.module("foo").osArch(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsArch() { - new Builder("foo").osArch(""); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testDuplicateOsArch() { - new Builder("foo").osArch("arm").osArch("arm"); + ModuleDescriptor.module("foo").osArch(""); } // osVersion public void testOsVersion() { - String osVersion = new Builder("foo").osName("11.2").build().osName().get(); + String osVersion = ModuleDescriptor.module("foo").osName("11.2").build().osName().get(); assertEquals(osVersion, "11.2"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsVersion() { - new Builder("foo").osVersion(null); + ModuleDescriptor.module("foo").osVersion(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsVersion() { - new Builder("foo").osVersion(""); + ModuleDescriptor.module("foo").osVersion(""); } - @Test(expectedExceptions = IllegalStateException.class) - public void testDuplicateOsVersion() { - new Builder("foo").osVersion("11.2").osVersion("11.2"); - } - - // reads private static InputStream EMPTY_INPUT_STREAM = new InputStream() { @@ -647,7 +937,8 @@ } }; - public void testRead() throws Exception { + // basic test reading module-info.class + public void testRead1() throws Exception { Module base = Object.class.getModule(); try (InputStream in = base.getResourceAsStream("module-info.class")) { @@ -664,9 +955,80 @@ } } - public void testReadsWithPackageFinder() { - // TBD: Need way to write a module-info.class without a - // ConcealedPackages attribute + /** + * Test reading a module-info.class that has a module name, requires, + * and qualified exports with module names that are not supported in the + * Java Language. + */ + public void testRead2() throws Exception { + // use non-public constructor to create a Builder that is not strict + Constructor ctor = Builder.class.getDeclaredConstructor(String.class, boolean.class); + ctor.setAccessible(true); + + Builder builder = (ModuleDescriptor.Builder) ctor.newInstance("m?1", false); + ModuleDescriptor descriptor = builder + .requires("java.base") + .requires("-m1") + .exports("p", Set.of("m2-")) + .build(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ModuleInfoWriter.write(descriptor, baos); + ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray()); + + descriptor = ModuleDescriptor.read(bb); + assertEquals(descriptor.name(), "m?1"); + + Set requires = descriptor.requires() + .stream() + .map(Requires::name) + .collect(Collectors.toSet()); + assertTrue(requires.size() == 2); + assertTrue(requires.contains("java.base")); + assertTrue(requires.contains("-m1")); + + assertTrue(descriptor.exports().size() == 1); + Exports e = descriptor.exports().iterator().next(); + assertTrue(e.targets().size() == 1); + assertTrue(e.targets().contains("m2-")); + } + + /** + * Test ModuleDescriptor with a packager finder + */ + public void testReadsWithPackageFinder() throws Exception { + ModuleDescriptor descriptor = ModuleDescriptor.module("foo") + .requires("java.base") + .build(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ModuleInfoWriter.write(descriptor, baos); + ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray()); + + descriptor = ModuleDescriptor.read(bb, () -> Set.of("p", "q")); + + assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().contains("p")); + assertTrue(descriptor.packages().contains("q")); + } + + /** + * Test ModuleDescriptor with a packager finder that doesn't return the + * complete set of packages. + */ + @Test(expectedExceptions = InvalidModuleDescriptorException.class) + public void testReadsWithBadPackageFinder() throws Exception { + ModuleDescriptor descriptor = ModuleDescriptor.module("foo") + .requires("java.base") + .exports("p") + .build(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ModuleInfoWriter.write(descriptor, baos); + ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray()); + + // package finder returns a set that doesn't include p + ModuleDescriptor.read(bb, () -> Set.of("q")); } @Test(expectedExceptions = InvalidModuleDescriptorException.class) @@ -689,7 +1051,7 @@ @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadOfJavaBaseWithRequires() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("java.base") + = ModuleDescriptor.module("java.base") .requires("other") .build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); @@ -699,7 +1061,7 @@ // The requires table must have an entry for java.base @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadWithEmptyRequires() { - ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build(); + ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); ModuleDescriptor.read(bb); } @@ -708,14 +1070,13 @@ @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadWithNoRequiresBase() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); ModuleDescriptor.read(bb); } - public void testReadWithNull() throws Exception { Module base = Object.class.getModule(); @@ -751,22 +1112,22 @@ // equals/hashCode/compareTo/toString public void testEqualsAndHashCode() { - ModuleDescriptor md1 = new Builder("foo").build(); - ModuleDescriptor md2 = new Builder("foo").build(); + ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor md2 = ModuleDescriptor.module("foo").build(); assertEquals(md1, md1); assertEquals(md1.hashCode(), md2.hashCode()); } public void testCompare() { - ModuleDescriptor md1 = new Builder("foo").build(); - ModuleDescriptor md2 = new Builder("bar").build(); + ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor md2 = ModuleDescriptor.module("bar").build(); int n = "foo".compareTo("bar"); assertTrue(md1.compareTo(md2) == n); assertTrue(md2.compareTo(md1) == -n); } public void testToString() { - String s = new Builder("m1").requires("m2").exports("p1").build().toString(); + String s = ModuleDescriptor.module("m1").requires("m2").exports("p1").build().toString(); assertTrue(s.contains("m1")); assertTrue(s.contains("m2")); assertTrue(s.contains("p1")); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/module/ModuleFinderTest.java --- a/jdk/test/java/lang/module/ModuleFinderTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/module/ModuleFinderTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -335,7 +335,7 @@ ModuleFinder finder = ModuleFinder.of(jar); Optional mref = finder.find("m"); - assertTrue(mref.isPresent(), "m not found"); + assertTrue(mref.isPresent(), "m1 not found"); ModuleDescriptor descriptor = mref.get().descriptor(); @@ -748,7 +748,7 @@ vs = mid.substring(i+1); } ModuleDescriptor.Builder builder - = new ModuleDescriptor.Builder(mn).requires("java.base"); + = ModuleDescriptor.module(mn).requires("java.base"); if (vs != null) builder.version(vs); return builder.build(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/module/ModuleReferenceTest.java --- a/jdk/test/java/lang/module/ModuleReferenceTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/module/ModuleReferenceTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -45,10 +45,10 @@ public void testBasic() throws Exception { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m") + = ModuleDescriptor.module("m") .exports("p") .exports("q") - .conceals("p.internal") + .contains("p.internal") .build(); URI uri = URI.create("module:/m"); @@ -76,7 +76,7 @@ public void testNullLocation() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m") + = ModuleDescriptor.module("m") .exports("p") .build(); Supplier supplier = makeSupplier(); @@ -86,7 +86,7 @@ @Test(expectedExceptions = { NullPointerException.class }) public void testNullSupplier() throws Exception { - ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m").build(); + ModuleDescriptor descriptor = ModuleDescriptor.module("m").build(); URI location = URI.create("module:/m"); new ModuleReference(descriptor, location, null); } @@ -94,11 +94,11 @@ public void testEqualsAndHashCode() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .build(); @@ -121,7 +121,7 @@ public void testToString() { - ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build(); + ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build(); URI uri = URI.create("module:/m1"); Supplier supplier = makeSupplier(); ModuleReference mref = new ModuleReference(descriptor, uri, supplier); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/module/MultiReleaseJarTest.java --- a/jdk/test/java/lang/module/MultiReleaseJarTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -80,7 +80,7 @@ public void testBasic() throws Exception { String name = "m1"; - ModuleDescriptor descriptor = new ModuleDescriptor.Builder(name) + ModuleDescriptor descriptor = ModuleDescriptor.module(name) .requires("java.base") .build(); @@ -117,12 +117,12 @@ public void testModuleInfoInVersionedSection() throws Exception { String name = "m1"; - ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name) + ModuleDescriptor descriptor1 = ModuleDescriptor.module(name) .requires("java.base") .build(); // module descriptor for versioned section - ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name) + ModuleDescriptor descriptor2 = ModuleDescriptor.module(name) .requires("java.base") .requires("jdk.unsupported") .build(); @@ -188,12 +188,12 @@ public void testModuleReader() throws Exception { String name = "m1"; - ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name) + ModuleDescriptor descriptor1 = ModuleDescriptor.module(name) .requires("java.base") .build(); // module descriptor for versioned section - ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name) + ModuleDescriptor descriptor2 = ModuleDescriptor.module(name) .requires("java.base") .requires("jdk.unsupported") .build(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/ref/FinalizerHistogramTest.java --- a/jdk/test/java/lang/ref/FinalizerHistogramTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/ref/FinalizerHistogramTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -31,6 +31,7 @@ /* * @test * @summary Unit test for FinalizerHistogram + * @modules java.base/java.lang.ref:open * @run main FinalizerHistogramTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java --- a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,8 @@ /** * @test * @build ModuleSetAccessibleTest - * @modules java.base/jdk.internal.misc + * @modules java.base/java.lang:open + * java.base/jdk.internal.misc:+open * @run testng ModuleSetAccessibleTest * @summary Test java.lang.reflect.AccessibleObject with modules */ @@ -142,81 +143,6 @@ /** - * Test that only public members of java.lang.reflect.Module can be make - * accessible. - */ - public void testJavaLangReflectModule() throws Exception { - - // non-public constructor - Constructor ctor - = Module.class.getDeclaredConstructor(ClassLoader.class, - ModuleDescriptor.class); - AccessibleObject[] ctors = { ctor }; - - try { - ctor.setAccessible(true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } - - try { - AccessibleObject.setAccessible(ctors, true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } - - // should succeed - ctor.setAccessible(false); - AccessibleObject.setAccessible(ctors, false); - - - // public method - Method method = Module.class.getMethod("addReads", Module.class); - AccessibleObject[] methods = { method }; - method.setAccessible(true); - AccessibleObject.setAccessible(methods, true); - method.setAccessible(false); - AccessibleObject.setAccessible(methods, false); - - // non-public method - method = Module.class.getDeclaredMethod("implAddReadsNoSync", Module.class); - methods[0] = method; - - try { - method.setAccessible(true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } - - try { - AccessibleObject.setAccessible(methods, true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } - - // should succeed - method.setAccessible(false); - AccessibleObject.setAccessible(methods, false); - - - // non-public field - Field field = Module.class.getDeclaredField("name"); - AccessibleObject[] fields = { field }; - - try { - field.setAccessible(true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } - - try { - AccessibleObject.setAccessible(fields, true); - assertTrue(false); - } catch (InaccessibleObjectException expected) { } - - // should succeed - field.setAccessible(false); - AccessibleObject.setAccessible(fields, false); - - } - - - /** * Test that the Class constructor cannot be make accessible. */ public void testJavaLangClass() throws Exception { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Layer/BasicLayerTest.java --- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,12 +32,14 @@ import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleFinder; import java.lang.reflect.Layer; import java.lang.reflect.LayerInstantiationException; import java.lang.reflect.Module; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -53,7 +55,7 @@ public void testEmpty() { Layer emptyLayer = Layer.empty(); - assertFalse(emptyLayer.parent().isPresent()); + assertTrue(emptyLayer.parents().isEmpty()); assertTrue(emptyLayer.configuration() == Configuration.empty()); @@ -97,8 +99,9 @@ // findLoader assertTrue(bootLayer.findLoader("java.base") == null); - // parent - assertTrue(bootLayer.parent().get() == Layer.empty()); + // parents + assertTrue(bootLayer.parents().size() == 1); + assertTrue(bootLayer.parents().get(0) == Layer.empty()); } @@ -107,18 +110,18 @@ */ public void testLayerOnEmpty() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .exports("p1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m3") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .build(); ModuleFinder finder @@ -178,8 +181,9 @@ assertTrue(false); } catch (IllegalArgumentException ignore) { } - // parent - assertTrue(layer.parent().get() == Layer.empty()); + // parents + assertTrue(layer.parents().size() == 1); + assertTrue(layer.parents().get(0) == Layer.empty()); } @@ -188,14 +192,14 @@ */ public void testLayerOnBoot() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .requires("java.base") .exports("p1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("java.base") .build(); @@ -241,8 +245,9 @@ assertTrue(layer.findLoader("m2") == loader); assertTrue(layer.findLoader("java.base") == null); - // parent - assertTrue(layer.parent().get() == Layer.boot()); + // parents + assertTrue(layer.parents().size() == 1); + assertTrue(layer.parents().get(0) == Layer.boot()); } @@ -250,16 +255,16 @@ * Exercise Layer defineModules with a configuration of two modules that * have the same module-private package. */ - public void testSameConcealedPackage() { + public void testPackageContainedInSelfAndOther() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") - .conceals("p") + .contains("p") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .conceals("p") + = ModuleDescriptor.module("m2") + .contains("p") .build(); ModuleFinder finder @@ -288,22 +293,22 @@ // m1 reads m2, m2 exports p to m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("m2") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .exports("p", "m1") + = ModuleDescriptor.module("m2") + .exports("p", Set.of("m1")) .build(); // m3 reads m4, m4 exports p to m3 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m4") .build(); ModuleDescriptor descriptor4 - = new ModuleDescriptor.Builder("m4") - .exports("p", "m3") + = ModuleDescriptor.module("m4") + .exports("p", Set.of("m3")) .build(); ModuleFinder finder @@ -325,7 +330,7 @@ map.put("m1", loader1); map.put("m2", loader1); map.put("m3", loader2); - map.put("m3", loader2); + map.put("m4", loader2); Layer.empty().defineModules(cf, map::get); // same loader @@ -338,20 +343,20 @@ /** - * Exercise Layer defineModules with a configuration that contains a module - * that has a concealed package that is the same name as a non-exported - * package in a parent layer. + * Exercise Layer defineModules with a configuration with a module that + * contains a package that is the same name as a non-exported package in + * a parent layer. */ - public void testConcealSamePackageAsBootLayer() { + public void testContainsSamePackageAsBootLayer() { // check assumption that java.base contains sun.launcher ModuleDescriptor base = Object.class.getModule().getDescriptor(); - assertTrue(base.conceals().contains("sun.launcher")); + assertTrue(base.packages().contains("sun.launcher")); ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("java.base") - .conceals("sun.launcher") + .contains("sun.launcher") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); @@ -370,20 +375,20 @@ * Test layers with implied readability. * * The test consists of three configurations: - * - Configuration/layer1: m1, m2 requires public m1 + * - Configuration/layer1: m1, m2 requires transitive m1 * - Configuration/layer2: m3 requires m1 */ public void testImpliedReadabilityWithLayers1() { - // cf1: m1 and m2, m2 requires public m1 + // cf1: m1 and m2, m2 requires transitive m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -397,7 +402,7 @@ // cf2: m3, m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -408,8 +413,11 @@ ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer1.parent().get() == Layer.empty()); - assertTrue(layer2.parent().get() == layer1); + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == Layer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); Module m1 = layer2.findModule("m1").get(); Module m2 = layer2.findModule("m2").get(); @@ -442,14 +450,14 @@ * * The test consists of three configurations: * - Configuration/layer1: m1 - * - Configuration/layer2: m2 requires public m3, m3 requires m2 + * - Configuration/layer2: m2 requires transitive m3, m3 requires m2 */ public void testImpliedReadabilityWithLayers2() { // cf1: m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -460,15 +468,15 @@ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - // cf2: m2, m3: m2 requires public m1, m3 requires m2 + // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -479,8 +487,11 @@ ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer1.parent().get() == Layer.empty()); - assertTrue(layer2.parent().get() == layer1); + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == Layer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); Module m1 = layer2.findModule("m1").get(); Module m2 = layer2.findModule("m2").get(); @@ -509,7 +520,7 @@ * * The test consists of three configurations: * - Configuration/layer1: m1 - * - Configuration/layer2: m2 requires public m1 + * - Configuration/layer2: m2 requires transitive m1 * - Configuration/layer3: m3 requires m1 */ public void testImpliedReadabilityWithLayers3() { @@ -517,7 +528,7 @@ // cf1: m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -528,11 +539,11 @@ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - // cf2: m2 requires public m1 + // cf2: m2 requires transitive m1 ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); @@ -546,7 +557,7 @@ // cf3: m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -557,9 +568,14 @@ ClassLoader cl3 = new ClassLoader() { }; Layer layer3 = layer2.defineModules(cf3, mn -> cl3); - assertTrue(layer1.parent().get() == Layer.empty()); - assertTrue(layer2.parent().get() == layer1); - assertTrue(layer3.parent().get() == layer2); + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == Layer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); + + assertTrue(layer3.parents().size() == 1); + assertTrue(layer3.parents().get(0) == layer2); Module m1 = layer3.findModule("m1").get(); Module m2 = layer3.findModule("m2").get(); @@ -587,20 +603,20 @@ * Test layers with implied readability. * * The test consists of two configurations: - * - Configuration/layer1: m1, m2 requires public m1 - * - Configuration/layer2: m3 requires public m2, m4 requires m3 + * - Configuration/layer1: m1, m2 requires transitive m1 + * - Configuration/layer2: m3 requires transitive m2, m4 requires m3 */ public void testImpliedReadabilityWithLayers4() { - // cf1: m1, m2 requires public m1 + // cf1: m1, m2 requires transitive m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") - .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -611,15 +627,15 @@ Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - // cf2: m3 requires public m2, m4 requires m3 + // cf2: m3 requires transitive m2, m4 requires m3 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") - .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2") + = ModuleDescriptor.module("m3") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") .build(); ModuleDescriptor descriptor4 - = new ModuleDescriptor.Builder("m4") + = ModuleDescriptor.module("m4") .requires("m3") .build(); @@ -631,8 +647,11 @@ ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer1.parent().get() == Layer.empty()); - assertTrue(layer2.parent().get() == layer1); + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == Layer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); Module m1 = layer2.findModule("m1").get(); Module m2 = layer2.findModule("m2").get(); @@ -675,7 +694,7 @@ public void testModuleAlreadyDefinedToLoader() { ModuleDescriptor md - = new ModuleDescriptor.Builder("m") + = ModuleDescriptor.module("m") .requires("java.base") .build(); @@ -704,14 +723,14 @@ public void testPackageAlreadyInNamedModule() { ModuleDescriptor md1 - = new ModuleDescriptor.Builder("m1") - .conceals("p") + = ModuleDescriptor.module("m1") + .contains("p") .requires("java.base") .build(); ModuleDescriptor md2 - = new ModuleDescriptor.Builder("m2") - .conceals("p") + = ModuleDescriptor.module("m2") + .contains("p") .requires("java.base") .build(); @@ -749,8 +768,8 @@ assertFalse(c.getModule().isNamed()); // in unnamed module ModuleDescriptor md - = new ModuleDescriptor.Builder("m") - .conceals(c.getPackageName()) + = ModuleDescriptor.module("m") + .contains(c.getPackageName()) .requires("java.base") .build(); @@ -768,7 +787,7 @@ */ public void testLayerWithJavaBase() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("java.base") + = ModuleDescriptor.module("java.base") .exports("java.lang") .build(); @@ -782,12 +801,7 @@ ClassLoader scl = ClassLoader.getSystemClassLoader(); try { - Layer.boot().defineModules(cf, loader -> null ); - assertTrue(false); - } catch (LayerInstantiationException e) { } - - try { - Layer.boot().defineModules(cf, loader -> new ClassLoader() { }); + Layer.boot().defineModules(cf, mn -> new ClassLoader() { }); assertTrue(false); } catch (LayerInstantiationException e) { } @@ -804,13 +818,81 @@ /** + * Attempt to create a Layer with a module containing a "java." package. + * This should only be allowed when the module is defined to the platform + * class loader. + */ + @Test(enabled = false) + public void testLayerWithJavaPackage() { + ModuleDescriptor descriptor + = ModuleDescriptor.module("foo") + .contains("java.foo") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("foo")); + assertTrue(cf.modules().size() == 1); + + ClassLoader pcl = ClassLoader.getPlatformClassLoader(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + try { + Layer.boot().defineModules(cf, mn -> new ClassLoader() { }); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + try { + Layer.boot().defineModulesWithOneLoader(cf, scl); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + try { + Layer.boot().defineModulesWithManyLoaders(cf, scl); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + // create layer with module defined to platform class loader + Layer layer = Layer.boot().defineModules(cf, mn -> pcl); + Optional om = layer.findModule("foo"); + assertTrue(om.isPresent()); + Module foo = om.get(); + assertTrue(foo.getClassLoader() == pcl); + assertTrue(foo.getPackages().length == 1); + assertTrue(foo.getPackages()[0].equals("java.foo")); + } + + + /** + * Attempt to create a Layer with a module defined to the boot loader + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testLayerWithBootLoader() { + ModuleDescriptor descriptor + = ModuleDescriptor.module("m1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + assertTrue(cf.modules().size() == 1); + + Layer.boot().defineModules(cf, mn -> null ); + } + + + /** * Parent of configuration != configuration of parent Layer */ @Test(expectedExceptions = { IllegalArgumentException.class }) public void testIncorrectParent1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("java.base") .build(); @@ -831,7 +913,7 @@ public void testIncorrectParent2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java --- a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,8 @@ * @summary Tests for java.lang.reflect.Layer@createWithXXX methods */ +import java.io.IOException; +import java.io.InputStream; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; @@ -38,8 +40,10 @@ import java.lang.reflect.LayerInstantiationException; import java.lang.reflect.Method; import java.lang.reflect.Module; +import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -263,10 +267,10 @@ public void testOverlappingPackages() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1").exports("p").build(); + = ModuleDescriptor.module("m1").exports("p").build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2").exports("p").build(); + = ModuleDescriptor.module("m2").exports("p").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -297,10 +301,10 @@ public void testSplitDelegation() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1").exports("p").build(); + = ModuleDescriptor.module("m1").exports("p").build(); ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2").exports("p").build(); + = ModuleDescriptor.module("m2").exports("p").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -312,10 +316,10 @@ checkLayer(layer1, "m1", "m2"); ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3").requires("m1").build(); + = ModuleDescriptor.module("m3").requires("m1").build(); ModuleDescriptor descriptor4 - = new ModuleDescriptor.Builder("m4").requires("m2").build(); + = ModuleDescriptor.module("m4").requires("m2").build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); @@ -568,6 +572,48 @@ } + /** + * Basic test of resource loading with a class loader created by + * Layer.defineModulesWithOneLoader. + */ + public void testResourcesOneLoader() throws Exception { + Configuration cf = resolveRequires("m1"); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); + ClassLoader loader = layer.findLoader("m1"); + testResourceLoading(loader, "p/Main.class"); + } + + /** + * Basic test of resource loading with a class loader created by + * Layer.defineModulesWithOneLoader. + */ + public void testResourcesManyLoaders() throws Exception { + Configuration cf = resolveRequires("m1"); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + ClassLoader loader = layer.findLoader("m1"); + testResourceLoading(loader, "p/Main.class"); + } + + /** + * Test that a resource is located by a class loader. + */ + private void testResourceLoading(ClassLoader loader, String name) + throws IOException + { + URL url = loader.getResource(name); + assertNotNull(url); + + try (InputStream in = loader.getResourceAsStream(name)) { + assertNotNull(in); + } + + Enumeration urls = loader.getResources(name); + assertTrue(urls.hasMoreElements()); + } + + // -- supporting methods -- diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Layer/LayerControllerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @build LayerControllerTest ModuleUtils + * @run testng LayerControllerTest + * @summary Basic tests for java.lang.reflect.Layer.Controller + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.List; +import java.util.Set; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class LayerControllerTest { + + /** + * Creates a Controller for a module layer containing modules m1 and m2. + * Module m1 contains p1, reads java.base, does not export/open any package + * Module m2 contains p2, reads java.base, does not export/open any package + */ + private Layer.Controller createTestLayer() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.module("m1") + .contains("p1") + .requires("java.base") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.module("m2") + .requires("java.base") + .contains("p2") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + Layer bootLayer = Layer.boot(); + + Configuration cf = bootLayer.configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2")); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + Layer.Controller controller + = Layer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl); + + Layer layer = controller.layer(); + + assertTrue(layer.modules().size() == 2); + assertTrue(layer.findModule("m1").isPresent()); + assertTrue(layer.findModule("m2").isPresent()); + + return controller; + } + + /** + * Basic test of Layer.Controller to update modules m1 and m2 to read and + * open packages to each other. + */ + public void testBasic() { + Layer.Controller controller = createTestLayer(); + Layer layer = controller.layer(); + Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new); + Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new); + + assertFalse(m1.canRead(m2)); + assertFalse(m1.isExported("p1")); + assertFalse(m1.isOpen("p1")); + assertFalse(m1.isExported("p1", m2)); + assertFalse(m1.isOpen("p1", m2)); + + assertFalse(m2.canRead(m1)); + assertFalse(m2.isExported("p2")); + assertFalse(m2.isOpen("p2")); + assertFalse(m2.isExported("p2", m1)); + assertFalse(m2.isOpen("p2", m1)); + + // update m1 to read m2 + assertTrue(controller.addReads(m1, m2) == controller); + assertTrue(m1.canRead(m2)); + assertFalse(m2.canRead(m1)); + + // update m2 to read m1 + assertTrue(controller.addReads(m2, m1) == controller); + assertTrue(m1.canRead(m2)); + assertTrue(m1.canRead(m1)); + + // update m1 to open p1 to m2 + assertTrue(controller.addOpens(m1, "p1", m2) == controller); + assertTrue(m1.isExported("p1", m2)); + assertTrue(m1.isOpen("p1", m2)); + assertFalse(m1.isExported("p1")); + assertFalse(m1.isOpen("p1")); + + // update m2 to open p2 to m1 + assertTrue(controller.addOpens(m2, "p2", m1) == controller); + assertTrue(m2.isExported("p2", m1)); + assertTrue(m2.isOpen("p2", m1)); + assertFalse(m2.isExported("p2")); + assertFalse(m2.isOpen("p2")); + } + + /** + * Test invalid argument handling + */ + public void testBadArguments() { + Layer.Controller controller = createTestLayer(); + Layer layer = controller.layer(); + Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new); + Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new); + Module base = Object.class.getModule(); + + // java.base is not in layer + try { + controller.addReads(base, m2); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + + // java.base is not in layer + try { + controller.addOpens(base, "java.lang", m2); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + + // m1 does not contain java.lang + try { + controller.addOpens(m1, "java.lang", m2); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + /** + * Test null handling + */ + public void testNulls() { + Layer.Controller controller = createTestLayer(); + Layer layer = controller.layer(); + Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new); + Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new); + assertTrue(m1 != null); + assertTrue(m2 != null); + + try { + controller.addReads(null, m2); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + controller.addReads(m1, null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + controller.addOpens(null, "p1", m2); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + controller.addOpens(m1, null, m2); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + controller.addOpens(m1, "p1", null); + assertTrue(false); + } catch (NullPointerException expected) { } + } +} \ No newline at end of file diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/AnnotationsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.nio.file.Files; +import java.nio.file.Path; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import jdk.internal.module.ClassFileAttributes; +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * @test + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.module + * java.xml + * @run testng AnnotationsTest + * @summary Basic test of annotations on modules + */ + +public class AnnotationsTest { + + /** + * Test that there are no annotations on an unnamed module. + */ + @Test + public void testUnnamedModule() { + Module module = this.getClass().getModule(); + assertTrue(module.getAnnotations().length == 0); + } + + /** + * Test loading a module with a RuntimeVisibleAnnotation attribute. + * The test copies the module-info.class for java.xml, adds the attribute, + * and then loads the updated module. + */ + @Test + public void testNamedModule() throws IOException { + + // "deprecate" java.xml + Path dir = Files.createTempDirectory("mods"); + deprecateModule("java.xml", true, "9", dir); + + // "load" the cloned java.xml + Module module = loadModule(dir, "java.xml"); + + // check the annotation is present + assertTrue(module.isAnnotationPresent(Deprecated.class)); + Deprecated d = module.getAnnotation(Deprecated.class); + assertNotNull(d, "@Deprecated not found"); + assertTrue(d.forRemoval()); + assertEquals(d.since(), "9"); + Annotation[] a = module.getAnnotations(); + assertTrue(a.length == 1); + assertTrue(a[0] instanceof Deprecated); + } + + + /** + * Copy the module-info.class for the given module, add the + * Deprecated annotation, and write the updated module-info.class + * to a directory. + */ + static void deprecateModule(String name, + boolean forRemoval, + String since, + Path output) throws IOException { + Module module = Layer.boot().findModule(name).orElse(null); + assertNotNull(module, name + " not found"); + + InputStream in = module.getResourceAsStream("module-info.class"); + assertNotNull(in, "No module-info.class for " + name); + + try (in) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); + + ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) { }; + + ClassReader cr = new ClassReader(in); + + List attrs = new ArrayList<>(); + attrs.add(new ClassFileAttributes.ModuleAttribute()); + attrs.add(new ClassFileAttributes.ModulePackagesAttribute()); + attrs.add(new ClassFileAttributes.ModuleVersionAttribute()); + attrs.add(new ClassFileAttributes.ModuleTargetAttribute()); + cr.accept(cv, attrs.toArray(new Attribute[0]), 0); + + AnnotationVisitor annotationVisitor + = cv.visitAnnotation("Ljava/lang/Deprecated;", true); + annotationVisitor.visit("forRemoval", forRemoval); + annotationVisitor.visit("since", since); + annotationVisitor.visitEnd(); + + byte[] bytes = cw.toByteArray(); + Path mi = output.resolve("module-info.class"); + Files.write(mi, bytes); + } + } + + /** + * Load the module of the given name in the given directory into a + * child layer. + */ + static Module loadModule(Path dir, String name) throws IOException { + ModuleFinder finder = ModuleFinder.of(dir); + + Layer bootLayer = Layer.boot(); + + Configuration cf = bootLayer.configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of(name)); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + + Module module = layer.findModule(name).orElse(null); + assertNotNull(module, name + " not loaded"); + return module; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/BasicModuleTest.java --- a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -174,8 +174,24 @@ // isExported assertTrue(base.isExported("java.lang")); assertTrue(base.isExported("java.lang", thisModule)); + assertTrue(base.isExported("java.lang", base)); + assertFalse(base.isExported("jdk.internal.misc")); + assertFalse(base.isExported("jdk.internal.misc", thisModule)); + assertTrue(base.isExported("jdk.internal.misc", base)); assertFalse(base.isExported("java.wombat")); assertFalse(base.isExported("java.wombat", thisModule)); + assertFalse(base.isExported("java.wombat", base)); + + // isOpen + assertFalse(base.isOpen("java.lang")); + assertFalse(base.isOpen("java.lang", thisModule)); + assertTrue(base.isOpen("java.lang", base)); + assertFalse(base.isOpen("jdk.internal.misc")); + assertFalse(base.isOpen("jdk.internal.misc", thisModule)); + assertTrue(base.isOpen("jdk.internal.misc", base)); + assertFalse(base.isOpen("java.wombat")); + assertFalse(base.isOpen("java.wombat", thisModule)); + assertFalse(base.isOpen("java.wombat", base)); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/WithSecurityManager.java --- a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,7 +23,7 @@ /** * @test - * @modules java.logging + * @modules jdk.compiler * @summary Test java.lang.reflect.Module methods that specify permission checks * @run main/othervm -Djava.security.policy=${test.src}/allow.policy WithSecurityManager allow * @run main/othervm WithSecurityManager deny @@ -47,8 +47,8 @@ public class WithSecurityManager { // a module that will be loaded into a child layer - static final String ANOTHER_MODULE = "java.logging"; - static final String ANOTHER_MODULE_RESOURCE = "java/util/logging/Logger.class"; + static final String ANOTHER_MODULE = "jdk.compiler"; + static final String ANOTHER_MODULE_RESOURCE = "com/sun/tools/javac/Main.class"; public static void main(String[] args) throws IOException { boolean allow = args[0].equals("allow"); @@ -144,4 +144,4 @@ throw new RuntimeException(); } -} \ No newline at end of file +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/AccessTest.java --- a/jdk/test/java/lang/reflect/Module/access/AccessTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/AccessTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -38,8 +38,8 @@ * @modules jdk.compiler * @build AccessTest CompilerUtils jdk.testlibrary.* * @run testng AccessTest - * @summary Driver for test that checks access to public members in exported - * and non-exported packages. + * @summary Driver for test that checks access to access to types in + * exported and non-exported packages. */ @Test @@ -74,6 +74,7 @@ int exitValue = executeTestJava("--module-path", MODS_DIR.toString(), "--add-modules", "target", + "-Dsun.reflect.enableStrictMode=true", "-m", "test/test.Main") .outputTo(System.out) .errorTo(System.out) diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/module-info.java --- a/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,5 +22,6 @@ */ module target { - exports p; + exports p1; + exports p2; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java --- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p; - -public class Exported { - - /** - * Public constructor - */ - public Exported() { } - - /** - * Public field - */ - public static Object field; - - /** - * Public method - */ - public static void run() { - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java --- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p; - -import java.lang.reflect.Module; - -public class Helper { - Helper() { } - - public static void exportPackage(String pn, Module who) { - Helper.class.getModule().addExports(pn, who); - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +import java.lang.reflect.Module; + +/** + * Helper class in target module to allow test invoke addExports[Private] + */ + +public class Helper { + Helper() { } + + public static void addExports(String pn, Module who) { + Helper.class.getModule().addExports(pn, who); + } + + public static void addOpens(String pn, Module who) { + Helper.class.getModule().addOpens(pn, who); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Public { + + // public constructor + public Public() { } + + // non-public constructor + private Public(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p2; + +class NonPublic { + + // public constructor + public NonPublic() { } + + // non-public constructor + private NonPublic(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java --- a/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package q; - -public class Internal { - - /** - * Public constructor - */ - public Internal() { } - - /** - * Public field - */ - public static Object field; - - /** - * Public method - */ - public static void run() { - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q1; + +public class Public { + + // public constructor + public Public() { } + + // non-public constructor + private Public(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q2; + +class NonPublic { + + // public constructor + public NonPublic() { } + + // non-public constructor + private NonPublic(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java --- a/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,166 +23,351 @@ package test; +import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.Layer; import java.lang.reflect.Method; import java.lang.reflect.Module; -import java.util.Optional; /** - * Test access to public members in exported and non-exported packages. + * Test access to public/non-public members of public/non-public classes in + * exported and non-exported packages. */ public class Main { public static void main(String[] args) throws Exception { + testPublicClassInExportedPackage(); + testNonPublicClassInExportedPackage(); + testPublicClassInNonExportedPackage(); + testNonPublicClassInNonExportedPackage(); + } + static void testPublicClassInExportedPackage() throws Exception { Module thisModule = Main.class.getModule(); - assertTrue(thisModule.isNamed()); + Module targetModule = getTargetModule(); + + assertTrue(targetModule.isExported("p1")); + assertTrue(targetModule.isExported("p1", thisModule)); + assertTrue(targetModule.isExported("p1", targetModule)); + + assertFalse(targetModule.isOpen("p1")); + assertFalse(targetModule.isOpen("p1", thisModule)); + assertTrue(targetModule.isOpen("p1", targetModule)); + + Class clazz = Class.forName("p1.Public"); + Constructor ctor1 = clazz.getConstructor(); // public + Constructor ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public + + Field f1 = clazz.getField("f1"); // public + Field f2 = clazz.getDeclaredField("f2"); // non-public + + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public - Optional om = Layer.boot().findModule("target"); - assertTrue(om.isPresent()); + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, false); + trySetAccessible(m1, true); + trySetAccessible(m2, false); + trySetAccessible(f1, true); + trySetAccessible(f2, false); + + targetAddOpens("p1", thisModule); - Module target = om.get(); + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, true); + trySetAccessible(m1, true); + trySetAccessible(m2, true); + trySetAccessible(f1, true); + trySetAccessible(f2, true); + } + + static void testNonPublicClassInExportedPackage() throws Exception { + Module thisModule = Main.class.getModule(); + Module targetModule = getTargetModule(); - assertTrue(target.isExported("p")); - assertTrue(target.isExported("p", thisModule)); + assertTrue(targetModule.isExported("p2")); + assertTrue(targetModule.isExported("p2", thisModule)); + assertTrue(targetModule.isExported("p2", targetModule)); + + assertFalse(targetModule.isOpen("p2")); + assertFalse(targetModule.isOpen("p2", thisModule)); + assertTrue(targetModule.isOpen("p1", targetModule)); + + Class clazz = Class.forName("p2.NonPublic"); + Constructor ctor1 = clazz.getConstructor(); + Constructor ctor2 = clazz.getDeclaredConstructor(Void.class); + + Field f1 = clazz.getField("f1"); // public + Field f2 = clazz.getDeclaredField("f2"); // non-public + + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public + + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, false); + trySetAccessible(ctor2, false); + trySetAccessible(m1, false); + trySetAccessible(m2, false); + trySetAccessible(f1, false); + trySetAccessible(f2, false); + + targetAddExports("p2", thisModule); - assertFalse(target.isExported("q")); - assertFalse(target.isExported("q", thisModule)); + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); + trySetAccessible(ctor1, false); + trySetAccessible(ctor2, false); + trySetAccessible(m1, false); + trySetAccessible(m2, false); + trySetAccessible(f1, false); + trySetAccessible(f2, false); + + targetAddOpens("p2", thisModule); - // thisModule does not read the target module + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); - assertFalse(thisModule.canRead(target)); + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, true); + trySetAccessible(m1, true); + trySetAccessible(m2, true); + trySetAccessible(f1, true); + trySetAccessible(f2, true); + } + + static void testPublicClassInNonExportedPackage() throws Exception { + Module thisModule = Main.class.getModule(); + Module targetModule = getTargetModule(); - tryAccessPublicMembers("p.Exported", true); - tryAccessPublicMembers("q.Internal", false); + assertFalse(targetModule.isExported("q1")); + assertFalse(targetModule.isExported("q1", thisModule)); + assertTrue(targetModule.isExported("q1", targetModule)); + + assertFalse(targetModule.isOpen("q1")); + assertFalse(targetModule.isOpen("q1", thisModule)); + assertTrue(targetModule.isOpen("q1", targetModule)); + + Class clazz = Class.forName("q1.Public"); + Constructor ctor1 = clazz.getConstructor(); // public + Constructor ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public + + Field f1 = clazz.getField("f1"); // public + Field f2 = clazz.getDeclaredField("f2"); // non-public + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, false); + trySetAccessible(ctor2, false); + trySetAccessible(m1, false); + trySetAccessible(m2, false); + trySetAccessible(f1, false); + trySetAccessible(f2, false); - // thisModule reads the target module + targetAddExports("q1", thisModule); + + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, false); + trySetAccessible(m1, true); + trySetAccessible(m2, false); + trySetAccessible(f1, true); + trySetAccessible(f2, false); - thisModule.addReads(target); - assertTrue(thisModule.canRead(target)); + targetAddOpens("q1", thisModule); + + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor1, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, true); + trySetAccessible(m1, true); + trySetAccessible(m2, true); + trySetAccessible(f1, true); + trySetAccessible(f2, true); + } - tryAccessPublicMembers("p.Exported", true); - tryAccessPublicMembers("q.Internal", false); + static void testNonPublicClassInNonExportedPackage() throws Exception { + Module thisModule = Main.class.getModule(); + Module targetModule = getTargetModule(); + + assertFalse(targetModule.isExported("q2")); + assertFalse(targetModule.isExported("q2", thisModule)); + assertTrue(targetModule.isExported("q2", targetModule)); + + assertFalse(targetModule.isOpen("q2")); + assertFalse(targetModule.isOpen("q2", thisModule)); + assertTrue(targetModule.isOpen("q2", targetModule)); + Class clazz = Class.forName("q2.NonPublic"); + Constructor ctor1 = clazz.getConstructor(); // public + Constructor ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public + Field f1 = clazz.getField("f1"); // public + Field f2 = clazz.getDeclaredField("f2"); // non-public - // change target module to export its internal package to thisModule + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public + + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); - targetAddExports("q", thisModule); - assertFalse(target.isExported("q")); - assertTrue(target.isExported("q", thisModule)); + trySetAccessible(ctor1, false); + trySetAccessible(ctor2, false); + trySetAccessible(m1, false); + trySetAccessible(m2, false); + trySetAccessible(f1, false); + trySetAccessible(f2, false); + + targetAddExports("q2", thisModule); + + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); - tryAccessPublicMembers("p.Exported", true); - tryAccessPublicMembers("q.Internal", true); + trySetAccessible(ctor1, false); + trySetAccessible(ctor2, false); + trySetAccessible(m1, false); + trySetAccessible(m2, false); + trySetAccessible(f1, false); + trySetAccessible(f2, false); + + targetAddOpens("q2", thisModule); + + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(m1, true); + trySetAccessible(m2, true); + trySetAccessible(f1, true); + trySetAccessible(f2, true); } - /** - * Attempt to access public members in a target class. - */ - static void tryAccessPublicMembers(String cn, boolean shouldSucceed) - throws Exception - { - - Class clazz = Class.forName(cn); - - Module thisModule = Main.class.getModule(); - Module targetModule = clazz.getModule(); + static Module getTargetModule() { + return Layer.boot().findModule("target").get(); + } - // check if the target class is in an exported package - String pn = cn.substring(0, cn.lastIndexOf('.')); - boolean exported = targetModule.isExported(pn, thisModule); - assertTrue(exported == shouldSucceed); - boolean shouldFail = !shouldSucceed; - - - // Class.newInstance - - try { - clazz.newInstance(); - assertTrue(shouldSucceed); - } catch (IllegalAccessException e) { - assertTrue(shouldFail); - } - - - // Constructor.newInstance and Constructor.setAccessible - - Constructor ctor = clazz.getConstructor(); + static void tryAccessConstructor(Constructor ctor, boolean shouldSucceed) { try { ctor.newInstance(); assertTrue(shouldSucceed); - } catch (IllegalAccessException e) { - assertTrue(shouldFail); + } catch (Exception e) { + assertFalse(shouldSucceed); } - try { - ctor.setAccessible(true); - assertTrue(shouldSucceed); - ctor.newInstance(); - } catch (InaccessibleObjectException e) { - assertTrue(shouldFail); - } + } - - // Method.invoke and Method.setAccessible - - Method m = clazz.getDeclaredMethod("run"); + static void tryAccessMethod(Method method, boolean shouldSucceed) { try { - m.invoke(null); - assertTrue(shouldSucceed); - } catch (IllegalAccessException e) { - assertTrue(shouldFail); - } - try { - m.setAccessible(true); + method.invoke(null); assertTrue(shouldSucceed); - m.invoke(null); - } catch (InaccessibleObjectException e) { - assertTrue(shouldFail); + } catch (Exception e) { + e.printStackTrace(); + assertFalse(shouldSucceed); } + } - // Field.get, Field.set and Field.setAccessible - - Field f = clazz.getDeclaredField("field"); + static void tryAccessObjectField(Field f, boolean shouldSucceed) { try { f.get(null); assertTrue(shouldSucceed); - } catch (IllegalAccessException e) { - assertTrue(shouldFail); + } catch (Exception e) { + assertFalse(shouldSucceed); } try { - f.set(null, 100); + f.set(null, new Object()); assertTrue(shouldSucceed); - } catch (IllegalAccessException e) { - assertTrue(shouldFail); + } catch (Exception e) { + assertFalse(shouldSucceed); } + } + + static void trySetAccessible(AccessibleObject ao, boolean shouldSucceed) { try { - f.setAccessible(true); - f.get(null); - f.set(null, 100); + ao.setAccessible(true); assertTrue(shouldSucceed); - } catch (InaccessibleObjectException e) { - assertTrue(shouldFail); + } catch (Exception e) { + assertFalse(shouldSucceed); } - } /** * Update target module to export a package to the given module. */ static void targetAddExports(String pn, Module who) throws Exception { - Class helper = Class.forName("p.Helper"); - Method m = helper.getMethod("exportPackage", String.class, Module.class); + Class helper = Class.forName("p1.Helper"); + Method m = helper.getMethod("addExports", String.class, Module.class); m.invoke(null, pn, who); } + /** + * Update target module to open a package to the given module. + */ + static void targetAddOpens(String pn, Module who) throws Exception { + Class helper = Class.forName("p1.Helper"); + Method m = helper.getMethod("addOpens", String.class, Module.class); + m.invoke(null, pn, who); + } static void assertTrue(boolean expr) { if (!expr) throw new RuntimeException(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/annotation/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/annotation/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library src + * @build m/* Basic + * @run testng/othervm Basic + * @summary Basic test for annotations on modules + */ + +import java.lang.reflect.Module; +import java.util.Arrays; + +import p.annotation.Foo; +import p.annotation.Bar; +import p.annotation.Baz; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class Basic { + + final Module module = Foo.class.getModule(); + + /** + * {@code @Foo} does not have RUNTIME retention policy. + */ + @Test + public void testInvisibleAnnotation() { + assertFalse(module.isAnnotationPresent(Foo.class)); + assertNull(module.getAnnotation(Foo.class)); + } + + /** + * {@code @Bar} has RUNTIME retention policy and value "bar" + */ + @Test + public void testBarAnnotation() { + assertTrue(module.isAnnotationPresent(Bar.class)); + Bar bar = module.getAnnotation(Bar.class); + assertNotNull(bar); + assertEquals(bar.value(), "bar"); + } + + /** + * {@code @Baz} has RUNTIME retention policy has a repeating value + */ + @Test + public void testBazAnnotation() { + assertTrue(module.isAnnotationPresent(Baz.class)); + Baz baz = module.getAnnotation(Baz.class); + assertNotNull(baz); + String[] expected = { "one", "two", "three" }; + assertTrue(Arrays.equals(baz.value(), expected)); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import p.annotation.*; + +@Foo +@Bar("bar") +@Baz({"one", "two", "three"}) +module m { + exports p.annotation; +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.MODULE; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value={MODULE}) +public @interface Bar { + String value(); +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.MODULE; + +@Target(value={MODULE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Baz { + String[] value(); +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.annotation; + +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.MODULE; + +@Target(value={MODULE}) +public @interface Foo {} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java --- a/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,6 +22,6 @@ */ module m3 { - requires public m2; + requires transitive m2; exports p.three; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/lang/reflect/Proxy/src/test/module-info.java --- a/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,7 +23,7 @@ module test { requires m1; - requires m3; // requires public m2 + requires m3; // requires transitive m2 exports jdk.test; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/net/InterfaceAddress/Equals.java --- a/jdk/test/java/net/InterfaceAddress/Equals.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/net/InterfaceAddress/Equals.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,7 @@ /* @test * @bug 6628576 + * @modules java.base/java.net:open * @summary InterfaceAddress.equals() NPE when broadcast field == null */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/nio/Buffer/Basic.java --- a/jdk/test/java/nio/Buffer/Basic.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/nio/Buffer/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,8 @@ * 4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 6231529 * 6221101 6234263 6535542 6591971 6593946 6795561 7190219 7199551 8065556 * 8149469 - * @modules java.base/jdk.internal.misc + * @modules java.base/java.nio:open + * java.base/jdk.internal.misc * @author Mark Reinhold */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/nio/channels/Selector/TemporarySelector.java --- a/jdk/test/java/nio/channels/Selector/TemporarySelector.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/nio/channels/Selector/TemporarySelector.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,7 +23,7 @@ /* @test * @bug 6645197 - * @run main/othervm -Xmx5m TemporarySelector + * @run main/othervm -Xmx16m TemporarySelector * @summary Timed read with socket adaptor throws ClosedSelectorException if temporary selector GC'ed. */ import java.io.IOException; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh --- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh Thu Dec 01 08:57:53 2016 +0000 @@ -109,7 +109,8 @@ go() { echo '' - sh -xc "$JAVA ${TESTVMOPTS} --add-exports java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \ + sh -xc "$JAVA ${TESTVMOPTS} --add-opens java.base/java.io=ALL-UNNAMED \ + --add-opens java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \ $1 $2 $3 $4 $5 $6 $7 $8" 2>&1 if [ $? != 0 ]; then failures=`expr $failures + 1`; fi } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/nio/file/etc/Exceptions.java --- a/jdk/test/java/nio/file/etc/Exceptions.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/nio/file/etc/Exceptions.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,7 @@ /* @test * @bug 4313887 6881498 + * @modules java.base/java.lang:open * @summary Miscellenous tests on exceptions in java.nio.file */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java Thu Dec 01 08:57:53 2016 +0000 @@ -37,7 +37,7 @@ * * @library ../../../testlibrary * @modules java.rmi/sun.rmi.registry - * java.rmi/sun.rmi.server + * java.rmi/sun.rmi.server:+open * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp * java.base/sun.nio.ch diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java --- a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,7 +30,7 @@ * rather than pinning it indefinitely. * @author Peter Jones * - * @modules java.rmi/sun.rmi.transport + * @modules java.rmi/sun.rmi.transport:+open * @build DGCAckFailure DGCAckFailure_Stub * @run main/othervm DGCAckFailure */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java --- a/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,7 @@ * @summary Tests proper parsing and defaulting of the * "java.rmi.server.useCodebaseOnly" property. * - * @modules java.rmi/sun.rmi.server + * @modules java.rmi/sun.rmi.server:+open * @run main/othervm UseCodebaseOnlyDefault true * @run main/othervm -Djava.rmi.server.useCodebaseOnly=xyzzy UseCodebaseOnlyDefault true * @run main/othervm -Djava.rmi.server.useCodebaseOnly UseCodebaseOnlyDefault true diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java --- a/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,7 +29,7 @@ * * @library ../../testlibrary * @modules java.rmi/sun.rmi.registry - * java.rmi/sun.rmi.server + * java.rmi/sun.rmi.server:+open * java.rmi/sun.rmi.transport * java.rmi/sun.rmi.transport.tcp * @build TestLibrary diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java --- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java Thu Dec 01 08:57:53 2016 +0000 @@ -77,7 +77,7 @@ TestParams.defaultPolicy + " --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED" + " --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED" + - " --add-exports java.rmi/sun.rmi.transport=ALL-UNNAMED" + + " --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED" + " --add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" + " -Djava.rmi.dgc.leaseValue=500000" + " -Dsun.rmi.dgc.checkInterval=" + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/security/modules/ModularTest.java --- a/jdk/test/java/security/modules/ModularTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/security/modules/ModularTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -164,7 +164,7 @@ final Builder builder; if (moduleType == MODULE_TYPE.EXPLICIT) { System.out.format(" %nGenerating ModuleDescriptor object"); - builder = new Builder(moduleName).exports(pkg); + builder = ModuleDescriptor.module(moduleName).exports(pkg); if (isService && serviceInterface != null && serviceImpl != null) { builder.provides(serviceInterface, serviceImpl); } else { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/security/testlibrary/Proc.java --- a/jdk/test/java/security/testlibrary/Proc.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/security/testlibrary/Proc.java Thu Dec 01 08:57:53 2016 +0000 @@ -257,7 +257,8 @@ if (hasModules) { Stream.of(jdk.internal.misc.VM.getRuntimeArguments()) - .filter(arg -> arg.startsWith("--add-exports=")) + .filter(arg -> arg.startsWith("--add-exports=") || + arg.startsWith("--add-opens=")) .forEach(cmd::add); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/time/TEST.properties --- a/jdk/test/java/time/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/time/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -4,3 +4,4 @@ modules = jdk.localedata lib.dirs = ../../lib/testlibrary lib.build = jdk.testlibrary.RandomFactory +modules = java.base/java.time:open java.base/java.time.chrono:open java.base/java.time.zone:open diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ArrayList/ArrayManagement.java --- a/jdk/test/java/util/ArrayList/ArrayManagement.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/ArrayList/ArrayManagement.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 8146568 * @summary brittle white box test of internal array management + * @modules java.base/java.util:open * @run testng ArrayManagement */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Calendar/StampOverflow.java --- a/jdk/test/java/util/Calendar/StampOverflow.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Calendar/StampOverflow.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 4404619 6348819 * @summary Make sure that Calendar doesn't cause nextStamp overflow. + * @modules java.base/java.util:open */ import java.lang.reflect.*; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Collection/MOAT.java --- a/jdk/test/java/util/Collection/MOAT.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Collection/MOAT.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * 4802647 7123424 8024709 * @summary Run many tests on many Collection and Map implementations * @author Martin Buchholz + * @modules java.base/java.util:open * @run main MOAT * @key randomness */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Collections/SyncSubMutexes.java --- a/jdk/test/java/util/Collections/SyncSubMutexes.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Collections/SyncSubMutexes.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,7 @@ * @bug 8048209 * @summary Check that Collections.synchronizedNavigableSet().tailSet() is using * the same lock object as it's source. + * @modules java.base/java.util:open * @run testng SyncSubMutexes */ import java.lang.reflect.Field; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Currency/CurrencyTest.java --- a/jdk/test/java/util/Currency/CurrencyTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Currency/CurrencyTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,8 @@ * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 8150324 * @summary Basic tests for Currency class. - * @modules jdk.localedata + * @modules java.base/java.util:open + * jdk.localedata */ import java.io.ByteArrayInputStream; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Currency/ValidateISO4217.java --- a/jdk/test/java/util/Currency/ValidateISO4217.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Currency/ValidateISO4217.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,8 @@ * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 * @summary Validate ISO 4217 data for Currency class. + * @modules java.base/java.util:open + * jdk.localedata */ /* diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/EnumSet/OneUniverse.java --- a/jdk/test/java/util/EnumSet/OneUniverse.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/EnumSet/OneUniverse.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @test * @bug 6276988 * @summary All enum constants in a class should share a single "universe". + * @modules java.base/java.util:open */ import java.lang.reflect.Field; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Hashtable/DeserializedLength.java --- a/jdk/test/java/util/Hashtable/DeserializedLength.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Hashtable/DeserializedLength.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * @test * @bug 8068427 * @summary Hashtable deserialization reconstitutes table with wrong capacity + * @modules java.base/java.util:open */ public class DeserializedLength { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/IdentityHashMap/Capacity.java --- a/jdk/test/java/util/IdentityHashMap/Capacity.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/IdentityHashMap/Capacity.java Thu Dec 01 08:57:53 2016 +0000 @@ -38,6 +38,7 @@ * @bug 6904367 * @summary IdentityHashMap reallocates storage when inserting expected * number of elements + * @modules java.base/java.util:open * @run testng Capacity * @key randomness */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/Locale/bug6312358.java --- a/jdk/test/java/util/Locale/bug6312358.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/Locale/bug6312358.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ * @bug 6312358 * @summary Verify that an NPE is thrown by issueing Locale.getInstance() with * any argument being null. + * @modules java.base/java.util:open */ import java.lang.reflect.InvocationTargetException; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/ReferencesTest.java --- a/jdk/test/java/util/ResourceBundle/ReferencesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/ResourceBundle/ReferencesTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,6 +23,7 @@ /* * @test * @bug 4405807 + * @modules java.base/java.util:open * @run main/othervm -Xms10m ReferencesTest * @summary Verify that references from ResourceBundle cache don't prevent * class loader reclamation. diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh --- a/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh Thu Dec 01 08:57:53 2016 +0000 @@ -71,7 +71,8 @@ echo 'jdk.test.Main should load bundles local to named module "test".' $JAVA -p mods -m test/jdk.test.Main de fr ja zh-tw en de || STATUS=1 -echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path." -$JAVA -cp extra.jar -p mods -m test/jdk.test.Main vi && STATUS=1 +echo "jdk.test.Main should load bundles from the jar file specified by the class-path." +$JAVA -cp extra.jar -p mods -m test/jdk.test.Main vi || STATUS=1 + exit $STATUS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", + locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println(rb.getBaseBundleName() + ": locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + System.out.println("ERROR: " + value + " expected: " + tag); + errors++; + } + + // inaccessible bundles + try { + ResourceBundle.getBundle("jdk.test.internal.resources.Foo", locale); + System.out.println("ERROR: jdk.test.internal.resources.Foo should not be accessible"); + errors++; + } catch (MissingResourceException e) { + e.printStackTrace(); + + Throwable cause = e.getCause(); + System.out.println("Expected: " + + (cause != null ? cause.getMessage() : e.getMessage())); + } + } + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.internal.resources; + +import java.util.ListResourceBundle; + +public class Foo extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.internal.resources; + +import java.util.ListResourceBundle; + +public class Foo_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.internal.resources; + +import java.util.ListResourceBundle; + +public class Foo_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.internal.resources; + +import java.util.ListResourceBundle; + +public class Foo_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +key=ja: message diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +key=zh: message diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +key=zh-TW: message diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +key=ja: message diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +key=zh: message diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +key=zh-TW: message diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module bundles { + opens jdk.test.resources; +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,74 @@ +# +# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @summary Test unnamed module to find resource bundles exported +# from a named module + + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java" + +rm -rf mods + +mkdir -p mods/test + +B=bundles +mkdir -p mods/$B +CLASSES="`find $TESTSRC/src/$B -name '*.java'`" +if [ "x$CLASSES" != x ]; then + $JAVAC -g -d mods --module-source-path $TESTSRC/src $CLASSES +fi +PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`" +if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$B/$D + cp $TESTSRC/src/$B/$P mods/$B/$D/ + done +fi + +mkdir classes +$JAVAC -d classes $TESTSRC/Main.java + +# access resource bundles that are exported private unconditionally +$JAVA -cp classes --module-path mods --add-modules bundles \ + Main de fr ja zh-tw en de + +# --add-exports can't open resources +$JAVA -cp classes --module-path mods --add-modules bundles \ + --add-opens bundles/jdk.test.internal.resources=ALL-UNNAMED \ + Main de fr ja zh-tw en de + +exit $? diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh --- a/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh Thu Dec 01 08:57:53 2016 +0000 @@ -111,9 +111,9 @@ runJava -cp mods/named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \ jdk.test.resources.props.MyResources true runJava -cp mods/named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \ - jdk.test.resources.classes.MyResources false + jdk.test.resources.classes.MyResources true runJava -cp mods/named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \ - jdk.test.resources.props.MyResources false + jdk.test.resources.props.MyResources true # Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg # both of which specify an unnamed module with ResourceBundle.getBundle. @@ -171,13 +171,13 @@ # Add mods/exported.named.bundles to the class path. runJava -cp mods/exported.named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \ - jdk.test.resources.exported.classes.MyResources false + jdk.test.resources.exported.classes.MyResources true runJava -cp mods/exported.named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \ - jdk.test.resources.exported.props.MyResources false + jdk.test.resources.exported.props.MyResources true runJava -cp mods/exported.named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \ - jdk.test.resources.exported.classes.MyResources false + jdk.test.resources.exported.classes.MyResources true runJava -cp mods/exported.named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \ - jdk.test.resources.exported.props.MyResources false + jdk.test.resources.exported.props.MyResources true # Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg # which specify an unnamed module with ResourceBundle.getBundle. diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/Basic.java --- a/jdk/test/java/util/ServiceLoader/Basic.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// - -import java.io.*; -import java.util.*; - - -public class Basic { - - private static PrintStream out = System.err; - - private static Set setOf(Iterable it) { - Set s = new HashSet(); - for (T t : it) - s.add(t); - return s; - } - - private static void checkEquals(Set s1, Set s2, boolean eq) { - if (s1.equals(s2) != eq) - throw new RuntimeException(String.format("%b %s : %s", - eq, s1, s2)); - } - - abstract static class TestLoader { - String name; - - TestLoader(String name) { this.name = name; } - - abstract ServiceLoader load(); - } - - static TestLoader tcclLoader = new TestLoader("Thread context class loader") { - ServiceLoader load() { - return ServiceLoader.load(FooService.class); - } - }; - - static TestLoader systemClLoader = new TestLoader("System class loader") { - ServiceLoader load() { - return ServiceLoader.load(FooService.class, ClassLoader.getSystemClassLoader()); - } - }; - - static TestLoader nullClLoader = new TestLoader("null (defer to system class loader)") { - ServiceLoader load() { - return ServiceLoader.load(FooService.class, null); - } - }; - - public static void main(String[] args) { - for (TestLoader tl : Arrays.asList(tcclLoader, systemClLoader, nullClLoader)) { - test(tl); - } - } - - static void test(TestLoader tl) { - ServiceLoader sl = tl.load(); - out.format("%s: %s%n", tl.name, sl); - - // Providers are cached - Set ps = setOf(sl); - checkEquals(ps, setOf(sl), true); - - // The cache can be flushed and reloaded - sl.reload(); - checkEquals(ps, setOf(sl), false); - - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/FooProvider1.java --- a/jdk/test/java/util/ServiceLoader/FooProvider1.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -public class FooProvider1 extends FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/FooProvider2.java --- a/jdk/test/java/util/ServiceLoader/FooProvider2.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -public class FooProvider2 extends FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/FooProvider3.java --- a/jdk/test/java/util/ServiceLoader/FooProvider3.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -public class FooProvider3 extends FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/FooService.java --- a/jdk/test/java/util/ServiceLoader/FooService.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -public abstract class FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/Load.java --- a/jdk/test/java/util/ServiceLoader/Load.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// - -import java.io.*; -import java.util.*; - - -public class Load { - - private static PrintStream out = System.err; - - public static void main(String[] args) throws Exception { - - boolean installedOnly = false; - - List expected = new ArrayList(Arrays.asList(args)); - if (!expected.isEmpty() && expected.get(0).equals("-i")) { - expected.remove(0); - installedOnly = true; - } - if (expected.isEmpty()) - throw new Exception("usage: Load [-i] ( fail | provider-class-name )*"); - - ServiceLoader sl = (installedOnly - ? ServiceLoader.loadInstalled(FooService.class) - : ServiceLoader.load(FooService.class)); - out.format("%s%n", sl); - Iterator sli = sl.iterator(); - Iterator ei = expected.iterator(); - - for (;; ei.remove()) { - FooService fp = null; - try { - if (!sli.hasNext()) - break; - fp = sli.next(); - } catch (ServiceConfigurationError x) { - if (ei.next().equals("fail")) { - out.format("Failed as expected: %s%n", x); - continue; - } - throw x; - } - String ec = ei.next(); - if (!fp.getClass().getName().equals(ec)) - throw new - Exception(String.format("Wrong provider %s; expected %s", - fp.getClass().getName(), ec)); - out.format("Provider found: %s%n", fp.getClass().getName()); - } - - if (ei.hasNext()) - throw new Exception("Missing providers: " + expected); - - } - -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic.sh --- a/jdk/test/java/util/ServiceLoader/basic.sh Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -# -# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test -# @bug 4640520 6354623 7198496 -# @summary Unit test for java.util.ServiceLoader -# -# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3 -# @run shell basic.sh - -# Command-line usage: sh basic.sh /path/to/build - -if [ -z "$TESTJAVA" ]; then - if [ $# -lt 1 ]; then exit 1; fi - TESTJAVA="$1"; shift - COMPILEJAVA="${TESTJAVA}" - TESTSRC="`pwd`" - TESTCLASSES="`pwd`" -fi - -JAVA="$TESTJAVA/bin/java" -JAR="$COMPILEJAVA/bin/jar" - -OS=`uname -s` -case "$OS" in - SunOS | Darwin | AIX ) - FS='/' - SEP=':' ;; - Linux ) - FS='/' - SEP=':' ;; - * ) - FS='\\' - SEP='\;' ;; -esac - -JARD=x.jar -EXTD=x.ext -TESTD=x.test -P3JAR=${EXTD}${FS}p3.jar - -if [ \! -d $EXTD ]; then - # Initialize - echo Initializing... - rm -rf $JARD $EXTD $TESTD - mkdir -p $JARD $EXTD $TESTD - - for n in 2 3; do - rm -rf $JARD/*; mkdir -p $JARD/META-INF/services - echo FooProvider$n \ - >$JARD/META-INF/services/FooService - cp $TESTCLASSES/FooProvider$n.class $JARD - if [ $n = 3 ]; then - cp $TESTCLASSES/FooService.class $JARD - fi - (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *) - done - - mv p3.jar $EXTD - - cp $TESTCLASSES/Load.class $TESTD - cp $TESTCLASSES/FooService.class $TESTD - cp $TESTCLASSES/FooProvider1.class $TESTD - mkdir -p $TESTD/META-INF/services - echo FooProvider1 \ - >$TESTD/META-INF/services/FooService - - # This gives us: - # $TESTD: FooProvider1 - # . : FooProvider2, in p2.jar - # $EXTD: FooProvider3, in p3.jar - -fi - -failures=0 - -go() { - echo '' - cp="$1"; shift - if [ -z "$cp" ]; then cp="$TESTCLASSES"; else cp="$TESTCLASSES$SEP$cp"; fi - vmargs="$1"; shift - sh -xc "'$JAVA' ${TESTVMOPTS} -cp $cp $vmargs $T $*" 2>&1 - if [ $? != 0 ]; then failures=`expr $failures + 1`; fi -} - - -# Java-level tests - -T=Basic -go ".${SEP}$TESTD${SEP}p2.jar" "" - -# Success cases - -T=Load - -go "$TESTD" "" FooProvider1 - -go ".${SEP}p2.jar" "" FooProvider2 - -go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2 - -go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2 - -go "${P3JAR}${SEP}$TESTD" "" FooProvider3 FooProvider1 - -go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \ - FooProvider3 FooProvider1 FooProvider2 - -# Failure cases - -mkdir -p x.meta/META-INF/services - -# Simple failures -for p in FooProvider42 'blah blah' 9234 'X!' java.lang.Object; do - echo $p >x.meta/META-INF/services/FooService - go ".${SEP}x.meta" "" fail -done - -# Failures followed by successes -echo FooProvider42 >x.meta/META-INF/services/FooService -go "$TESTD${SEP}x.meta" "" FooProvider1 fail -go "x.meta${SEP}$TESTD" "" fail FooProvider1 -go "$TESTD${SEP}x.meta${SEP}${SEP}p2.jar" "" \ - FooProvider1 fail FooProvider2 - - -# Summary - -echo '' -if [ $failures -gt 0 ]; - then echo "$failures case(s) failed"; - else echo "All cases passed"; fi -exit $failures diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/BarProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/BarProvider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class BarProvider { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// + +import java.io.*; +import java.util.*; + + +public class Basic { + + private static PrintStream out = System.err; + + private static Set setOf(Iterable it) { + Set s = new HashSet(); + for (T t : it) + s.add(t); + return s; + } + + private static void checkEquals(Set s1, Set s2, boolean eq) { + if (s1.equals(s2) != eq) + throw new RuntimeException(String.format("%b %s : %s", + eq, s1, s2)); + } + + abstract static class TestLoader { + String name; + + TestLoader(String name) { this.name = name; } + + abstract ServiceLoader load(); + } + + static TestLoader tcclLoader = new TestLoader("Thread context class loader") { + ServiceLoader load() { + return ServiceLoader.load(FooService.class); + } + }; + + static TestLoader systemClLoader = new TestLoader("System class loader") { + ServiceLoader load() { + return ServiceLoader.load(FooService.class, ClassLoader.getSystemClassLoader()); + } + }; + + static TestLoader nullClLoader = new TestLoader("null (defer to system class loader)") { + ServiceLoader load() { + return ServiceLoader.load(FooService.class, null); + } + }; + + public static void main(String[] args) { + for (TestLoader tl : Arrays.asList(tcclLoader, systemClLoader, nullClLoader)) { + test(tl); + } + } + + static void test(TestLoader tl) { + ServiceLoader sl = tl.load(); + out.format("%s: %s%n", tl.name, sl); + + // Providers are cached + Set ps = setOf(sl); + checkEquals(ps, setOf(sl), true); + + // The cache can be flushed and reloaded + sl.reload(); + checkEquals(ps, setOf(sl), false); + + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/FooProvider1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider1.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class FooProvider1 extends FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/FooProvider2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider2.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class FooProvider2 extends FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/FooProvider3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider3.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class FooProvider3 extends FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/FooService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/FooService.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public abstract class FooService { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/Load.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/Load.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// + +import java.io.*; +import java.util.*; + + +public class Load { + + private static PrintStream out = System.err; + + public static void main(String[] args) throws Exception { + + boolean installedOnly = false; + + List expected = new ArrayList(Arrays.asList(args)); + if (!expected.isEmpty() && expected.get(0).equals("-i")) { + expected.remove(0); + installedOnly = true; + } + if (expected.isEmpty()) + throw new Exception("usage: Load [-i] ( fail | provider-class-name )*"); + + ServiceLoader sl = (installedOnly + ? ServiceLoader.loadInstalled(FooService.class) + : ServiceLoader.load(FooService.class)); + out.format("%s%n", sl); + Iterator sli = sl.iterator(); + Iterator ei = expected.iterator(); + + for (;; ei.remove()) { + FooService fp = null; + try { + if (!sli.hasNext()) + break; + fp = sli.next(); + } catch (ServiceConfigurationError x) { + if (ei.next().equals("fail")) { + out.format("Failed as expected: %s%n", x); + continue; + } + throw x; + } + String ec = ei.next(); + if (!fp.getClass().getName().equals(ec)) + throw new + Exception(String.format("Wrong provider %s; expected %s", + fp.getClass().getName(), ec)); + out.format("Provider found: %s%n", fp.getClass().getName()); + } + + if (ei.hasNext()) + throw new Exception("Missing providers: " + expected); + + } + +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/basic/basic.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/basic/basic.sh Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,153 @@ +# +# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 4640520 6354623 7198496 +# @summary Unit test for java.util.ServiceLoader +# +# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3 BarProvider +# @run shell basic.sh + +# Command-line usage: sh basic.sh /path/to/build + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVA="$TESTJAVA/bin/java" +JAR="$COMPILEJAVA/bin/jar" + +OS=`uname -s` +case "$OS" in + SunOS | Darwin | AIX ) + FS='/' + SEP=':' ;; + Linux ) + FS='/' + SEP=':' ;; + * ) + FS='\\' + SEP='\;' ;; +esac + +JARD=x.jar +EXTD=x.ext +TESTD=x.test +P3JAR=${EXTD}${FS}p3.jar + +if [ \! -d $EXTD ]; then + # Initialize + echo Initializing... + rm -rf $JARD $EXTD $TESTD + mkdir -p $JARD $EXTD $TESTD + + for n in 2 3; do + rm -rf $JARD/*; mkdir -p $JARD/META-INF/services + echo FooProvider$n \ + >$JARD/META-INF/services/FooService + cp $TESTCLASSES/FooProvider$n.class $JARD + if [ $n = 3 ]; then + cp $TESTCLASSES/FooService.class $JARD + fi + (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *) + done + + mv p3.jar $EXTD + + cp $TESTCLASSES/Load.class $TESTD + cp $TESTCLASSES/FooService.class $TESTD + cp $TESTCLASSES/FooProvider1.class $TESTD + mkdir -p $TESTD/META-INF/services + echo FooProvider1 \ + >$TESTD/META-INF/services/FooService + + # This gives us: + # $TESTD: FooProvider1 + # . : FooProvider2, in p2.jar + # $EXTD: FooProvider3, in p3.jar + +fi + +failures=0 + +go() { + echo '' + cp="$1"; shift + if [ -z "$cp" ]; then cp="$TESTCLASSES"; else cp="$TESTCLASSES$SEP$cp"; fi + vmargs="$1"; shift + sh -xc "'$JAVA' ${TESTVMOPTS} -cp $cp $vmargs $T $*" 2>&1 + if [ $? != 0 ]; then failures=`expr $failures + 1`; fi +} + + +# Java-level tests + +T=Basic +go ".${SEP}$TESTD${SEP}p2.jar" "" + +# Success cases + +T=Load + +go "$TESTD" "" FooProvider1 + +go ".${SEP}p2.jar" "" FooProvider2 + +go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2 + +go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2 + +go "${P3JAR}${SEP}$TESTD" "" FooProvider3 FooProvider1 + +go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \ + FooProvider3 FooProvider1 FooProvider2 + +# Failure cases + +mkdir -p x.meta/META-INF/services + +# Simple failures +for p in FooProvider42 'blah blah' 9234 'X!' BarProvider; do + echo $p >x.meta/META-INF/services/FooService + go ".${SEP}x.meta" "" fail +done + +# Failures followed by successes +echo FooProvider42 >x.meta/META-INF/services/FooService +go "$TESTD${SEP}x.meta" "" FooProvider1 fail +go "x.meta${SEP}$TESTD" "" fail FooProvider1 +go "$TESTD${SEP}x.meta${SEP}${SEP}p2.jar" "" \ + FooProvider1 fail FooProvider2 + + +# Summary + +echo '' +if [ $failures -gt 0 ]; + then echo "$failures case(s) failed"; + else echo "All cases passed"; fi +exit $failures diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build CompilerUtils + * @run testng/othervm BadProvidersTest + * @summary Basic test of ServiceLoader with bad provider and bad provider + * factories deployed on the module path + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.ServiceLoader.Provider; +import java.util.Set; +import java.util.stream.Collectors; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.*; + +/** + * Basic test of `provides S with PF` and `provides S with P` where the provider + * factory or provider + */ + +public class BadProvidersTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + private static final Path SRC_DIR = Paths.get(TEST_SRC, "modules"); + + private static final Path BADFACTORIES_DIR = Paths.get(TEST_SRC, "badfactories"); + private static final Path BADPROVIDERS_DIR = Paths.get(TEST_SRC, "badproviders"); + + private static final String TEST1_MODULE = "test1"; + private static final String TEST2_MODULE = "test2"; + + private static final String TEST_SERVICE = "p.Service"; + + /** + * Compiles a module, returning a module path with the compiled module. + */ + private Path compileTest(String moduleName) throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path output = Files.createDirectory(dir.resolve(moduleName)); + boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(moduleName), output); + assertTrue(compiled); + return dir; + } + + /** + * Resolves a test module and loads it into its own layer. ServiceLoader + * is then used to load all providers. + */ + private List loadProviders(Path mp, String moduleName) throws Exception { + ModuleFinder finder = ModuleFinder.of(mp); + + Layer bootLayer = Layer.boot(); + + Configuration cf = bootLayer.configuration() + .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(moduleName)); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); + + Class service = layer.findLoader(moduleName).loadClass(TEST_SERVICE); + + return ServiceLoader.load(layer, service) + .stream() + .collect(Collectors.toList()); + } + + @Test + public void sanityTest1() throws Exception { + Path mods = compileTest(TEST1_MODULE); + List list = loadProviders(mods, TEST1_MODULE); + assertTrue(list.size() == 1); + + // the provider is a singleton, enforced by the provider factory + Object p1 = list.get(0).get(); + Object p2 = list.get(0).get(); + assertTrue(p1 != null); + assertTrue(p1 == p2); + } + + @Test + public void sanityTest2() throws Exception { + Path mods = compileTest(TEST2_MODULE); + List list = loadProviders(mods, TEST2_MODULE); + assertTrue(list.size() == 1); + Object p = list.get(0).get(); + assertTrue(p != null); + } + + + @DataProvider(name = "badfactories") + public Object[][] createBadFactories() { + return new Object[][] { + { "classnotpublic", null }, + { "methodnotpublic", null }, + { "badreturntype", null }, + { "returnsnull", null }, + { "throwsexception", null }, + }; + } + + + @Test(dataProvider = "badfactories", + expectedExceptions = ServiceConfigurationError.class) + public void testBadFactory(String testName, String ignore) throws Exception { + Path mods = compileTest(TEST1_MODULE); + + // compile the bad factory + Path source = BADFACTORIES_DIR.resolve(testName); + Path output = Files.createTempDirectory(USER_DIR, "tmp"); + boolean compiled = CompilerUtils.compile(source, output); + assertTrue(compiled); + + // copy the compiled class into the module + Path classFile = Paths.get("p", "ProviderFactory.class"); + Files.copy(output.resolve(classFile), + mods.resolve(TEST1_MODULE).resolve(classFile), + StandardCopyOption.REPLACE_EXISTING); + + // load providers and instantiate each one + loadProviders(mods, TEST1_MODULE).forEach(Provider::get); + } + + + @DataProvider(name = "badproviders") + public Object[][] createBadProviders() { + return new Object[][] { + { "notpublic", null }, + { "ctornotpublic", null }, + { "notasubtype", null }, + { "throwsexception", null } + }; + } + + + @Test(dataProvider = "badproviders", + expectedExceptions = ServiceConfigurationError.class) + public void testBadProvider(String testName, String ignore) throws Exception { + Path mods = compileTest(TEST2_MODULE); + + // compile the bad provider + Path source = BADPROVIDERS_DIR.resolve(testName); + Path output = Files.createTempDirectory(USER_DIR, "tmp"); + boolean compiled = CompilerUtils.compile(source, output); + assertTrue(compiled); + + // copy the compiled class into the module + Path classFile = Paths.get("p", "Provider.class"); + Files.copy(output.resolve(classFile), + mods.resolve(TEST2_MODULE).resolve(classFile), + StandardCopyOption.REPLACE_EXISTING); + + // load providers and instantiate each one + loadProviders(mods, TEST2_MODULE).forEach(Provider::get); + } + +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library modules + * @build bananascript/* + * @compile src/pearscript/org/pear/PearScriptEngineFactory.java + * src/pearscript/org/pear/PearScript.java + * @run testng/othervm Basic + * @summary Basic test for ServiceLoader with a provider deployed as a module. + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.*; +import java.util.ServiceLoader.Provider; +import java.util.stream.Collectors; +import javax.script.ScriptEngineFactory; + +import org.testng.annotations.Test; +import org.testng.annotations.BeforeTest; +import static org.testng.Assert.*; + +/** + * Basic test for ServiceLoader. The test make use of two service providers: + * 1. BananaScriptEngine - a ScriptEngineFactory deployed as a module on the + * module path. It implementations a singleton via the public static + * provider method. + * 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path + * with a service configuration file. + */ + +public class Basic { + + // Copy the services configuration file for "pearscript" into place. + @BeforeTest + public void setup() throws Exception { + Path src = Paths.get(System.getProperty("test.src", "")); + Path classes = Paths.get(System.getProperty("test.classes", "")); + String st = ScriptEngineFactory.class.getName(); + Path config = Paths.get("META-INF", "services", st); + Path source = src.resolve("src").resolve("pearscript").resolve(config); + Path target = classes.resolve(config); + Files.createDirectories(target.getParent()); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + } + + /** + * Basic test of iterator() to ensure that providers located as modules + * and on the class path are found. + */ + @Test + public void testIterator() { + ServiceLoader loader + = ServiceLoader.load(ScriptEngineFactory.class); + Set names = collectAll(loader) + .stream() + .map(ScriptEngineFactory::getEngineName) + .collect(Collectors.toSet()); + assertTrue(names.contains("BananaScriptEngine")); + assertTrue(names.contains("PearScriptEngine")); + } + + /** + * Basic test of iterator() to test iteration order. Providers deployed + * as named modules should be found before providers deployed on the class + * path. + */ + @Test + public void testIteratorOrder() { + ServiceLoader loader + = ServiceLoader.load(ScriptEngineFactory.class); + boolean foundUnnamed = false; + for (ScriptEngineFactory factory : collectAll(loader)) { + if (factory.getClass().getModule().isNamed()) { + if (foundUnnamed) { + assertTrue(false, "Named module element after unnamed"); + } + } else { + foundUnnamed = true; + } + } + } + + /** + * Basic test of Provider::type + */ + @Test + public void testProviderType() { + Set types = ServiceLoader.load(ScriptEngineFactory.class) + .stream() + .map(Provider::type) + .map(Class::getName) + .collect(Collectors.toSet()); + assertTrue(types.contains("org.banana.BananaScriptEngineFactory")); + assertTrue(types.contains("org.pear.PearScriptEngineFactory")); + } + + /** + * Basic test of Provider::get + */ + @Test + public void testProviderGet() { + Set names = ServiceLoader.load(ScriptEngineFactory.class) + .stream() + .map(Provider::get) + .map(ScriptEngineFactory::getEngineName) + .collect(Collectors.toSet()); + assertTrue(names.contains("BananaScriptEngine")); + assertTrue(names.contains("PearScriptEngine")); + } + + /** + * Basic test of the public static provider method. BananaScriptEngine + * defines a provider method that returns the same instance. + */ + @Test + public void testSingleton() { + Optional> oprovider + = ServiceLoader.load(ScriptEngineFactory.class) + .stream() + .filter(p -> p.type().getName().equals("org.banana.BananaScriptEngineFactory")) + .findFirst(); + assertTrue(oprovider.isPresent()); + Provider provider = oprovider.get(); + + // invoke Provider::get twice + ScriptEngineFactory factory1 = provider.get(); + ScriptEngineFactory factory2 = provider.get(); + assertTrue(factory1 == factory2); + } + + /** + * Basic test of stream() to ensure that elements for providers in named + * modules come before elements for providers in unnamed modules. + */ + @Test + public void testStreamOrder() { + List> types = ServiceLoader.load(ScriptEngineFactory.class) + .stream() + .map(Provider::type) + .collect(Collectors.toList()); + + boolean foundUnnamed = false; + for (Class factoryClass : types) { + if (factoryClass.getModule().isNamed()) { + if (foundUnnamed) { + assertTrue(false, "Named module element after unnamed"); + } + } else { + foundUnnamed = true; + } + } + } + + /** + * Basic test of ServiceLoader.findFirst() + */ + @Test + public void testFindFirst() { + Optional ofactory + = ServiceLoader.load(ScriptEngineFactory.class).findFirst(); + assertTrue(ofactory.isPresent()); + ScriptEngineFactory factory = ofactory.get(); + assertTrue(factory.getClass().getModule().isNamed()); + + class S { } + assertFalse(ServiceLoader.load(S.class).findFirst().isPresent()); + } + + /** + * Basic test ServiceLoader.load specifying the platform class loader. + * The providers on the module path and class path should not be located. + */ + @Test + public void testWithPlatformClassLoader() { + ClassLoader pcl = ClassLoader.getPlatformClassLoader(); + + // iterator + ServiceLoader loader + = ServiceLoader.load(ScriptEngineFactory.class, pcl); + Set names = collectAll(loader) + .stream() + .map(ScriptEngineFactory::getEngineName) + .collect(Collectors.toSet()); + assertFalse(names.contains("BananaScriptEngine")); + assertFalse(names.contains("PearScriptEngine")); + + // stream + names = ServiceLoader.load(ScriptEngineFactory.class, pcl) + .stream() + .map(Provider::get) + .map(ScriptEngineFactory::getEngineName) + .collect(Collectors.toSet()); + assertFalse(names.contains("BananaScriptEngine")); + assertFalse(names.contains("PearScriptEngine")); + } + + /** + * Basic test of ServiceLoader.load, using the class loader for + * a module in a custom layer as the context. + */ + @Test + public void testWithCustomLayer1() { + Layer layer = createCustomLayer("bananascript"); + + ClassLoader loader = layer.findLoader("bananascript"); + List providers + = collectAll(ServiceLoader.load(ScriptEngineFactory.class, loader)); + + // should have at least 2 x bananascript + pearscript + assertTrue(providers.size() >= 3); + + // first element should be the provider in the custom layer + ScriptEngineFactory factory = providers.get(0); + assertTrue(factory.getClass().getClassLoader() == loader); + assertTrue(factory.getClass().getModule().getLayer() == layer); + assertTrue(factory.getEngineName().equals("BananaScriptEngine")); + + // remainder should be the boot layer + providers.remove(0); + Set names = providers.stream() + .map(ScriptEngineFactory::getEngineName) + .collect(Collectors.toSet()); + assertTrue(names.contains("BananaScriptEngine")); + assertTrue(names.contains("PearScriptEngine")); + } + + /** + * Basic test of ServiceLoader.load using a custom Layer as the context. + */ + @Test + public void testWithCustomLayer2() { + Layer layer = createCustomLayer("bananascript"); + + List factories + = collectAll(ServiceLoader.load(layer, ScriptEngineFactory.class)); + + // should have at least 2 x bananascript + assertTrue(factories.size() >= 2); + + // first element should be the provider in the custom layer + ScriptEngineFactory factory = factories.get(0); + assertTrue(factory.getClass().getModule().getLayer() == layer); + assertTrue(factory.getEngineName().equals("BananaScriptEngine")); + + // remainder should be the boot layer + factories.remove(0); + Set names = factories.stream() + .map(ScriptEngineFactory::getEngineName) + .collect(Collectors.toSet()); + assertTrue(names.contains("BananaScriptEngine")); + assertFalse(names.contains("PearScriptEngine")); + } + + /** + * Basic test of ServiceLoader.load with a tree of layers. + * + * Test scenario: + * - boot layer contains "bananascript", maybe other script engines + * - layer1, with boot layer as parent, contains "bananascript" + * - layer2, with boot layer as parent, contains "bananascript" + * - layer3, with layer1 ad layer as parents, contains "bananascript" + * + * ServiceLoader should locate all 4 script engine factories in DFS order. + */ + @Test + public void testWithCustomLayer3() { + Layer bootLayer = Layer.boot(); + Configuration cf0 = bootLayer.configuration(); + + // boot layer should contain "bananascript" + List factories + = collectAll(ServiceLoader.load(bootLayer, ScriptEngineFactory.class)); + int countInBootLayer = factories.size(); + assertTrue(countInBootLayer >= 1); + assertTrue(factories.stream() + .map(p -> p.getEngineName()) + .filter("BananaScriptEngine"::equals) + .findAny() + .isPresent()); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Path dir = Paths.get(System.getProperty("test.classes", "."), "modules"); + ModuleFinder finder = ModuleFinder.of(dir); + + // layer1 + Configuration cf1 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); + Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl); + assertTrue(layer1.modules().size() == 1); + + // layer2 + Configuration cf2 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); + Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl); + assertTrue(layer2.modules().size() == 1); + + // layer3 with layer1 and layer2 as parents + Configuration cf3 = Configuration.resolveRequiresAndUses(finder, + List.of(cf1, cf2), + ModuleFinder.of(), + Set.of()); + Layer layer3 = Layer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer(); + assertTrue(layer3.modules().size() == 1); + + + // class loaders + ClassLoader loader1 = layer1.findLoader("bananascript"); + ClassLoader loader2 = layer2.findLoader("bananascript"); + ClassLoader loader3 = layer3.findLoader("bananascript"); + assertTrue(loader1 != loader2); + assertTrue(loader1 != loader3); + assertTrue(loader2 != loader3); + + // load all factories with layer3 as the context + factories = collectAll(ServiceLoader.load(layer3, ScriptEngineFactory.class)); + int count = factories.size(); + assertTrue(count == countInBootLayer + 3); + + // the ordering should be layer3, layer1, boot layer, layer2 + + ScriptEngineFactory factory = factories.get(0); + assertTrue(factory.getClass().getModule().getLayer() == layer3); + assertTrue(factory.getClass().getClassLoader() == loader3); + assertTrue(factory.getEngineName().equals("BananaScriptEngine")); + + factory = factories.get(1); + assertTrue(factory.getClass().getModule().getLayer() == layer1); + assertTrue(factory.getClass().getClassLoader() == loader1); + assertTrue(factory.getEngineName().equals("BananaScriptEngine")); + + // boot layer "bananascript" and maybe other factories + int last = count -1; + boolean found = false; + for (int i=2; i) null, ClassLoader.getSystemClassLoader()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testLoadNull3() { + class S { } + ServiceLoader.load((Layer) null, S.class); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testLoadNull4() { + ServiceLoader.load(Layer.empty(), null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testLoadNull5() { + ServiceLoader.loadInstalled(null); + } + + /** + * Create a custom Layer by resolving the given module names. The modules + * are located in the {@code ${test.classes}/modules} directory. + */ + private Layer createCustomLayer(String... modules) { + Path dir = Paths.get(System.getProperty("test.classes", "."), "modules"); + ModuleFinder finder = ModuleFinder.of(dir); + Set roots = new HashSet<>(); + Collections.addAll(roots, modules); + Layer bootLayer = Layer.boot(); + Configuration parent = bootLayer.configuration(); + Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), roots); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + assertTrue(layer.modules().size() == 1); + return layer; + } + + private List collectAll(ServiceLoader loader) { + List list = new ArrayList<>(); + Iterator iterator = loader.iterator(); + while (iterator.hasNext()) { + list.add(iterator.next()); + } + return list; + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/MiscTests.java --- a/jdk/test/java/util/ServiceLoader/modules/MiscTests.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.lang.reflect.Layer; -import java.security.Provider; -import java.util.ServiceLoader; - -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/* - * @test - * @run testng MiscTests - * @summary Basic test of ServiceLoader with modules - */ - -public class MiscTests { - - @Test - public void testEmptyLayer() { - ServiceLoader sl - = ServiceLoader.load(Layer.empty(), Provider.class); - assertFalse(sl.iterator().hasNext()); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testNullLayer() { - ServiceLoader.load(null, Provider.class); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testNullService() { - ServiceLoader.load(Layer.empty(), null); - } - -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/ServicesTest.java --- a/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.File; -import java.lang.module.Configuration; -import java.lang.module.ModuleFinder; -import java.lang.reflect.Layer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ServiceLoader; -import java.util.Set; -import javax.script.ScriptEngineFactory; - -import static jdk.testlibrary.ProcessTools.executeTestJava; - -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * @test - * @library /lib/testlibrary - * @modules java.scripting - * jdk.compiler - * @build ServicesTest CompilerUtils jdk.testlibrary.* - * @run testng ServicesTest - * @summary Tests ServiceLoader to locate service providers on the module path - * and class path. Also tests ServiceLoader with a custom Layer. - */ - -@Test -public class ServicesTest { - - private static final String TEST_SRC = System.getProperty("test.src"); - - private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); - private static final Path CLASSES_DIR = Paths.get("classes"); - private static final Path MODS_DIR = Paths.get("mods"); - - // modules to compile to the module path - private static final String MODULES[] = { "test", "bananascript" }; - - // directories of classes to compile to the class path - private static final String CLASSES[] = { "pearscript" }; - - // resources to copy to the class path - private static final String RESOURCES[] = { - "pearscript/META-INF/services/javax.script.ScriptEngineFactory" - }; - - - /** - * Compiles all modules and classes used by the test - */ - @BeforeTest - public void setup() throws Exception { - - // modules - for (String mn : MODULES ) { - Path src = SRC_DIR.resolve(mn); - Path mods = MODS_DIR.resolve(mn); - assertTrue(CompilerUtils.compile(src, mods)); - } - - // classes - for (String dir : CLASSES) { - Path src = SRC_DIR.resolve(dir); - assertTrue(CompilerUtils.compile(src, CLASSES_DIR)); - } - - // copy resources - for (String rn : RESOURCES) { - Path file = Paths.get(rn.replace('/', File.separatorChar)); - Path source = SRC_DIR.resolve(file); - - // drop directory to get a target of classes/META-INF/... - Path target = CLASSES_DIR.resolve(file.subpath(1, file.getNameCount())); - - Files.createDirectories(target.getParent()); - Files.copy(source, target); - } - - } - - - /** - * Run test with --module-path. - * - * BananaScriptEngine should be found. - */ - public void runWithModulePath() throws Exception { - int exitValue - = executeTestJava("--module-path", MODS_DIR.toString(), - "--add-modules", "bananascript", - "-m", "test/test.Main", - "BananaScriptEngine") - .outputTo(System.out) - .errorTo(System.out) - .getExitValue(); - - assertTrue(exitValue == 0); - } - - - /** - * Run test with --module-path and -classpath. - * - * Both BananaScriptEngine and PearScriptEngine should be found - */ - public void runWithModulePathAndClassPath() throws Exception { - int exitValue - = executeTestJava("--module-path", MODS_DIR.toString(), - "-cp", CLASSES_DIR.toString(), - "--add-modules", "bananascript", - "-m", "test/test.Main", - "BananaScriptEngine", "PearScriptEngine") - .outputTo(System.out) - .errorTo(System.out) - .getExitValue(); - - assertTrue(exitValue == 0); - } - - - /** - * Exercise ServiceLoader.load(Layer, Class). - */ - public void testWithCustomLayer() throws Exception { - - ServiceLoader sl; - - // BananaScriptEngine should not be in the boot Layer - sl = ServiceLoader.load(Layer.boot(), ScriptEngineFactory.class); - assertTrue(find("BananaScriptEngine", sl) == null); - - // create a custom Layer - ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Layer bootLayer = Layer.boot(); - Configuration parent = bootLayer.configuration(); - Configuration cf - = parent.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); - ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); - - assertTrue(layer.findModule("bananascript").isPresent()); - ClassLoader loader = layer.findLoader("bananascript"); - - sl = ServiceLoader.load(layer, ScriptEngineFactory.class); - ScriptEngineFactory factory = find("BananaScriptEngine", sl); - assertTrue(factory != null); - assertEquals(factory.getClass().getModule().getName(), "bananascript"); - assertTrue(factory.getClass().getClassLoader() == loader); - - } - - /** - * Find the given scripting engine (by name) via the ScriptEngineFactory - * that ServiceLoader has found. - */ - static ScriptEngineFactory find(String name, - ServiceLoader sl) { - for (ScriptEngineFactory factory : sl) { - if (factory.getEngineName().equals(name)) - return factory; - } - return null; - } - - -} - diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * A provider factory with a provider() method with a return type that is not + * p.Service + */ + +public class ProviderFactory { + ProviderFactory() { } + + public static Object provider() { + throw new RuntimeException("Should not be called"); + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Not a provider factory because the class is not public. + */ + +class ProviderFactory { + ProviderFactory() { } + + public static Service provider() { + throw new RuntimeException("Should not be called"); + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Not a provider factory because the static provider() method is not public. + */ + +public class ProviderFactory { + ProviderFactory() { } + + static Service provider() { + throw new RuntimeException("Should not be called"); + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * A provider factory that defines a public static provider method that returns + * null. + */ + +public class ProviderFactory { + ProviderFactory() { } + + public static Service provider() { + return null; + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * A provider factory that throws an exception. + */ + +public class ProviderFactory { + ProviderFactory() { } + + public static Service provider() { + throw new RuntimeException(); + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * A provider class with a non-public constructor + */ + +public class Provider implements Service { + Provider() { } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * A provider class that is not a subtype of Service. + */ + +public class Provider { + Provider() { } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Provider class not public. + */ + +class Provider implements Service { + public Provider() { } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * A provider class with a constructor throws an exception. + */ + +public class Provider { + public Provider() { + throw new RuntimeException(); + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module bananascript { + requires java.scripting; + + provides javax.script.ScriptEngineFactory + with org.banana.BananaScriptEngineFactory; +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScript.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScript.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.banana; + +import java.io.Reader; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class BananaScript implements ScriptEngine { + + @Override + public Object eval(String script, ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script, Bindings n) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , Bindings n) { + throw new RuntimeException(); + } + @Override + public void put(String key, Object value) { + throw new RuntimeException(); + } + + @Override + public Object get(String key) { + throw new RuntimeException(); + } + + @Override + public Bindings getBindings(int scope) { + throw new RuntimeException(); + } + + @Override + public void setBindings(Bindings bindings, int scope) { + throw new RuntimeException(); + } + + @Override + public Bindings createBindings() { + throw new RuntimeException(); + } + + @Override + public ScriptContext getContext() { + throw new RuntimeException(); + } + + @Override + public void setContext(ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public ScriptEngineFactory getFactory() { + throw new RuntimeException(); + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.banana; + +import java.util.Arrays; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class BananaScriptEngineFactory implements ScriptEngineFactory { + + static final BananaScriptEngineFactory INSTANCE = new BananaScriptEngineFactory(null); + + public BananaScriptEngineFactory() { + throw new RuntimeException("Should not be called"); + } + + private BananaScriptEngineFactory(Void param) { } + + public static BananaScriptEngineFactory provider() { + return INSTANCE; + } + + @Override + public String getEngineName() { + return "BananaScriptEngine"; + } + + @Override + public String getEngineVersion() { + return "1.0"; + } + + @Override + public List getExtensions() { + return Arrays.asList("banana"); + } + + @Override + public List getMimeTypes() { + return Arrays.asList("application/x-bananascript"); + } + + @Override + public List getNames() { + return Arrays.asList("BananaScript"); + } + + @Override + public String getLanguageName() { + return "BananaScript"; + } + + @Override + public String getLanguageVersion() { + return "1.0"; + } + + @Override + public Object getParameter(String key) { + return null; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + throw new RuntimeException(); + } + + @Override + public String getOutputStatement(String toDisplay) { + throw new RuntimeException(); + } + + @Override + public String getProgram(String... statements) { + throw new RuntimeException(); + } + + @Override + public ScriptEngine getScriptEngine() { + return new BananaScript(); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Test module that provides an implementation of p.Service via a + * provider factory class. + */ + +module test1 { + exports p; + provides p.Service with p.ProviderFactory; +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Provider factory + */ +public class ProviderFactory { + ProviderFactory() { } + + private static final Service INSTANCE = new Service() { }; + + public static Service provider() { + return INSTANCE; + } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Service type + */ +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Test module that provides an implementation of p.Service. + */ + +module test2 { + exports p; + provides p.Service with p.Provider; +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Provider type + */ +public class Provider implements Service { + public Provider() { } +} + diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +/** + * Service type + */ +public interface Service { } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java --- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module bananascript { - requires java.scripting; - - provides javax.script.ScriptEngineFactory - with org.banana.BananaScriptEngineFactory; -} - diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java --- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.banana; - -import java.io.Reader; -import javax.script.Bindings; -import javax.script.ScriptContext; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; - -public class BananaScript implements ScriptEngine { - - @Override - public Object eval(String script, ScriptContext context) { - throw new RuntimeException(); - } - - @Override - public Object eval(Reader reader , ScriptContext context) { - throw new RuntimeException(); - } - - @Override - public Object eval(String script) { - throw new RuntimeException(); - } - - @Override - public Object eval(Reader reader) { - throw new RuntimeException(); - } - - @Override - public Object eval(String script, Bindings n) { - throw new RuntimeException(); - } - - @Override - public Object eval(Reader reader , Bindings n) { - throw new RuntimeException(); - } - @Override - public void put(String key, Object value) { - throw new RuntimeException(); - } - - @Override - public Object get(String key) { - throw new RuntimeException(); - } - - @Override - public Bindings getBindings(int scope) { - throw new RuntimeException(); - } - - @Override - public void setBindings(Bindings bindings, int scope) { - throw new RuntimeException(); - } - - @Override - public Bindings createBindings() { - throw new RuntimeException(); - } - - @Override - public ScriptContext getContext() { - throw new RuntimeException(); - } - - @Override - public void setContext(ScriptContext context) { - throw new RuntimeException(); - } - - @Override - public ScriptEngineFactory getFactory() { - throw new RuntimeException(); - } -} - diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java --- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package org.banana; - -import java.util.Arrays; -import java.util.List; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineFactory; - -public class BananaScriptEngineFactory implements ScriptEngineFactory { - - @Override - public String getEngineName() { - return "BananaScriptEngine"; - } - - @Override - public String getEngineVersion() { - return "1.0"; - } - - @Override - public List getExtensions() { - return Arrays.asList("banana"); - } - - @Override - public List getMimeTypes() { - return Arrays.asList("application/x-bananascript"); - } - - @Override - public List getNames() { - return Arrays.asList("BananaScript"); - } - - @Override - public String getLanguageName() { - return "BananaScript"; - } - - @Override - public String getLanguageVersion() { - return "1.0"; - } - - @Override - public Object getParameter(String key) { - return null; - } - - @Override - public String getMethodCallSyntax(String obj, String m, String... args) { - throw new RuntimeException(); - } - - @Override - public String getOutputStatement(String toDisplay) { - throw new RuntimeException(); - } - - @Override - public String getProgram(String... statements) { - throw new RuntimeException(); - } - - @Override - public ScriptEngine getScriptEngine() { - return new BananaScript(); - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java --- a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,12 @@ public class PearScriptEngineFactory implements ScriptEngineFactory { + public PearScriptEngineFactory() { } + + public static PearScriptEngineFactory provider() { + throw new RuntimeException("Should not be called"); + } + @Override public String getEngineName() { return "PearScriptEngine"; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java --- a/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module test { - requires java.scripting; - - uses javax.script.ScriptEngineFactory; -} - diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java --- a/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package test; - -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; -import javax.script.ScriptEngineFactory; - -public class Main { - public static void main(String[] args) { - Set engines = new HashSet<>(); - for (ScriptEngineFactory factory: ServiceLoader.load(ScriptEngineFactory.class)) { - System.out.format("loaded: %s%n" , factory.getEngineName()); - engines.add(factory.getEngineName()); - } - - for (String engine: args) { - if (!engines.contains(engine)) - throw new RuntimeException(engine + " not found"); - } - } -} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java --- a/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java Thu Dec 01 08:57:53 2016 +0000 @@ -49,6 +49,7 @@ /* * @test * @bug 7014263 + * @modules java.base/java.util.concurrent:open * @summary White box testing of ArrayBlockingQueue iterators. */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/BlockingQueue/LastElement.java --- a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,6 +24,7 @@ /* * @test * @bug 6215625 7161229 + * @modules java.base/java.util.concurrent:open * @summary Check correct behavior when last element is removed. * @author Martin Buchholz */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java --- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java Thu Dec 01 08:57:53 2016 +0000 @@ -35,6 +35,8 @@ /* * @test * @bug 6236036 6264015 + * @modules java.base/java.util.concurrent:open + * java.base/java.util.concurrent.locks:open * @summary Checks for a memory leak when a sequence of aborted timed * waits occur without a signal. Uses the strategy of detecting * changes in the size of the object graph retained by a root object. diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java --- a/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,6 +34,8 @@ /* * @test * @bug 8054446 8137184 8137185 + * @modules java.base/java.util.concurrent:open + * java.base/java.util.concurrent.locks:open * @summary Regression test for memory leak in remove(Object) */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java --- a/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,6 +34,7 @@ /* * @test + * @modules java.base/java.util.concurrent:open * @summary Test Phaser phase integer overflow behavior */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java --- a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java Thu Dec 01 08:57:53 2016 +0000 @@ -36,6 +36,7 @@ * @bug 8022642 8065320 8129861 * @summary Ensure relative sanity when zero core threads * @library /lib/testlibrary/ + * @modules java.base/java.util.concurrent:open */ import static java.util.concurrent.TimeUnit.HOURS; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java --- a/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,6 +24,7 @@ /* * @test * @bug 4992443 4994819 + * @modules java.base/java.util.concurrent.atomic:open * @run main VMSupportsCS8 * @summary Checks that the value of VMSupportsCS8 matches system properties. */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java --- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java Thu Dec 01 08:57:53 2016 +0000 @@ -35,6 +35,7 @@ /* * @test * @bug 8004138 + * @modules java.base/java.util.concurrent:open * @summary Checks that ForkJoinTask thrown exceptions are not leaked. * This whitebox test is sensitive to forkjoin implementation details. */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/concurrent/tck/JSR166TestCase.java --- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java Thu Dec 01 08:57:53 2016 +0000 @@ -36,7 +36,8 @@ /* * @test * @summary JSR-166 tck tests - * @modules java.management + * @modules java.base/java.util.concurrent:open + * java.management * @build * * @run junit/othervm/timeout=1000 -Djsr166.testImplementationDetails=true JSR166TestCase * @run junit/othervm/timeout=1000 -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 -Djsr166.testImplementationDetails=true JSR166TestCase diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/logging/FileHandlerLongLimit.java --- a/jdk/test/java/util/logging/FileHandlerLongLimit.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/logging/FileHandlerLongLimit.java Thu Dec 01 08:57:53 2016 +0000 @@ -52,6 +52,7 @@ * @test * @bug 8059767 * @summary tests that FileHandler can accept a long limit. + * @modules java.logging/java.util.logging:open * @run main/othervm FileHandlerLongLimit UNSECURE * @run main/othervm FileHandlerLongLimit SECURE * @author danielfuchs diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/logging/HandlersConfigTest.java --- a/jdk/test/java/util/logging/HandlersConfigTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/logging/HandlersConfigTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,7 @@ * configured correctly from defaults and/or LogManager properties * as specified in javadoc and that no special * logging permission is required for instantiating them. + * @modules java.logging/java.util.logging:open * @run main/othervm HandlersConfigTest default * @run main/othervm HandlersConfigTest configured */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/logging/LocalizedLevelName.java --- a/jdk/test/java/util/logging/LocalizedLevelName.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/logging/LocalizedLevelName.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ * @test * @bug 8016127 8024131 * @summary test logging.properties localized + * @modules java.logging/sun.util.logging.resources:open * @run main/othervm LocalizedLevelName */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java --- a/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -61,6 +61,7 @@ * @test * @bug 8033661 * @summary tests LogManager.updateConfiguration(bin) + * @modules java.logging/java.util.logging:open * @run main/othervm UpdateConfigurationTest UNSECURE * @run main/othervm UpdateConfigurationTest SECURE * @author danielfuchs diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java --- a/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -136,10 +136,6 @@ // class resource bundle in another named module m1. failToLoadResourceBundle("mylogger.g", "p1.resource.ClassResource", true, NAMED_NEGATIVE_CLASSBUNDLE_MSG); - // in named module m2, try to create a logger with - // class resource bundle in an unnamed module. - failToLoadResourceBundle("mylogger.h", "p3.resource.ClassResource", - true, NAMED_NEGATIVE_CLASSBUNDLE_MSG); } static void failToLoadPropertyRBs() { @@ -153,10 +149,6 @@ // property resource bundle in another named module m1. failToLoadResourceBundle("mylogger.k", "p1.resource.p", true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG); - // in named module m2, try to create a logger with - // property resource bundle in an unnamed module. - failToLoadResourceBundle("mylogger.l", "p3.resource.p", - true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG); } static void failToLoadResourceBundle(String loggerName, String rbName, diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/ObjectName/CompressedStorageTest.java --- a/jdk/test/javax/management/ObjectName/CompressedStorageTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/ObjectName/CompressedStorageTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,7 @@ * @summary Tests the limits imposed on the domain name part of an * ObjectName instance * @author Jaroslav Bachorik - * @modules java.management + * @modules java.management/javax.management:open * @run main CompressedStorageTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/loading/MLetInternalsTest.java --- a/jdk/test/javax/management/loading/MLetInternalsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/loading/MLetInternalsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -36,7 +36,7 @@ * @bug 8058089 * @summary Tests various internal functions provided by MLet for correctness * @author Jaroslav Bachorik - * @modules java.management + * @modules java.management/javax.management.loading:open * @run testng MLetInternalsTest */ public class MLetInternalsTest { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/openmbean/TabularDataOrderTest.java --- a/jdk/test/javax/management/openmbean/TabularDataOrderTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/openmbean/TabularDataOrderTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,7 @@ * @bug 6334663 * @summary Test that TabularDataSupport preserves the order elements were added * @author Eamonn McManus - * @modules java.management + * @modules java.management/javax.management.openmbean:open */ import java.io.ByteArrayInputStream; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java --- a/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,7 +29,7 @@ * thrown when constructor is invoked with null class loader as * an argument. * @author Amit Sapre - * @modules java.management + * @modules java.management/javax.management.remote.rmi:open * @run clean ObjectInputStreamWithLoaderNullCheckTest * @run build ObjectInputStreamWithLoaderNullCheckTest * @run main ObjectInputStreamWithLoaderNullCheckTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java --- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -42,7 +42,7 @@ * @bug 6566891 * @summary Check no memory leak on RMIConnector's rmbscMap * @author Shanliang JIANG - * @modules java.management + * @modules java.management/javax.management.remote.rmi:open * @run clean RMIConnectorInternalMapTest * @run build RMIConnectorInternalMapTest * @run main RMIConnectorInternalMapTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java --- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -38,7 +38,7 @@ * @bug 6566891 * @summary Check no memory leak on RMIConnector's nullSubjectConn * @author Shanliang JIANG - * @modules java.management + * @modules java.management/javax.management.remote.rmi:open * @run clean RMIConnectorNullSubjectConnTest * @run build RMIConnectorNullSubjectConnTest * @run main RMIConnectorNullSubjectConnTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java --- a/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,8 @@ * @test * @bug 6957378 * @summary Test that a listener can be removed remotely from an MBean that no longer exists. - * @modules java.management/com.sun.jmx.remote.internal + * @modules java.management/javax.management.remote.rmi:open + * java.management/com.sun.jmx.remote.internal:+open * @author Eamonn McManus * @run main/othervm -XX:+UsePerfData DeadListenerTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,8 +30,8 @@ * @modules java.security.jgss * jdk.security.auth * java.base/sun.security.util - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,10 +27,10 @@ * @summary Testing DTLS engines do not enable RC4 ciphers by default. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS DTLSNotEnabledRC4Test diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @key randomness * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java --- a/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,10 +28,10 @@ * causes IllegalArgumentException. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS DTLSUnsupportedCiphersTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLS/TEST.properties --- a/jdk/test/javax/net/ssl/DTLS/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLS/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -1,7 +1,7 @@ modules = \ - java.security.jgss/sun.security.krb5 \ + java.security.jgss/sun.security.krb5:+open \ java.security.jgss/sun.security.krb5.internal.crypto \ java.security.jgss/sun.security.krb5.internal.ccache \ - java.security.jgss/sun.security.krb5.internal \ + java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ktab \ java.base/sun.security.util diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,10 +27,10 @@ * @summary Testing DTLS engines do not enable RC4 ciphers by default. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 DTLSv10NotEnabledRC4Test diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @key randomness * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,10 +28,10 @@ * causes IllegalArgumentException. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/DTLSv10/TEST.properties --- a/jdk/test/javax/net/ssl/DTLSv10/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/DTLSv10/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -1,7 +1,7 @@ modules = \ - java.security.jgss/sun.security.krb5 \ + java.security.jgss/sun.security.krb5:+open \ java.security.jgss/sun.security.krb5.internal.crypto \ java.security.jgss/sun.security.krb5.internal.ccache \ - java.security.jgss/sun.security.krb5.internal \ + java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ktab \ java.base/sun.security.util diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TEST.properties --- a/jdk/test/javax/net/ssl/TLS/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -1,8 +1,8 @@ modules = \ + java.security.jgss/sun.security.krb5:+open \ java.security.jgss/sun.security.krb5.internal.crypto \ java.security.jgss/sun.security.krb5.internal.ktab \ - java.security.jgss/sun.security.krb5 \ java.security.jgss/sun.security.krb5.internal.ccache \ - java.security.jgss/sun.security.krb5.internal \ + java.security.jgss/sun.security.krb5.internal:+open \ java.base/sun.security.util \ jdk.crypto.ec/sun.security.ec diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,11 +28,11 @@ * @summary javax/net/ssl/TLS/TLSClientPropertyTest.java needs to be * updated for JDK-8061210 * @modules java.security.jgss + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm TLSClientPropertyTest NoProperty * @run main/othervm TLSClientPropertyTest SSLv3 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,11 +29,11 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSDataExchangeTest * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSDataExchangeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,11 +29,11 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSEnginesClosureTest * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSEnginesClosureTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,11 +29,11 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSHandshakeTest * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSHandshakeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,11 +30,11 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSMFLNTest * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSMFLNTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java --- a/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,11 +27,11 @@ * @summary Testing TLS engines do not enable RC4 ciphers by default. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS TLSNotEnabledRC4Test */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,11 +29,11 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeTest * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,11 +29,11 @@ * @key randomness * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS TLSRehandshakeWithCipherChangeTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,11 +30,11 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeWithDataExTest * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeWithDataExTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java --- a/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,11 +28,11 @@ * causes IllegalArgumentException. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLS TLSUnsupportedCiphersTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TEST.properties --- a/jdk/test/javax/net/ssl/TLSv1/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -1,7 +1,7 @@ modules = \ - java.security.jgss/sun.security.krb5 \ + java.security.jgss/sun.security.krb5:+open \ java.security.jgss/sun.security.krb5.internal.crypto \ java.security.jgss/sun.security.krb5.internal.ccache \ - java.security.jgss/sun.security.krb5.internal \ + java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ktab \ java.base/sun.security.util diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSDataExchangeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSEnginesClosureTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSHandshakeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSMFLNTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,10 +27,10 @@ * @summary Testing TLS engines do not enable RC4 ciphers by default. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 TLSNotEnabledRC4Test diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @key randomness * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 TLSRehandshakeWithCipherChangeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeWithDataExTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java --- a/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,10 +28,10 @@ * causes IllegalArgumentException. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 TLSUnsupportedCiphersTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java --- a/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,10 +34,10 @@ * @summary Support TLS 1.1 * @run main/othervm EmptyCertificateAuthorities * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @author Xuelei Fan diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java --- a/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,10 +34,10 @@ * @summary Support TLS 1.1 * @run main/othervm ExportableBlockCipher * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @author Xuelei Fan diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java --- a/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java Thu Dec 01 08:57:53 2016 +0000 @@ -33,10 +33,10 @@ * @bug 4873188 * @summary Support TLS 1.1 * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm ExportableStreamCipher diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java --- a/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,10 +28,10 @@ * @bug 4873188 * @summary Support TLS 1.1 * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm GenericBlockCipher diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java --- a/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,10 +28,10 @@ * @bug 4873188 * @summary Support TLS 1.1 * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm GenericStreamCipher diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TEST.properties --- a/jdk/test/javax/net/ssl/TLSv11/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -1,7 +1,7 @@ modules = \ - java.security.jgss/sun.security.krb5 \ + java.security.jgss/sun.security.krb5:+open \ java.security.jgss/sun.security.krb5.internal.crypto \ java.security.jgss/sun.security.krb5.internal.ccache \ - java.security.jgss/sun.security.krb5.internal \ + java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ktab \ java.base/sun.security.util diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSDataExchangeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSEnginesClosureTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSHandshakeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSMFLNTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,10 +27,10 @@ * @summary Testing TLS engines do not enable RC4 ciphers by default. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSNotEnabledRC4Test diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,10 +29,10 @@ * @key randomness * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSRehandshakeWithCipherChangeTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,10 +30,10 @@ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss * jdk.security.auth - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeWithDataExTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java --- a/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,10 +28,10 @@ * causes IllegalArgumentException. * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon * @modules java.security.jgss - * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open + * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.ccache - * java.security.jgss/sun.security.krb5.internal * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSUnsupportedCiphersTest diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java --- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,7 +23,7 @@ /* @test @summary Test SoftSynthesizer implicit open/close using getReceiver. - @modules java.desktop/com.sun.media.sound + @modules java.desktop/com.sun.media.sound:+open */ import java.lang.reflect.Field; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java --- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,7 +23,7 @@ /* @test @summary Test SoftSynthesizer open method - @modules java.desktop/com.sun.media.sound + @modules java.desktop/com.sun.media.sound:+open */ import java.lang.reflect.Field; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java --- a/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,6 +25,7 @@ @bug 6688203 @summary Memory leak and performance problems in the method getFileSystemView of FileSystemView @author Pavel Porvatov + @modules java.desktop/javax.swing.filechooser:open @run main bug6688203 */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JLabel/7004134/bug7004134.java --- a/jdk/test/javax/swing/JLabel/7004134/bug7004134.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JLabel/7004134/bug7004134.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,7 @@ * @summary JLabel containing a ToolTipText does no longer show ToolTip after browser refresh * @author Pavel Porvatov * @modules java.desktop/sun.awt + * @modules java.desktop/javax.swing:open */ import sun.awt.SunToolkit; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java --- a/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,6 +30,7 @@ * @author Sergey Malenkov * @library ../.. * @modules java.desktop/sun.awt + * @modules java.desktop/javax.swing.plaf.basic:open */ import sun.awt.AppContext; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java --- a/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,7 @@ * @bug 6800513 * @summary GTK-LaF renders menus incompletely * @author Mario Torre + * @modules java.desktop/javax.swing:open * @library ../../regtesthelpers/ * @build Util * @run main bug6800513 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JSlider/6794836/bug6794836.java --- a/jdk/test/javax/swing/JSlider/6794836/bug6794836.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JSlider/6794836/bug6794836.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,7 @@ * @bug 6794836 * @summary BasicSliderUI throws NullPointerExc when JSlider maximum is Integer.MAX_VALUE * @author Pavel Porvatov + * @modules java.desktop/javax.swing.plaf.basic:open * @run main bug6794836 */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JSlider/6848475/bug6848475.java --- a/jdk/test/javax/swing/JSlider/6848475/bug6848475.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JSlider/6848475/bug6848475.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,7 @@ * @bug 6848475 * @summary JSlider does not display the correct value of its BoundedRangeModel * @author Pavel Porvatov + * @modules java.desktop/javax.swing.plaf.basic:open * @run main bug6848475 */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java --- a/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java Thu Dec 01 08:57:53 2016 +0000 @@ -29,6 +29,7 @@ /* @test @bug 7010561 @summary Tab text position with Synth based LaF is different to Java 5/6 + @modules java.desktop/javax.swing.plaf.basic:open @author Pavel Porvatov */ public class bug7010561 { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/JTree/6263446/bug6263446.java --- a/jdk/test/javax/swing/JTree/6263446/bug6263446.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/JTree/6263446/bug6263446.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,7 @@ * @bug 6263446 * @summary Tests that double-clicking to edit a cell doesn't select the content. * @author Shannon Hickey + * @modules java.desktop/javax.swing.tree:open * @run main bug6263446 */ import java.awt.*; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java --- a/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,6 +24,7 @@ /* @test @bug 7013453 @summary BufferStrategyPaintManager.dispose will cause IllegalMonitorStateException in event thread + @modules java.desktop/javax.swing:open @author Pavel Porvatov */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/Security/6938813/bug6938813.java --- a/jdk/test/javax/swing/Security/6938813/bug6938813.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/Security/6938813/bug6938813.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,7 @@ * @bug 6938813 * @summary Swing mutable statics * @author Pavel Porvatov + * @modules java.desktop/javax.swing.text.html.parser:open * @modules java.desktop/sun.awt */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/border/Test7149090.java --- a/jdk/test/javax/swing/border/Test7149090.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/border/Test7149090.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,6 +24,7 @@ /* @test @bug 7149090 @summary Nimbus:BorderFactory.createTitledBorder() the DEFAULT position of a title is not the same as the TOP + @modules java.desktop/javax.swing.border:open @author Pavel Porvatov */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java --- a/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,7 @@ * @bug 7143614 * @summary Issues with Synth Look&Feel * @author Pavel Porvatov + * @modules java.desktop/javax.swing.plaf.synth:open * @modules java.desktop/sun.awt */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/swing/text/View/8014863/bug8014863.java --- a/jdk/test/javax/swing/text/View/8014863/bug8014863.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/swing/text/View/8014863/bug8014863.java Thu Dec 01 08:57:53 2016 +0000 @@ -28,6 +28,7 @@ * @bug 8024395 * @summary Tests the calculation of the line breaks when a text is inserted * @author Dmitry Markov + * @modules java.desktop/javax.swing.text:open * @library ../../../regtesthelpers * @build Util * @run main bug8014863 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java --- a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java Thu Dec 01 08:57:53 2016 +0000 @@ -30,7 +30,7 @@ * correctly maps them to their preferred mime names. * Also checks that the Encodings.properties resource file * is consistent. - * @modules java.xml/com.sun.org.apache.xml.internal.serializer + * @modules java.xml/com.sun.org.apache.xml.internal.serializer:+open * @compile -XDignore.symbol.file CheckEncodingPropertiesFile.java * @run main CheckEncodingPropertiesFile * @author Daniel Fuchs diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java --- a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java Thu Dec 01 08:57:53 2016 +0000 @@ -31,7 +31,7 @@ * in com.sun.org.apache.xerces.internal.impl.dv.xs.PrecisionDecimalDV$XPrecisionDecimal. * Since that method is private the test unfortunately needs to use reflection * to invoke the method. - * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs + * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs:open * @run main XPrecisionDecimalToString * @author Daniel Fuchs */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/internal/jline/console/StripAnsiTest.java --- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,7 @@ * @test * @bug 8080679 8131913 * @modules jdk.internal.le/jdk.internal.jline - * jdk.internal.le/jdk.internal.jline.console + * jdk.internal.le/jdk.internal.jline.console:+open * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly. */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java --- a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,7 +22,6 @@ */ import jdk.internal.misc.Unsafe; -import java.lang.reflect.Field; /** * Helper class to support testing of Unsafe.copyMemory and Unsafe.copySwapMemory @@ -37,17 +36,7 @@ static final int SMALL_COPY_SIZE = 32; static final int BASE_ALIGNMENT = 16; - protected static final Unsafe UNSAFE; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } + protected static final Unsafe UNSAFE = Unsafe.getUnsafe(); static long alignDown(long value, long alignment) { return value & ~(alignment - 1); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java --- a/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java Thu Dec 01 08:57:53 2016 +0000 @@ -152,6 +152,9 @@ try { ClassFileReader reader = ClassFileReader.newInstance(path); for (ClassFile cf : reader.getClassFiles()) { + if (cf.access_flags.is(AccessFlags.ACC_MODULE)) + continue; + String classFileName = cf.getName(); // for each ClassFile // parse constant pool to find matching method refs diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/etc/VerifyModuleDelegation.java --- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java Thu Dec 01 08:57:53 2016 +0000 @@ -50,15 +50,15 @@ private static final String JAVA_COMPACT2 = "java.compact2"; private static final ModuleDescriptor BASE - = new ModuleDescriptor.Builder(JAVA_BASE).build(); + = ModuleDescriptor.module(JAVA_BASE).build(); private static final ModuleDescriptor COMPACT2 - = new ModuleDescriptor.Builder(JAVA_COMPACT2) + = ModuleDescriptor.module(JAVA_COMPACT2) .requires(Set.of(MANDATED), JAVA_BASE) - .requires(Set.of(PUBLIC), JAVA_COMPACT1) - .requires(Set.of(PUBLIC), "java.rmi") - .requires(Set.of(PUBLIC), "java.sql") - .requires(Set.of(PUBLIC), "java.xml") + .requires(Set.of(TRANSITIVE), JAVA_COMPACT1) + .requires(Set.of(TRANSITIVE), "java.rmi") + .requires(Set.of(TRANSITIVE), "java.sql") + .requires(Set.of(TRANSITIVE), "java.xml") .build(); private static final Set MREFS diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library modules + * @build m1/* m2/* + * @run testng/othervm --add-modules=m1,m2 Basic + * @summary Basic test of open modules and open packages + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Constructor; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.Module; + +import org.testng.annotations.Test; +import org.testng.annotations.BeforeTest; +import static org.testng.Assert.*; + +/** + * open module m1 { + * exports p; + * // contains p.internal + * } + * + * module m2 { + * exports q; + * exports q; + * // contains q.internal + * } + * + * Each package in m1 and m2 contains a public type a non-public type. + */ + +public class Basic { + + @BeforeTest + public void checkSetup() throws Exception { + Module m1 = Class.forName("p.PublicType").getModule(); + assertTrue(m1.isNamed()); + assertTrue(m1.getDescriptor().isOpen()); + assertTrue(m1.getDescriptor().packages().size() == 2); + assertTrue(m1.getDescriptor().packages().contains("p")); + assertTrue(m1.getDescriptor().packages().contains("p.internal")); + assertTrue(m1.getDescriptor().exports().size() == 1); + ModuleDescriptor.Exports e = m1.getDescriptor().exports().iterator().next(); + assertTrue(e.source().equals("p")); + assertTrue(m1.isOpen("p")); + assertTrue(m1.isOpen("p.internal")); + + Module m2 = Class.forName("q.PublicType").getModule(); + assertTrue(m2.isNamed()); + assertFalse(m2.getDescriptor().isOpen()); + assertTrue(m2.getDescriptor().packages().size() == 2); + assertTrue(m2.getDescriptor().packages().contains("q")); + assertTrue(m2.getDescriptor().packages().contains("q.internal")); + assertTrue(m2.getDescriptor().exports().size() == 1); + e = m2.getDescriptor().exports().iterator().next(); + assertTrue(e.source().equals("q")); + assertTrue(m2.isOpen("q")); + assertFalse(m2.isOpen("p.internal")); + } + + @Test + public void testPublicTypeInExportedPackage() throws Throwable { + // invokespecial + new p.PublicType(); + + Class clazz = p.PublicType.class; + + // core reflection + Constructor ctor = clazz.getConstructor(); + ctor.newInstance(); + ctor.setAccessible(true); + ctor.newInstance(); + + // method handles + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + findNoArgConstructorAndInvoke(clazz, lookup); + } + + @Test + public void testNotPublicTypeInExportedPackage() throws Throwable { + Class clazz = Class.forName("p.NotPublicType"); + + // core reflection + Constructor ctor = clazz.getConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + ctor.setAccessible(true); + ctor.newInstance(); + + // method handles + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + findNoArgConstructorAndInvoke(clazz, lookup); + } + + @Test + public void testPublicTypeInNonExportedPackage() throws Throwable { + Class clazz = Class.forName("p.internal.PublicType"); + + // core reflection + Constructor ctor = clazz.getConstructor(); + ctor.newInstance(); // should succeed + ctor.setAccessible(true); + ctor.newInstance(); + + // method handles + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + findNoArgConstructorAndInvoke(clazz, lookup); + } + + @Test + public void testNotPublicTypeInNonExportedPackage() throws Throwable { + Class clazz = Class.forName("p.internal.NotPublicType"); + + // core reflection + Constructor ctor = clazz.getConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + ctor.setAccessible(true); + ctor.newInstance(); + + // method handles + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + findNoArgConstructorAndInvoke(clazz, lookup); + } + + @Test + public void testPublicTypeInOpenPackage() throws Throwable { + // invokespecial + // new q.PublicType(); TBD + + // core reflection + Class clazz = q.PublicType.class; + clazz.getConstructor().newInstance(); + + // method handles + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + findNoArgConstructorAndInvoke(clazz, lookup); + + } + + @Test + public void testNotPublicTypeInOpenPackage() throws Throwable { + Class clazz = Class.forName("q.NotPublicType"); + + // core reflection + Constructor ctor = clazz.getConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + ctor.setAccessible(true); + ctor.newInstance(); + + // method handles + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + } catch (IllegalAccessException expected) { } + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + findNoArgConstructorAndInvoke(clazz, lookup); + } + + @Test + public void testPublicTypeInConcealedPackage() throws Throwable { + Class clazz = Class.forName("q.internal.PublicType"); + + // core reflection + Constructor ctor = clazz.getConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + ctor.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + // method handles + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + } catch (IllegalAccessException expected) { } + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + } + + @Test + public void testNotPublicTypeInConcealedPackage() throws Throwable { + Class clazz = Class.forName("q.internal.NotPublicType"); + + // core reflection + Constructor ctor = clazz.getConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + ctor.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + // method handles + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup()); + } catch (IllegalAccessException expected) { } + try { + findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup()); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + } + + /** + * Produces the method handle for the no-arg constructor and invokes it + */ + Object findNoArgConstructorAndInvoke(Class clazz, Lookup lookup) throws Throwable { + MethodType mt = MethodType.methodType(void.class); + MethodHandle mh = lookup.findConstructor(clazz, mt); + return mh.invoke(); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m1/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +open module m1 { + exports p; +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p; + +class NotPublicType { + public NotPublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m1/p/PublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m1/p/PublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p; + +public class PublicType { + public PublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p.internal; + +class NotPublicType { + public NotPublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p.internal; + +public class PublicType { + public PublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m2/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m2/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module m2 { + exports q; + opens q; +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package q; + +class NotPublicType { + public NotPublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m2/q/PublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m2/q/PublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package q; + +public class PublicType { + public PublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package q.internal; + +class NotPublicType { + public NotPublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package q.internal; + +public class PublicType { + public PublicType() { } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java --- a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -58,10 +58,10 @@ assertTrue(requires.contains("java.base")); // uses ScriptEngineFactory - Map provides = descriptor.provides(); + Set provides = descriptor.provides(); assertTrue(provides.size() == 1); String sn = ScriptEngineFactory.class.getName(); - assertTrue(provides.containsKey(sn)); + assertTrue(provides.iterator().next().service().equals(sn)); // Check that it is iterated over with ServiceLoader ServiceLoader sl diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/net/idn/TestStringPrep.java --- a/jdk/test/sun/net/idn/TestStringPrep.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/net/idn/TestStringPrep.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,8 @@ * @test * @summary Unit test for sun.net.idn.Punycode * @bug 4737170 8060097 - * @modules java.base/sun.net.idn java.base/sun.text.normalizer + * @modules java.base/sun.net.idn:+open + * java.base/sun.text.normalizer * @library . * @compile -XDignore.symbol.file TestStringPrep.java NFS4StringPrep.java * TestData.java diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/net/www/http/HttpClient/IsAvailable.java --- a/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,7 @@ * @summary HttpClient available() check throws SocketException when connection * has been closed * @modules java.base/sun.net - * java.base/sun.net.www.http + * java.base/sun.net.www.http:+open */ import java.net.URL; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/net/www/protocol/http/NoNTLM.java --- a/jdk/test/sun/net/www/protocol/http/NoNTLM.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/net/www/protocol/http/NoNTLM.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,7 @@ * @summary Sanity check that NTLM will not be selected by the http protocol * handler when running on a profile that does not support NTLM * @modules java.base/sun.net.www - * java.base/sun.net.www.protocol.http + * java.base/sun.net.www.protocol.http:open * @run main/othervm NoNTLM */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/jgss/spnego/NotPreferredMech.java --- a/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,7 @@ * @bug 8048194 * @modules java.base/sun.security.util * java.security.jgss/sun.security.jgss - * java.security.jgss/sun.security.jgss.spnego + * java.security.jgss/sun.security.jgss.spnego:+open * @run main/othervm NotPreferredMech * @summary GSSContext.acceptSecContext fails when a supported mech is not initiator preferred */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/RFC396xTest.java --- a/jdk/test/sun/security/krb5/RFC396xTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/RFC396xTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,7 @@ * @bug 6862679 * @modules java.security.jgss/sun.security.krb5 * java.security.jgss/sun.security.krb5.internal.crypto - * java.security.jgss/sun.security.krb5.internal.crypto.dk + * java.security.jgss/sun.security.krb5.internal.crypto.dk:+open * @run main/othervm RFC396xTest * @summary ESC: AD Authentication with user with umlauts fails */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/auto/Renew.java --- a/jdk/test/sun/security/krb5/auto/Renew.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/auto/Renew.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,8 +27,8 @@ * @summary JAAS Krb5LoginModule has suspect ticket-renewal logic, * relies on clockskew grace * @modules java.base/sun.security.util - * java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal + * java.security.jgss/sun.security.krb5:+open + * java.security.jgss/sun.security.krb5.internal:+open * java.security.jgss/sun.security.krb5.internal.ccache * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/auto/TEST.properties --- a/jdk/test/sun/security/krb5/auto/TEST.properties Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/auto/TEST.properties Thu Dec 01 08:57:53 2016 +0000 @@ -1,8 +1,8 @@ modules java.base/jdk.internal.misc \ java.base/sun.security.util \ java.security.jgss/sun.security.jgss \ - java.security.jgss/sun.security.krb5 \ - java.security.jgss/sun.security.krb5.internal \ + java.security.jgss/sun.security.krb5:+open \ + java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ccache \ java.security.jgss/sun.security.krb5.internal.rcache \ java.security.jgss/sun.security.krb5.internal.crypto \ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/ccache/TimeInCCache.java --- a/jdk/test/sun/security/krb5/ccache/TimeInCCache.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/ccache/TimeInCCache.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,7 @@ * @test * @bug 6590930 * @modules java.security.jgss/sun.security.krb5 - * java.security.jgss/sun.security.krb5.internal.ccache + * java.security.jgss/sun.security.krb5.internal.ccache:+open * @run main/othervm TimeInCCache * @summary read/write does not match for ccache */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/config/DefUdpLimit.java --- a/jdk/test/sun/security/krb5/config/DefUdpLimit.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/config/DefUdpLimit.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,8 +25,7 @@ * @test * @bug 8009875 * @summary Provide a default udp_preference_limit for krb5.conf - * @modules java.security.jgss/sun.security.krb5 - * @compile -XDignore.symbol.file DefUdpLimit.java + * @modules java.security.jgss/sun.security.krb5:+open * @run main/othervm DefUdpLimit -1 1465 * @run main/othervm DefUdpLimit 0 0 * @run main/othervm DefUdpLimit 1234 1234 diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/config/DnsFallback.java --- a/jdk/test/sun/security/krb5/config/DnsFallback.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/config/DnsFallback.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,7 +23,7 @@ /* * @test * @bug 6673164 6552334 8077102 - * @modules java.security.jgss/sun.security.krb5 + * @modules java.security.jgss/sun.security.krb5:+open * @run main/othervm DnsFallback * @summary fix dns_fallback parse error, and use dns by default */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java --- a/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,7 @@ * @test * @bug 7184246 * @summary Simplify Config.get() of krb5 - * @modules java.security.jgss/sun.security.krb5 + * @modules java.security.jgss/sun.security.krb5:+open */ import java.lang.reflect.Field; import java.lang.reflect.Method; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/krb5/tools/KtabZero.java --- a/jdk/test/sun/security/krb5/tools/KtabZero.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/krb5/tools/KtabZero.java Thu Dec 01 08:57:53 2016 +0000 @@ -34,7 +34,7 @@ * @bug 8014196 * @summary ktab creates a file with zero kt_vno * @requires os.family == "windows" - * @modules java.security.jgss/sun.security.krb5.internal.ktab + * @modules java.security.jgss/sun.security.krb5.internal.ktab:+open * java.security.jgss/sun.security.krb5.internal.tools */ public class KtabZero { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java --- a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -24,7 +24,8 @@ /** * @test * @bug 8047769 - * @modules java.base/sun.security.provider + * @modules java.base/java.lang.ref:open + * java.base/sun.security.provider:open * @summary SecureRandom should be more frugal with file descriptors */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java --- a/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java Thu Dec 01 08:57:53 2016 +0000 @@ -33,7 +33,8 @@ /** * @test * @bug 8051408 - * @modules java.base/sun.security.provider + * @modules java.base/java.lang.reflect:open + * java.base/sun.security.provider:+open * @run main/othervm CommonSeeder * @summary check entropy reading of DRBGs */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java --- a/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,7 +32,7 @@ /** * @test * @bug 8157308 - * @modules java.base/sun.security.provider + * @modules java.base/sun.security.provider:+open * @summary Make AbstractDrbg non-Serializable * @run main DRBGS11n mech * @run main DRBGS11n capability diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java --- a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,8 @@ * @bug 8080535 * @summary Expected size of Character.UnicodeBlock.map is not optimal * @library /lib/testlibrary - * @modules java.base/sun.security.ssl + * @modules java.base/java.util:open + * java.base/sun.security.ssl:open * @build jdk.testlibrary.OptimalCapacity * @run main OptimalListSize */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java --- a/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,7 +27,7 @@ * @summary Make sure jar files with large entries (more than max heap size) * can be signed * @modules jdk.jartool/sun.security.tools.jarsigner - * @run main/othervm -Xmx8M LargeJarEntry + * @run main/othervm -Xmx16m LargeJarEntry * @author Sean Mullan */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/tools/keytool/StartDateTest.java --- a/jdk/test/sun/security/tools/keytool/StartDateTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/tools/keytool/StartDateTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,8 +25,7 @@ * @test * @bug 6468285 * @summary keytool ability to backdate self-signed certificates to compensate for clock skew - * @modules java.base/sun.security.tools.keytool - * @compile -XDignore.symbol.file StartDateTest.java + * @modules java.base/sun.security.tools.keytool:+open * @run main StartDateTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java --- a/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,7 @@ * @author Gary Ellison * @bug 4170635 * @summary Verify equals()/hashCode() contract honored - * @modules java.base/sun.security.util + * @modules java.base/sun.security.util:+open * java.base/sun.security.x509 * @run main/othervm/policy=Allow.policy DerInputBufferEqualsHashCode */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/tools/jconsole/ResourceCheckTest.java --- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -27,6 +27,7 @@ * @bug 5008856 5023573 5024917 5062569 7172176 * @summary 'missing resource key' error for key = "Operating system" * @modules jdk.jconsole/sun.tools.jconsole + * jdk.jconsole/sun.tools.jconsole.resources:open * @run main ResourceCheckTest */ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/sun/util/calendar/zi/TestZoneInfo310.java --- a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,7 @@ * @bug 8007572 8008161 8157792 * @summary Test whether the TimeZone generated from JSR310 tzdb is the same * as the one from the tz data from javazic - * @modules java.base/sun.util.calendar + * @modules java.base/sun.util.calendar:+open * @build BackEnd Checksum DayOfWeek Gen GenDoc Main Mappings Month * Rule RuleDay RuleRec Simple TestZoneInfo310 Time Timezone * TzIDOldMapping Zone ZoneInfoFile ZoneInfoOld ZoneRec Zoneinfo diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/mmrjar/ConcealedPackage.java --- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,6 +26,8 @@ * @bug 8146486 * @summary Fail to create a MR modular JAR with a versioned entry in * base-versioned empty package + * @modules jdk.compiler + * jdk.jartool * @library /lib/testlibrary * @build jdk.testlibrary.FileUtils * @run testng ConcealedPackage @@ -56,6 +58,7 @@ private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") .orElseThrow(() -> new RuntimeException("javac tool not found")); private final String linesep = System.lineSeparator(); + private final Path testsrc; private final Path userdir; private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream(); private final PrintStream out = new PrintStream(outbytes, true); @@ -63,7 +66,7 @@ private final PrintStream err = new PrintStream(errbytes, true); public ConcealedPackage() throws IOException { - Path testsrc = Paths.get(System.getProperty("test.src")); + testsrc = Paths.get(System.getProperty("test.src")); userdir = Paths.get(System.getProperty("user.dir", ".")); // compile the classes directory @@ -124,8 +127,7 @@ jar("-tf mmr.jar"); - String s = new String(outbytes.toByteArray()); - Set actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet()); + Set actual = lines(outbytes); Set expected = Set.of( "META-INF/", "META-INF/MANIFEST.MF", @@ -139,10 +141,8 @@ rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class"); Assert.assertEquals(rc, 1); - s = new String(errbytes.toByteArray()); - Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public " - + "class not found in base entries") - ); + String s = new String(errbytes.toByteArray()); + Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class")); } // updates a valid multi-release jar with a module-info class and new @@ -158,15 +158,11 @@ Assert.assertEquals(rc, 0); String s = new String(errbytes.toByteArray()); - Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a " - + "concealed package, \nplacing this jar on the class path " - + "will result in incompatible public interfaces") - ); + Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class")); jar("-tf mmr.jar"); - s = new String(outbytes.toByteArray()); - Set actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet()); + Set actual = lines(outbytes); Set expected = Set.of( "META-INF/", "META-INF/MANIFEST.MF", @@ -186,9 +182,7 @@ Assert.assertEquals(rc, 1); String s = new String(errbytes.toByteArray()); - Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public " - + "class not found in base entries") - ); + Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class")); } // jar tool succeeds building mmr.jar because of concealed package @@ -199,15 +193,11 @@ Assert.assertEquals(rc, 0); String s = new String(errbytes.toByteArray()); - Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a " - + "concealed package, \nplacing this jar on the class path " - + "will result in incompatible public interfaces") - ); + Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class")); jar("-tf mmr.jar"); - s = new String(outbytes.toByteArray()); - Set actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet()); + Set actual = lines(outbytes); Set expected = Set.of( "META-INF/", "META-INF/MANIFEST.MF", @@ -222,4 +212,128 @@ ); Assert.assertEquals(actual, expected); } + + // jar tool does two updates, no exported packages, all concealed + @Test + public void test5() throws IOException { + // compile the mr10 directory + Path source = testsrc.resolve("src").resolve("mr10"); + Path destination = Paths.get("mr10"); + javac(source, destination); + + // create a directory for this tests special files + Files.createDirectory(Paths.get("test5")); + + // create an empty module-info.java + String hi = "module hi {" + linesep + "}" + linesep; + Path modinfo = Paths.get("test5", "module-info.java"); + Files.write(modinfo, hi.getBytes()); + + // and compile it + javac(modinfo, Paths.get("test5")); + + int rc = jar("--create --file mr.jar -C classes ."); + Assert.assertEquals(rc, 0); + + rc = jar("--update --file mr.jar -C test5 module-info.class" + + " --release 9 -C mr9 ."); + Assert.assertEquals(rc, 0); + + jar("tf mr.jar"); + + Set actual = lines(outbytes); + Set expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "p/", + "p/Hi.class", + "META-INF/versions/9/p/", + "META-INF/versions/9/p/Hi.class", + "META-INF/versions/9/p/internal/", + "META-INF/versions/9/p/internal/Bar.class", + "module-info.class" + ); + Assert.assertEquals(actual, expected); + + jar("-d --file mr.jar"); + + actual = lines(outbytes); + expected = Set.of( + "hi", + "requires mandated java.base", + "contains p", + "contains p.internal" + ); + Assert.assertEquals(actual, expected); + + rc = jar("--update --file mr.jar --release 10 -C mr10 ."); + Assert.assertEquals(rc, 0); + + jar("tf mr.jar"); + + actual = lines(outbytes); + expected = Set.of( + "META-INF/", + "META-INF/MANIFEST.MF", + "p/", + "p/Hi.class", + "META-INF/versions/9/p/", + "META-INF/versions/9/p/Hi.class", + "META-INF/versions/9/p/internal/", + "META-INF/versions/9/p/internal/Bar.class", + "META-INF/versions/10/p/", + "META-INF/versions/10/p/internal/", + "META-INF/versions/10/p/internal/bar/", + "META-INF/versions/10/p/internal/bar/Gee.class", + "module-info.class" + ); + Assert.assertEquals(actual, expected); + + jar("-d --file mr.jar"); + + actual = lines(outbytes); + expected = Set.of( + "hi", + "requires mandated java.base", + "contains p", + "contains p.internal", + "contains p.internal.bar" + ); + Assert.assertEquals(actual, expected); + } + + private static Set lines(ByteArrayOutputStream baos) { + String s = new String(baos.toByteArray()); + return Arrays.stream(s.split("\\R")) + .map(l -> l.trim()) + .filter(l -> l.length() > 0) + .collect(Collectors.toSet()); + } + + static enum Message { + NOT_FOUND_IN_BASE_ENTRY( + ", contains a new public class not found in base entries" + ), + NEW_CONCEALED_PACKAGE_WARNING( + " is a public class" + + " in a concealed package, placing this jar on the class path will result" + + " in incompatible public interfaces" + ); + + final String msg; + Message(String msg) { + this.msg = msg; + } + + /* + * Test if the given output contains this message ignoring the line break. + */ + boolean match(String output, String entry) { + System.out.println("Expected: " + entry + msg); + System.out.println("Found: " + output); + return Arrays.stream(output.split("\\R")) + .collect(Collectors.joining(" ")) + .contains(entry + msg); + } + } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,7 @@ +package p.internal.bar; + +public class Gee { + public void geeWhiz() { + System.out.println("Gee whiz"); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/modularJar/Basic.java --- a/jdk/test/tools/jar/modularJar/Basic.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jar/modularJar/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,19 +22,18 @@ */ import java.io.*; +import java.lang.module.ModuleDescriptor; import java.lang.reflect.Method; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; +import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.function.Consumer; import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.testlibrary.FileUtils; @@ -76,7 +75,8 @@ Set.of("jdk.test.foo"), null, // no uses null, // no provides - Set.of("jdk.test.foo.internal")); + Set.of("jdk.test.foo.internal", + "jdk.test.foo.resources")); static TestModuleData BAR = new TestModuleData("bar", "4.5.6.7", "jdk.test.bar.Bar", @@ -99,17 +99,18 @@ final String version; final String message; final String hashes; - final Set conceals; + final Set packages; TestModuleData(String mn, String v, String mc, String m, String h, Set requires, Set exports, Set uses, - Set provides, Set conceals) { + Set provides, Set contains) { moduleName = mn; mainClass = mc; version = v; message = m; hashes = h; - this.requires = requires; - this.exports = exports; - this.uses = uses; - this.provides = provides; - this.conceals = conceals; + this.requires = requires != null ? requires : Collections.emptySet(); + this.exports = exports != null ? exports : Collections.emptySet(); + this.uses = uses != null ? uses : Collections.emptySet();; + this.provides = provides != null ? provides : Collections.emptySet(); + this.packages = Stream.concat(this.exports.stream(), contains.stream()) + .collect(Collectors.toSet()); } static TestModuleData from(String s) { try { @@ -148,8 +149,8 @@ provides = stringToSet(line); } else if (line.startsWith("hashes:")) { hashes = line.substring("hashes:".length()); - } else if (line.startsWith("conceals:")) { - line = line.substring("conceals:".length()); + } else if (line.startsWith("contains:")) { + line = line.substring("contains:".length()); conceals = stringToSet(line); } else { throw new AssertionError("Unknown value " + line); @@ -192,16 +193,14 @@ assertSetsEqual(expected.exports, received.exports); assertSetsEqual(expected.uses, received.uses); assertSetsEqual(expected.provides, received.provides); - assertSetsEqual(expected.conceals, received.conceals); + assertSetsEqual(expected.packages, received.packages); } static void assertSetsEqual(Set s1, Set s2) { - if (s1 == null && s2 == null) // none expected, or received - return; - assertTrue(s1.size() == s2.size(), - "Unexpected set size difference: ", s1.size(), ", ", s2.size()); - s1.forEach(p -> assertTrue(s2.contains(p), "Expected ", p, ", in ", s2)); - } + if (!s1.equals(s2)) { + org.testng.Assert.assertTrue(false, s1 + " vs " + s2); + } + } @BeforeTest public void compileModules() throws Exception { @@ -209,6 +208,11 @@ compileModule(BAR.moduleName, MODULE_CLASSES); compileModule("baz"); // for service provider consistency checking + // copy resources + copyResource(TEST_SRC.resolve("src").resolve(FOO.moduleName), + MODULE_CLASSES.resolve(FOO.moduleName), + "jdk/test/foo/resources/foo.properties"); + setupMRJARModuleInfo(FOO.moduleName); setupMRJARModuleInfo(BAR.moduleName); setupMRJARModuleInfo("baz"); @@ -228,6 +232,12 @@ "--no-manifest", "-C", modClasses.toString(), ".") .assertSuccess(); + + assertSetsEqual(readPackagesAttribute(modularJar), + Set.of("jdk.test.foo", + "jdk.test.foo.resources", + "jdk.test.foo.internal")); + java(mp, FOO.moduleName + "/" + FOO.mainClass) .assertSuccess() .resultChecker(r -> assertModuleData(r, FOO)); @@ -375,7 +385,8 @@ "--file=" + modularJar.toString(), "--no-manifest", "-C", modClasses.toString(), "module-info.class", - "-C", modClasses.toString(), "jdk/test/foo/Foo.class") + "-C", modClasses.toString(), "jdk/test/foo/Foo.class", + "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties") .assertSuccess(); jar("--update", "--file=" + modularJar.toString(), @@ -471,13 +482,63 @@ "Expecting to find \"bar, requires foo,...\"", "in output, but did not: [" + r.output + "]"); p = Pattern.compile( - "conceals\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal"); + "contains\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal"); assertTrue(p.matcher(r.output).find(), - "Expecting to find \"conceals jdk.test.foo,...\"", + "Expecting to find \"contains jdk.test.foo,...\"", "in output, but did not: [" + r.output + "]"); }); } + + @Test + public void partialUpdateFooPackagesAttribute() throws IOException { + Path mp = Paths.get("partialUpdateFooPackagesAttribute"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + // Not all files, and none from non-exported packages, + // i.e. no concealed list in first create + jar("--create", + "--file=" + modularJar.toString(), + "--no-manifest", + "-C", modClasses.toString(), "module-info.class", + "-C", modClasses.toString(), "jdk/test/foo/Foo.class") + .assertSuccess(); + + assertSetsEqual(readPackagesAttribute(modularJar), + Set.of("jdk.test.foo")); + + jar("--update", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties") + .assertSuccess(); + + assertSetsEqual(readPackagesAttribute(modularJar), + Set.of("jdk.test.foo", "jdk.test.foo.resources")); + + jar("--update", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class") + .assertSuccess(); + + assertSetsEqual(readPackagesAttribute(modularJar), + Set.of("jdk.test.foo", + "jdk.test.foo.resources", + "jdk.test.foo.internal")); + + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + } + + private Set readPackagesAttribute(Path jar) { + return getModuleDescriptor(jar).packages(); + } + @Test public void hashBarInFooModule() throws IOException { Path mp = Paths.get("dependencesFooBar"); @@ -506,6 +567,7 @@ .assertSuccess(); java(mp, BAR.moduleName + "/" + BAR.mainClass, + "--add-exports", "java.base/jdk.internal.misc=bar", "--add-exports", "java.base/jdk.internal.module=bar") .assertSuccess() .resultChecker(r -> { @@ -550,6 +612,7 @@ "-C", barClasses.toString(), ".").assertSuccess(); java(mp, BAR.moduleName + "/" + BAR.mainClass, + "--add-exports", "java.base/jdk.internal.misc=bar", "--add-exports", "java.base/jdk.internal.module=bar") .assertFailure() .resultChecker(r -> { @@ -750,12 +813,22 @@ static Path compileModule(String mn, Path mp) throws IOException { - Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn); + Path sourcePath = TEST_SRC.resolve("src").resolve(mn); Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn)); - javac(build, mp, fileList(fooSourcePath)); + javac(build, mp, sourceList(sourcePath)); return build; } + static void copyResource(Path srcDir, Path dir, String resource) + throws IOException + { + Path dest = dir.resolve(resource); + Files.deleteIfExists(dest); + + Files.createDirectories(dest.getParent()); + Files.copy(srcDir.resolve(resource), dest); + } + static void setupMRJARModuleInfo(String moduleName) throws IOException { Path modClasses = MODULE_CLASSES.resolve(moduleName); Path metaInfDir = MRJAR_DIR.resolve(moduleName).resolve("META-INF"); @@ -774,6 +847,18 @@ } } + static ModuleDescriptor getModuleDescriptor(Path jar) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + try (JarFile jf = new JarFile(jar.toFile())) { + JarEntry entry = jf.getJarEntry("module-info.class"); + try (InputStream in = jf.getInputStream(entry)) { + return ModuleDescriptor.read(in); + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + // Re-enable when there is support in javax.tools for module path // static void javac(Path dest, Path... sourceFiles) throws IOException { // out.printf("Compiling %d source files %s%n", sourceFiles.length, @@ -817,6 +902,8 @@ commands.add(dest.toString()); if (dest.toString().contains("bar")) { commands.add("--add-exports"); + commands.add("java.base/jdk.internal.misc=bar"); + commands.add("--add-exports"); commands.add("java.base/jdk.internal.module=bar"); } if (modulePath != null) { @@ -848,17 +935,10 @@ return run(new ProcessBuilder(commands)); } - static Path[] fileList(Path directory) throws IOException { - final List filePaths = new ArrayList<>(); - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) { - filePaths.add(file); - return FileVisitResult.CONTINUE; - } - }); - return filePaths.toArray(new Path[filePaths.size()]); + static Path[] sourceList(Path directory) throws IOException { + return Files.find(directory, Integer.MAX_VALUE, + (file, attrs) -> (file.toString().endsWith(".java"))) + .toArray(Path[]::new); } static void createTestDir(Path p) throws IOException{ diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java --- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,10 +26,14 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Requires; -import java.lang.reflect.Method; +import java.lang.module.ModuleDescriptor.Provides; import java.util.Optional; import java.util.StringJoiner; +import java.util.HashSet; +import java.util.Set; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.module.ModuleHashes; import jdk.test.bar.internal.Message; @@ -56,19 +60,20 @@ System.out.println("uses:" + sj.toString()); sj = new StringJoiner(","); - md.provides().keySet().stream().sorted().forEach(sj::add); + md.provides().stream().map(Provides::service).sorted().forEach(sj::add); if (!sj.toString().equals("")) System.out.println("provides:" + sj.toString()); sj = new StringJoiner(","); - md.conceals().forEach(sj::add); + Set concealed = new HashSet<>(md.packages()); + md.exports().stream().map(Exports::source).forEach(concealed::remove); + concealed.forEach(sj::add); if (!sj.toString().equals("")) - System.out.println("conceals:" + sj.toString()); + System.out.println("contains:" + sj.toString()); - Method m = ModuleDescriptor.class.getDeclaredMethod("hashes"); - m.setAccessible(true); ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor(); - Optional oHashes = (Optional) m.invoke(foo); + JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess(); + Optional oHashes = jlma.hashes(foo); System.out.println("hashes:" + oHashes.get().hashFor("bar")); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java --- a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java Thu Dec 01 08:57:53 2016 +0000 @@ -26,7 +26,10 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Provides; import java.util.StringJoiner; +import java.util.HashSet; +import java.util.Set; import jdk.test.foo.internal.Message; @@ -53,13 +56,15 @@ System.out.println("uses:" + sj.toString()); sj = new StringJoiner(","); - md.provides().keySet().stream().sorted().forEach(sj::add); + md.provides().stream().map(Provides::service).sorted().forEach(sj::add); if (!sj.toString().equals("")) System.out.println("provides:" + sj.toString()); sj = new StringJoiner(","); - md.conceals().forEach(sj::add); + Set concealed = new HashSet<>(md.packages()); + md.exports().stream().map(Exports::source).forEach(concealed::remove); + concealed.forEach(sj::add); if (!sj.toString().equals("")) - System.out.println("conceals:" + sj.toString()); + System.out.println("contains:" + sj.toString()); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,1 @@ +name = foo diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/multiRelease/Basic.java --- a/jdk/test/tools/jar/multiRelease/Basic.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jar/multiRelease/Basic.java Thu Dec 01 08:57:53 2016 +0000 @@ -25,7 +25,9 @@ * @test * @library /test/lib * @modules java.base/jdk.internal.misc - * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Platform + * jdk.compiler + * jdk.jartool + * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils * @run testng Basic */ @@ -39,12 +41,14 @@ import java.util.*; import java.util.function.Consumer; import java.util.jar.*; +import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.*; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.Utils; + import static java.lang.String.format; import static java.lang.System.out; @@ -292,7 +296,7 @@ "--release", "9", "-C", classes.resolve("v9").toString(), ".") .assertSuccess() .resultChecker(r -> - assertTrue(r.output.contains("contains a class that is identical"), r.output) + assertTrue(r.outputContains("contains a class that is identical"), r.output) ); delete(jarfile); @@ -450,7 +454,7 @@ "--release", "9", "-C", classes.resolve("v9").toString(), ".") .assertFailure() .resultChecker(r -> - assertTrue(r.output.contains("an isolated nested class"), r.output) + assertTrue(r.outputContains("an isolated nested class"), r.output) ); delete(jarfile); @@ -605,6 +609,13 @@ this.ec = ec; this.output = output; } + + boolean outputContains(String msg) { + return Arrays.stream(output.split("\\R")) + .collect(Collectors.joining(" ")) + .contains(msg); + } + Result assertSuccess() { assertTrue(ec == 0, format("ec: %d, output: %s", ec, output)); return this; diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jar/multiRelease/Basic1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jar/multiRelease/Basic1.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib + * @modules java.base/jdk.internal.misc + * jdk.compiler + * jdk.jartool + * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils + * @run testng Basic1 + */ + +import static org.testng.Assert.*; + +import org.testng.annotations.*; + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.function.Consumer; +import java.util.jar.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.*; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Utils; + + +import static java.lang.String.format; +import static java.lang.System.out; + +public class Basic1 { + private final String src = System.getProperty("test.src", "."); + + @BeforeTest + public void setup() throws IOException { + String test = "test01"; + Path classes = Paths.get("classes", "base"); + Files.createDirectories(classes); + Path source = Paths.get(src, "data", test, "base", "version"); + javac(classes, source.resolve("Main.java"), source.resolve("Version.java")); + + Path v9 = Paths.get("v9").resolve("META-INF").resolve("versions").resolve("9"); + Files.createDirectories(v9); + source = Paths.get(src, "data", test, "v9", "version"); + javac(v9, source.resolve("Version.java")); + + Path v10 = Paths.get("v10").resolve("META-INF").resolve("versions").resolve("10"); + Files.createDirectories(v10); + source = Paths.get(src, "data", test, "v10", "version"); + javac(v10, source.resolve("Version.java")); + } + + @Test + public void test() throws IOException { + String jarfile = "test.jar"; + Path classes = Paths.get("classes"); + Path v9 = Paths.get("v9"); + Path v10 = Paths.get("v10"); + + jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".", + "--release", "9", "-C", v9.toString(), ".", + "--release", "10", "-C", v10.toString(), ".") + .assertSuccess(); + + checkMultiRelease(jarfile, true); + + Map names = Map.of( + "version/Main.class", + new String[] {"classes", "base", "version", "Main.class"}, + + "version/Version.class", + new String[] {"classes", "base", "version", "Version.class"}, + + "META-INF/versions/9/version/Version.class", + new String[] {"v9", "META-INF", "versions", "9", "version", "Version.class"}, + + "META-INF/versions/10/version/Version.class", + new String[] {"v10", "META-INF", "versions", "10", "version", "Version.class"} + ); + + compare(jarfile, names); + } + + @Test + public void testFail() throws IOException { + String jarfile = "test.jar"; + Path classes = Paths.get("classes"); + Path v9 = Paths.get("v9"); + Path v10 = Paths.get("v10"); + + jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".", + "--release", "9", "-C", v10.toString(), ".") + .assertFailure() + .outputContains("unexpected versioned entry META-INF/versions/"); + } + + private void checkMultiRelease(String jarFile, boolean expected) throws IOException { + try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ, + JarFile.runtimeVersion())) { + assertEquals(jf.isMultiRelease(), expected); + } + } + + // compares the bytes found in the jar entries with the bytes found in the + // corresponding data files used to create the entries + private void compare(String jarfile, Map names) throws IOException { + try (JarFile jf = new JarFile(jarfile)) { + for (String name : names.keySet()) { + Path path = Paths.get("", names.get(name)); + byte[] b1 = Files.readAllBytes(path); + byte[] b2; + JarEntry je = jf.getJarEntry(name); + try (InputStream is = jf.getInputStream(je)) { + b2 = is.readAllBytes(); + } + assertEquals(b1,b2); + } + } + } + + /* + * The following methods were taken from modular jar and other jar tests + */ + + void javac(Path dest, Path... sourceFiles) throws IOException { + String javac = JDKToolFinder.getJDKTool("javac"); + + List commands = new ArrayList<>(); + commands.add(javac); + String opts = System.getProperty("test.compiler.opts"); + if (!opts.isEmpty()) { + commands.addAll(Arrays.asList(opts.split(" +"))); + } + commands.add("-d"); + commands.add(dest.toString()); + Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x)); + + quickFail(run(new ProcessBuilder(commands))); + } + + Result jarWithStdin(File stdinSource, String... args) { + String jar = JDKToolFinder.getJDKTool("jar"); + List commands = new ArrayList<>(); + commands.add(jar); + commands.addAll(Utils.getForwardVmOptions()); + Stream.of(args).forEach(x -> commands.add(x)); + ProcessBuilder p = new ProcessBuilder(commands); + if (stdinSource != null) + p.redirectInput(stdinSource); + return run(p); + } + + Result jar(String... args) { + return jarWithStdin(null, args); + } + + void quickFail(Result r) { + if (r.ec != 0) + throw new RuntimeException(r.output); + } + + Result run(ProcessBuilder pb) { + Process p; + out.printf("Running: %s%n", pb.command()); + try { + p = pb.start(); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't start process '%s'", pb.command()), e); + } + + String output; + try { + output = toString(p.getInputStream(), p.getErrorStream()); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't read process output '%s'", pb.command()), e); + } + + try { + p.waitFor(); + } catch (InterruptedException e) { + throw new RuntimeException( + format("Process hasn't finished '%s'", pb.command()), e); + } + return new Result(p.exitValue(), output); + } + + String toString(InputStream in1, InputStream in2) throws IOException { + try (ByteArrayOutputStream dst = new ByteArrayOutputStream(); + InputStream concatenated = new SequenceInputStream(in1, in2)) { + concatenated.transferTo(dst); + return new String(dst.toByteArray(), "UTF-8"); + } + } + + static class Result { + final int ec; + final String output; + + private Result(int ec, String output) { + this.ec = ec; + this.output = output; + } + + boolean outputContains(String msg) { + return Arrays.stream(output.split("\\R")) + .collect(Collectors.joining(" ")) + .contains(msg); + } + + Result assertSuccess() { + assertTrue(ec == 0, format("ec: %d, output: %s", ec, output)); + return this; + } + Result assertFailure() { + assertTrue(ec != 0, format("ec: %d, output: %s", ec, output)); + return this; + } + Result resultChecker(Consumer r) { r.accept(this); return this; } + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/IntegrationTest.java --- a/jdk/test/tools/jlink/IntegrationTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/IntegrationTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -59,7 +59,6 @@ * @library ../lib * @modules java.base/jdk.internal.jimage * jdk.jdeps/com.sun.tools.classfile - * jdk.jlink/jdk.tools.jlink * jdk.jlink/jdk.tools.jlink.builder * jdk.jlink/jdk.tools.jlink.internal * jdk.jlink/jdk.tools.jlink.internal.plugins diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/JLinkNegativeTest.java --- a/jdk/test/tools/jlink/JLinkNegativeTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/JLinkNegativeTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -274,7 +274,7 @@ helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames); try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { - ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1) + ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1) .requires("java.base").build(), out); } @@ -332,7 +332,7 @@ helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames); try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { - ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1) + ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1) .requires("java.base").build(), out); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/JLinkTest.java --- a/jdk/test/tools/jlink/JLinkTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/JLinkTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -62,9 +62,11 @@ // number of built-in plugins from jdk.jlink module private static int getNumJlinkPlugins() { ModuleDescriptor desc = Plugin.class.getModule().getDescriptor(); - return desc.provides(). - get(Plugin.class.getName()). - providers().size(); + return desc.provides().stream() + .filter(p -> p.service().equals(Plugin.class.getName())) + .map(p -> p.providers().size()) + .findAny() + .orElse(0); } private static boolean isOfJLinkModule(Plugin p) { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/basic/AllModulePath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/basic/AllModulePath.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary jlink test of --add-module ALL-MODULE-PATH + * @library /lib/testlibrary + * @modules jdk.compiler + * @build jdk.testlibrary.ProcessTools + * jdk.testlibrary.OutputAnalyzer + * CompilerUtils + * @run testng AllModulePath + */ + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.spi.ToolProvider; + +import jdk.testlibrary.ProcessTools; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class AllModulePath { + + private final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods"); + private final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src"); + private final Path MODS = Paths.get("mods"); + + private final static Set MODULES = Set.of("test", "m1"); + + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> + new RuntimeException("jlink tool not found") + ); + + @BeforeClass + public void setup() throws Throwable { + if (Files.notExists(JMODS)) { + return; + } + + Files.createDirectories(MODS); + + for (String mn : MODULES) { + Path mod = MODS.resolve(mn); + if (!CompilerUtils.compile(SRC.resolve(mn), mod)) { + throw new AssertionError("Compilation failure. See log."); + } + } + } + + @Test + public void testAllModulePath() throws Throwable { + if (Files.notExists(JMODS)) { + return; + } + + // create custom image + Path image = Paths.get("image"); + createImage(image, "--add-modules", "ALL-MODULE-PATH"); + + Set modules = new HashSet<>(); + Files.find(JMODS, 1, (Path p, BasicFileAttributes attr) -> + p.toString().endsWith(".jmod")) + .map(p -> JMODS.relativize(p).toString()) + .map(n -> n.substring(0, n.length()-5)) + .forEach(modules::add); + modules.add("m1"); + modules.add("test"); + checkModules(image, modules); + } + + @Test + public void testLimitModules() throws Throwable { + if (Files.notExists(JMODS)) { + return; + } + + // create custom image + Path image = Paths.get("image1"); + createImage(image, + "--add-modules", "ALL-MODULE-PATH", + "--limit-modules", "m1"); + + checkModules(image, Set.of("m1", "java.base")); + } + + @Test + public void testAddModules() throws Throwable { + if (Files.notExists(JMODS)) { + return; + } + + // create custom image + Path image = Paths.get("image2"); + createImage(image, + "--add-modules", "m1,test", + "--add-modules", "ALL-MODULE-PATH", + "--limit-modules", "java.base"); + + checkModules(image, Set.of("m1", "test", "java.base")); + } + + /* + * check the modules linked in the image + */ + private void checkModules(Path image, Set modules) throws Throwable { + Path cmd = findTool(image, "java"); + + List options = new ArrayList<>(); + options.add(cmd.toString()); + options.add("-m"); + options.add("m1/p.ListModules"); + options.addAll(modules); + + ProcessBuilder pb = new ProcessBuilder(options); + ProcessTools.executeCommand(pb) + .shouldHaveExitValue(0); + } + + private Path findTool(Path image, String tool) { + String suffix = System.getProperty("os.name").startsWith("Windows") + ? ".exe" : ""; + + Path cmd = image.resolve("bin").resolve(tool + suffix); + if (Files.notExists(cmd)) { + throw new RuntimeException(cmd + " not found"); + } + return cmd; + } + + private void createImage(Path image, String... options) throws IOException { + String modulepath = JMODS.toString() + File.pathSeparator + MODS.toString(); + List opts = List.of("--module-path", modulepath, + "--output", image.toString()); + String[] args = Stream.concat(opts.stream(), Arrays.stream(options)) + .toArray(String[]::new); + + System.out.println("jlink " + Arrays.stream(args).collect(Collectors.joining(" "))); + PrintWriter pw = new PrintWriter(System.out); + int rc = JLINK_TOOL.run(pw, pw, args); + assertTrue(rc == 0); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/basic/BasicTest.java --- a/jdk/test/tools/jlink/basic/BasicTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/basic/BasicTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -59,10 +59,11 @@ new RuntimeException("jlink tool not found") ); + private final String TEST_MODULE = "test"; private final Path jdkHome = Paths.get(System.getProperty("test.jdk")); private final Path jdkMods = jdkHome.resolve("jmods"); private final Path testSrc = Paths.get(System.getProperty("test.src")); - private final Path src = testSrc.resolve("src"); + private final Path src = testSrc.resolve("src").resolve(TEST_MODULE); private final Path classes = Paths.get("classes"); private final Path jmods = Paths.get("jmods"); private final Path jars = Paths.get("jars"); @@ -80,23 +81,22 @@ throw new AssertionError("Compilation failure. See log."); } - String modName = "test"; Files.createDirectories(jmods); Files.createDirectories(jars); Path jarfile = jars.resolve("test.jar"); JarUtils.createJarFile(jarfile, classes); Path image = Paths.get("mysmallimage"); - runJmod(jarfile.toString(), modName); - runJlink(image, modName, "--compress", "2"); - execute(image, modName); + runJmod(jarfile.toString(), TEST_MODULE); + runJlink(image, TEST_MODULE, "--compress", "2"); + execute(image, TEST_MODULE); - Files.delete(jmods.resolve(modName + ".jmod")); + Files.delete(jmods.resolve(TEST_MODULE + ".jmod")); image = Paths.get("myimage"); - runJmod(classes.toString(), modName); - runJlink(image, modName); - execute(image, modName); + runJmod(classes.toString(), TEST_MODULE); + runJlink(image, TEST_MODULE); + execute(image, TEST_MODULE); } private void execute(Path image, String moduleName) throws Throwable { diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/basic/src/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/basic/src/m1/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/basic/src/m1/p/ListModules.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/basic/src/m1/p/ListModules.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class ListModules { + public static void main(String... args) { + Set modules = ModuleFinder.ofSystem().findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()); + + Set expected = Arrays.stream(args).collect(Collectors.toSet()); + + if (!modules.equals(expected)) { + throw new RuntimeException(modules + " != " + expected); + } + + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/FileCopierPluginTest.java --- a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -75,11 +75,11 @@ String target = "target" + File.separator + name; Files.write(txt.toPath(), content.getBytes()); - File lic = new File(System.getProperty("java.home"), "LICENSE"); + File lic = new File(System.getProperty("java.home"), "LICENSE.txt"); StringBuilder builder = new StringBuilder(); int expected = lic.exists() ? 4 : 3; if (lic.exists()) { - builder.append("LICENSE,"); + builder.append("LICENSE.txt,"); } builder.append(txt.getAbsolutePath()+","); builder.append(txt.getAbsolutePath() + "=" + target+","); @@ -116,9 +116,9 @@ imgbuilder.storeFiles(pool); if (lic.exists()) { - File license = new File(root.toFile(), "LICENSE"); + File license = new File(root.toFile(), "LICENSE.txt"); if (!license.exists() || license.length() == 0) { - throw new AssertionError("Invalide license file " + throw new AssertionError("Invalid license file " + license.getAbsoluteFile()); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,11 +22,10 @@ */ import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.module.ModuleDescriptor.*; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; -import java.util.Collections; -import java.util.EnumSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -58,14 +57,32 @@ } private void testModuleDescriptor(ModuleDescriptor md) { - assertUnmodifiable(md.conceals(), "conceal"); assertUnmodifiable(md.packages(), "package"); assertUnmodifiable(md.requires(), - jlma.newRequires(EnumSet.allOf(Modifier.class), "require")); - assertUnmodifiable(md.exports(), jlma.newExports("export")); + jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require")); + for (Requires req : md.requires()) { + assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE); + } + + assertUnmodifiable(md.exports(), jlma.newExports(Set.of(), "export", Set.of())); + for (Exports exp : md.exports()) { + assertUnmodifiable(exp.modifiers(), Exports.Modifier.SYNTHETIC); + assertUnmodifiable(exp.targets(), "target"); + } + + assertUnmodifiable(md.opens(), jlma.newOpens(Set.of(), "open", Set.of())); + for (Opens opens : md.opens()) { + assertUnmodifiable(opens.modifiers(), Opens.Modifier.SYNTHETIC); + assertUnmodifiable(opens.targets(), "target"); + } + assertUnmodifiable(md.uses(), "use"); - assertUnmodifiable(md.provides(), "provide", - jlma.newProvides("provide", Collections.singleton("provide"))); + + assertUnmodifiable(md.provides(), + jlma.newProvides("provide", List.of("provide"))); + for (Provides provides : md.provides()) { + assertUnmodifiable(provides.providers(), "provide"); + } } @@ -80,6 +97,17 @@ } } + private void assertUnmodifiable(List list, T dummy) { + try { + list.add(dummy); + fail("Should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // pass + } catch (Exception e) { + fail("Should throw UnsupportedOperationException"); + } + } + private void assertUnmodifiable(Map set, T dummyKey, V dummyValue) { try { set.put(dummyKey, dummyValue); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -52,9 +52,11 @@ private static final Path MODS_DIR = Paths.get("mods"); private static final Path IMAGE = Paths.get("image"); private static final Path JMODS = Paths.get(JAVA_HOME, "jmods"); + private static final String MAIN_MID = "m1/p1.Main"; // the names of the modules in this test - private static String[] modules = new String[] {"m1", "m2", "m3"}; + private static String[] modules = new String[] {"m1", "m2", "m3", "m4"}; + private static boolean hasJmods() { if (!Files.exists(JMODS)) { @@ -80,7 +82,7 @@ FileUtils.deleteFileTreeUnchecked(IMAGE); } - createImage(IMAGE, "java.base", "m1"); + createImage(IMAGE, "java.base", "m1", "m3"); } private void createImage(Path outputDir, String... modules) throws Throwable { @@ -96,20 +98,34 @@ /* * Test the image created when linking with a module with - * no ConcealedPackages attribute + * no Packages attribute */ @Test - public void test() throws Throwable { + public void testPackagesAttribute() throws Throwable { if (!hasJmods()) return; Path java = IMAGE.resolve("bin").resolve("java"); - assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main") + assertTrue(executeProcess(java.toString(), "-m", MAIN_MID) .outputTo(System.out) .errorTo(System.out) .getExitValue() == 0); } /* + * Test the image created when linking with an open module + */ + @Test + public void testOpenModule() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), "-m", "m3/p3.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + /* * Disable the fast loading of system modules. * Parsing module-info.class */ @@ -120,7 +136,7 @@ Path java = IMAGE.resolve("bin").resolve("java"); assertTrue(executeProcess(java.toString(), "-Djdk.system.module.finder.disabledFastPath", - "-m", "m1/p1.Main") + "-m", MAIN_MID) .outputTo(System.out) .errorTo(System.out) .getExitValue() == 0); @@ -135,9 +151,9 @@ if (!hasJmods()) return; Path dir = Paths.get("newImage"); - createImage(dir, "java.base", "m1", "m2", "m3"); + createImage(dir, "java.base", "m1", "m2", "m3", "m4"); Path java = dir.resolve("bin").resolve("java"); - assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main") + assertTrue(executeProcess(java.toString(), "-m", MAIN_MID) .outputTo(System.out) .errorTo(System.out) .getExitValue() == 0); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -48,7 +48,6 @@ } static void validate(ModuleDescriptor md) { - checkPackages(md.conceals(), "p1", "p2"); checkPackages(md.packages(), "p1", "p2"); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,4 +22,5 @@ */ module m3 { + requires m4; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p3; + +import p4.Foo; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Module; + +import static java.lang.module.ModuleDescriptor.Exports.Modifier.*; + +/** + * Test if m4 is an open module and p4 is package that m3 can access + */ +public class Main { + public static void main(String... args) throws Exception { + Module m4 = Foo.class.getModule(); + if (!m4.isOpen("p4")) { + throw new RuntimeException("m3 can't access p4"); + } + + // Test if it can access a private field + Foo foo = Foo.create("foo"); + + Field field = Foo.class.getDeclaredField("name"); + field.setAccessible(true); + String name = (String) field.get(foo); + if (!name.equals("foo")) { + throw new RuntimeException("unexpected Foo::name value = " + name); + } + + checkOpenModule(); + } + + // check the module descriptor of the open module m4 + static void checkOpenModule() { + ModuleDescriptor md = Foo.class.getModule().getDescriptor(); + System.out.println(md); + + if (!md.isOpen()) { + throw new RuntimeException("m4 is a open module"); + } + + if (md.packages().size() != 1 || !md.packages().contains("p4")) { + throw new RuntimeException("unexpected m4 packages: " + md.packages()); + } + + if (!md.opens().isEmpty()) { + throw new RuntimeException("unexpected m4 opens: " + md.opens()); + } + } + +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +open module m4 { + exports p4; +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p4; + +public class Foo { + private final String name; + + private Foo(String name) { + this.name = name; + } + + public static Foo create(String name) { + return new Foo(name); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jmod/JmodTest.java --- a/jdk/test/tools/jmod/JmodTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jmod/JmodTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,13 +23,13 @@ /* * @test + * @bug 8142968 + * @summary Basic test for jmod * @library /lib/testlibrary * @modules jdk.compiler * jdk.jlink * @build jdk.testlibrary.FileUtils CompilerUtils * @run testng JmodTest - * @bug 8142968 - * @summary Basic test for jmod */ import java.io.*; @@ -76,6 +76,9 @@ for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { Path dir = EXPLODED_DIR.resolve(name); assertTrue(compileModule(name, dir.resolve("classes"))); + copyResource(SRC_DIR.resolve("foo"), + dir.resolve("classes"), + "jdk/test/foo/resources/foo.properties"); createCmds(dir.resolve("bin")); createLibs(dir.resolve("lib")); createConfigs(dir.resolve("conf")); @@ -127,6 +130,7 @@ assertContains(r.output, CLASSES_PREFIX + "module-info.class"); assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class"); assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); + assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); }); } @@ -279,6 +283,7 @@ Set expectedFilenames = new HashSet<>(); expectedFilenames.add(CLASSES_PREFIX + "module-info.class"); expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class"); + expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); expectedFilenames.add(LIBS_PREFIX + "second.so"); expectedFilenames.add(LIBS_PREFIX + "third/third.so"); assertJmodContent(jmod, expectedFilenames); @@ -303,15 +308,15 @@ .assertSuccess() .resultChecker(r -> { // Expect similar output: "foo, requires mandated java.base - // exports jdk.test.foo, conceals jdk.test.foo.internal" + // exports jdk.test.foo, contains jdk.test.foo.internal" Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base"); assertTrue(p.matcher(r.output).find(), "Expecting to find \"foo, requires java.base\"" + "in output, but did not: [" + r.output + "]"); p = Pattern.compile( - "exports\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal"); + "exports\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal"); assertTrue(p.matcher(r.output).find(), - "Expecting to find \"exports ..., conceals ...\"" + + "Expecting to find \"exports ..., contains ...\"" + "in output, but did not: [" + r.output + "]"); }); } @@ -369,6 +374,26 @@ } @Test + public void testPackagesAttribute() throws IOException { + Path jmod = MODS_DIR.resolve("foo.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + Set expectedPackages = Set.of("jdk.test.foo", + "jdk.test.foo.internal", + "jdk.test.foo.resources"); + + jmod("create", + "--class-path", cp, + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + Set pkgs = getModuleDescriptor(jmod).packages(); + assertEquals(pkgs, expectedPackages); + }); + } + + @Test public void testVersion() { jmod("--version") .assertSuccess() @@ -557,6 +582,14 @@ } } + static void copyResource(Path srcDir, Path dir, String resource) throws IOException { + Path dest = dir.resolve(resource); + Files.deleteIfExists(dest); + + Files.createDirectories(dest.getParent()); + Files.copy(srcDir.resolve(resource), dest); + } + // Standalone entry point. public static void main(String[] args) throws Throwable { JmodTest test = new JmodTest(); diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jmod/hashes/src/org.bar/module-info.java --- a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,5 +22,5 @@ */ module org.bar { - requires public m1; + requires transitive m1; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jmod/hashes/src/org.foo/module-info.java --- a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,5 +22,5 @@ */ module org.foo { - requires public org.bar; + requires transitive org.bar; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,1 @@ +name = foo diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/InfoStreams.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/InfoStreams.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @build InfoStreams jdk.testlibrary.ProcessTools + * @run main InfoStreams + * @summary Test that informational options use the correct streams + */ + +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.OutputAnalyzer; + + +public class InfoStreams { + + public static OutputAnalyzer run(String ... opts) throws Exception { + return ProcessTools.executeTestJava(opts).shouldHaveExitValue(0); + } + + private static final String + java_version = System.getProperty("java.version"), + USAGE = "^Usage: java ", + VERSION_ERR = "^(java|openjdk) version \"" + java_version + "\"", + VERSION_OUT = "^(java|openjdk) " + java_version, + FULLVERSION_ERR = "^(java|openjdk) full version \"" + java_version + ".*\"", + FULLVERSION_OUT = "^(java|openjdk) " + java_version, + NONSTD = ".*These extra options are subject to change"; + + public static void main(String ... args) throws Exception { + + String classPath = System.getProperty("java.class.path"); + + run("-help").stderrShouldMatch(USAGE).stdoutShouldNotMatch("."); + run("--help").stdoutShouldMatch(USAGE).stderrShouldNotMatch("."); + + run("-version").stderrShouldMatch(VERSION_ERR).stdoutShouldNotMatch("."); + run("--version").stdoutShouldMatch(VERSION_OUT).stderrShouldNotMatch("."); + + run("-showversion", "--dry-run", "-cp", classPath, "InfoStreams") + .stderrShouldMatch(VERSION_ERR) + .stdoutShouldNotMatch("."); + run("--show-version", "--dry-run", "-cp", classPath, "InfoStreams") + .stdoutShouldMatch(VERSION_OUT) + .stderrShouldNotMatch("."); + + run("-fullversion").stderrShouldMatch(FULLVERSION_ERR) + .stdoutShouldNotMatch("."); + run("--full-version").stdoutShouldMatch(FULLVERSION_OUT) + .stderrShouldNotMatch("."); + + run("-X").stderrShouldMatch(NONSTD).stdoutShouldNotMatch("."); + run("--help-extra").stdoutShouldMatch(NONSTD).stderrShouldNotMatch("."); + + } + +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/addexports/AddExportsTest.java --- a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -32,7 +32,9 @@ import java.nio.file.Path; import java.nio.file.Paths; +import java.util.stream.Stream; +import jdk.testlibrary.OutputAnalyzer; import static jdk.testlibrary.ProcessTools.*; import org.testng.annotations.BeforeTest; @@ -202,13 +204,15 @@ /** - * --add-exports allows duplicates + * --add-exports and --add-opens allows duplicates */ public void testWithDuplicateOption() throws Exception { int exitValue = executeTestJava("--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED", + "--add-opens", "java.base/java.util=ALL-UNNAMED", + "--add-opens", "java.base/java.util=ALL-UNNAMED", "-version") .outputTo(System.out) .errorTo(System.out) @@ -218,23 +222,33 @@ } + private OutputAnalyzer execJava(String... options) { + try { + return executeTestJava(options); + } catch (Exception e) { + throw new Error(e); + } + } + /** - * Exercise --add-exports with unknown values. Warning is emitted. + * Exercise --add-exports and --add-opens with unknown values. + * Warning is emitted. */ @Test(dataProvider = "unknownvalues") - public void testWithUnknownValue(String value, String ignore) throws Exception { + public void testWithUnknownValue(String value, String ignore) { + Stream.of("--add-exports", "--add-opens") + .forEach(option -> { + // --add-exports $VALUE -version + int exitValue = execJava(option, value, "-version") + .stderrShouldMatch("WARNING: .*.monkey.*") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); - // --add-exports $VALUE -version - int exitValue = - executeTestJava("--add-exports", value, - "-version") - .stderrShouldMatch("WARNING: .*.monkey.*") - .outputTo(System.out) - .errorTo(System.out) - .getExitValue(); + assertTrue(exitValue == 0); + }); + } - assertTrue(exitValue == 0); - } @DataProvider(name = "unknownvalues") public Object[][] unknownValues() { @@ -250,20 +264,20 @@ /** - * Exercise --add-exports with bad values + * Exercise --add-exports and --add-opens with bad values */ @Test(dataProvider = "badvalues") - public void testWithBadValue(String value, String ignore) throws Exception { - - // --add-exports $VALUE -version - int exitValue = - executeTestJava("--add-exports", value, - "-version") - .outputTo(System.out) - .errorTo(System.out) - .getExitValue(); + public void testWithBadValue(String value, String ignore) { + Stream.of("--add-exports", "--add-opens") + .forEach(option -> { + // --add-exports $VALUE -version + int exitValue = execJava(option, value, "-version") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); assertTrue(exitValue != 0); + }); } @DataProvider(name = "badvalues") diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build AddExportsAndOpensInManifest Test2 JarUtils jdk.testlibrary.* + * @compile --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED Test1.java + * @run testng AddExportsAndOpensInManifest + * @summary Basic test for Add-Exports and Add-Opens attributes in the + * manifest of a main application JAR + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class AddExportsAndOpensInManifest { + + /** + * Package Test1 and Test2 into a JAR file with the given attributes + * in the JAR manifest, then execute the JAR file with `java -jar`. + */ + private OutputAnalyzer runTest(String attributes) throws Exception { + Manifest man = new Manifest(); + Attributes attrs = man.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + + for (String nameAndValue : attributes.split(",")) { + String[] s = nameAndValue.split("="); + if (s.length != 2) + throw new RuntimeException("Malformed: " + nameAndValue); + String name = s[0]; + String value = s[1]; + attrs.put(new Attributes.Name(name), value); + } + + // create the JAR file with Test1 and Test2 + Path jarfile = Paths.get("test.jar"); + Files.deleteIfExists(jarfile); + + Path classes = Paths.get(System.getProperty("test.classes", "")); + JarUtils.createJarFile(jarfile, man, classes, + Paths.get("Test1.class"), Paths.get("Test2.class")); + + // java -jar test.jar + return ProcessTools.executeTestJava("-jar", jarfile.toString()) + .outputTo(System.out) + .errorTo(System.out); + } + + /** + * Run test with the given JAR attributes, expecting the test to pass + */ + private void runExpectingPass(String attrs) throws Exception { + int exitValue = runTest(attrs).getExitValue(); + assertTrue(exitValue == 0); + } + + /** + * Run test with the given JAR attributes, expecting the test to fail + * with at least the given output + */ + private void runExpectingFail(String attrs, String errorString) throws Exception { + int exitValue = runTest(attrs).shouldContain(errorString).getExitValue(); + assertTrue(exitValue != 0); + } + + + /** + * Run tests to make sure that they fail in the expected way. + */ + public void testSanity() throws Exception { + runExpectingFail("Main-Class=Test1", "IllegalAccessError"); + runExpectingFail("Main-Class=Test2", "InaccessibleObjectException"); + } + + /** + * Run tests with the Add-Exports attribute in the main manifest. + */ + public void testWithAddExports() throws Exception { + runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc"); + runExpectingFail("Main-Class=Test2,Add-Exports=java.base/jdk.internal.misc", + "InaccessibleObjectException"); + + // run with leading and trailing spaces + runExpectingPass("Main-Class=Test1,Add-Exports= java.base/jdk.internal.misc"); + runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc "); + + // run with multiple values + runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc" + + " java.base/jdk.internal.loader"); + runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.loader" + + " java.base/jdk.internal.misc"); + + // run with duplicate values + runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc" + + " java.base/jdk.internal.misc"); + } + + /** + * Run tests with the Add-Opens attribute in the main manifest. + */ + public void testWithAddOpens() throws Exception { + runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc"); + runExpectingPass("Main-Class=Test2,Add-Opens=java.base/jdk.internal.misc"); + + // run with leading and trailing spaces + runExpectingPass("Main-Class=Test1,Add-Opens= java.base/jdk.internal.misc"); + runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc "); + + // run with multiple values + runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc" + + " java.base/jdk.internal.loader"); + runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.loader" + + " java.base/jdk.internal.misc"); + + // run with duplicate values + runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc" + + " java.base/jdk.internal.misc"); + } + + /** + * Run tests a bad module or package name + */ + public void testWithBadModuleOrPackage() throws Exception { + // Add-Exports with bad module name + String attrs = "Main-Class=Test1,Add-Exports=java.DoesNotExist/jdk.internal.misc"; + runExpectingFail(attrs, "IllegalAccessError"); + + // Add-Exports with bad package name + attrs = "Main-Class=Test1,Add-Exports=java.base/jdk.internal.DoesNotExit"; + runExpectingFail(attrs, "IllegalAccessError"); + + // Add-Opens with bad module name + attrs = "Main-Class=Test1,Add-Opens=java.DoesNotExist/jdk.internal.misc"; + runExpectingFail(attrs, "IllegalAccessError"); + + // Add-Opens with bad package name + attrs = "Main-Class=Test1,Add-Opens=java.base/jdk.internal.DoesNotExit"; + runExpectingFail(attrs, "IllegalAccessError"); + } + +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/addexports/manifest/Test1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test1.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.misc.Unsafe; + +public class Test1 { + public static void main(String[] args) throws Exception { + Unsafe unsafe = Unsafe.getUnsafe(); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/addexports/manifest/Test2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test2.java Thu Dec 01 08:57:53 2016 +0000 @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Field; + +/** + * Use core reflection and setAccessible(true) to access private field. + */ + +public class Test2 { + public static void main(String[] args) throws Exception { + Class c = Class.forName("jdk.internal.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + Object unsafe = f.get(null); + } +} diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java --- a/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java Thu Dec 01 08:57:53 2016 +0000 @@ -23,13 +23,10 @@ package jdk.test1; -import java.lang.reflect.Field; import jdk.internal.misc.Unsafe; public class Main { public static void main(String[] args) throws Exception { - Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - Unsafe unsafe = (Unsafe) theUnsafe.get(null); + Unsafe unsafe = Unsafe.getUnsafe(); } } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/listmods/ListModsTest.java --- a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java Thu Dec 01 08:57:53 2016 +0000 @@ -115,7 +115,7 @@ .outputTo(System.out) .errorTo(System.out); output.shouldNotContain("java.base"); - output.shouldNotContain("java.rhubarb"); + output.shouldContain("java.rhubarb not observable"); assertTrue(output.getExitValue() == 0); } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java --- a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java Thu Dec 01 08:57:53 2016 +0000 @@ -22,6 +22,6 @@ */ module java.transaction { - requires public java.enterprise; + requires transitive java.enterprise; exports javax.transaction; } diff -r 7a4a59859ac0 -r a60f280f803c jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java Wed Nov 23 16:16:35 2016 +0000 +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java Thu Dec 01 08:57:53 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.Code_attribute; import com.sun.tools.classfile.CompilationID_attribute; -import com.sun.tools.classfile.ConcealedPackages_attribute; import com.sun.tools.classfile.ConstantPool; import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; @@ -65,8 +64,6 @@ import com.sun.tools.classfile.EnclosingMethod_attribute; import com.sun.tools.classfile.Exceptions_attribute; import com.sun.tools.classfile.Field; -import com.sun.tools.classfile.Hashes_attribute; -import com.sun.tools.classfile.Hashes_attribute.Entry; import com.sun.tools.classfile.InnerClasses_attribute; import com.sun.tools.classfile.InnerClasses_attribute.Info; import com.sun.tools.classfile.Instruction; @@ -74,13 +71,18 @@ import com.sun.tools.classfile.LineNumberTable_attribute; import com.sun.tools.classfile.LocalVariableTable_attribute; import com.sun.tools.classfile.LocalVariableTypeTable_attribute; -import com.sun.tools.classfile.MainClass_attribute; import com.sun.tools.classfile.Method; import com.sun.tools.classfile.MethodParameters_attribute; import com.sun.tools.classfile.Module_attribute; import com.sun.tools.classfile.Module_attribute.ExportsEntry; import com.sun.tools.classfile.Module_attribute.ProvidesEntry; import com.sun.tools.classfile.Module_attribute.RequiresEntry; +import com.sun.tools.classfile.ModuleHashes_attribute; +import com.sun.tools.classfile.ModuleHashes_attribute.Entry; +import com.sun.tools.classfile.ModuleMainClass_attribute; +import com.sun.tools.classfile.ModuleTarget_attribute; +import com.sun.tools.classfile.ModulePackages_attribute; +import com.sun.tools.classfile.ModuleVersion_attribute; import com.sun.tools.classfile.Opcode; import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; @@ -102,11 +104,9 @@ import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame_extended; import com.sun.tools.classfile.StackMap_attribute; import com.sun.tools.classfile.Synthetic_attribute; -import com.sun.tools.classfile.TargetPlatform_attribute; import com.sun.tools.classfile.TypeAnnotation; import com.sun.tools.classfile.TypeAnnotation.Position; import static com.sun.tools.classfile.TypeAnnotation.TargetType.THROWS; -import com.sun.tools.classfile.Version_attribute; import java.io.*; import java.util.*; import java.util.jar.JarEntry; @@ -1017,7 +1017,7 @@ } @Override - public Element visitConcealedPackages(ConcealedPackages_attribute attr, Element p) { + public Element visitModulePackages(ModulePackages_attribute attr, Element p) { Element e = new Element(x.getCpString(attr.attribute_name_index)); for (int i : attr.packages_index) { Element ee = new Element("Package"); @@ -1128,7 +1128,7 @@ for (ExportsEntry export : exports) { Element exto = new Element("exports"); exto.setAttr("package", x.getCpString(export.exports_index)); - for ( int idx : export.exports_to_index) { + for (int idx : export.exports_to_index) { exto.setAttr("module", x.getCpString(idx)); } ex.add(exto); @@ -1140,7 +1140,9 @@ Element ex = new Element("Provides"); for (ProvidesEntry provide : provides) { ex.setAttr("provides", x.getCpString(provide.provides_index)); - ex.setAttr("with", x.getCpString(provide.with_index)); + for (int idx : provide.with_index) { + ex.setAttr("with", x.getCpString(idx)); + } } p.add(ex); } @@ -1461,14 +1463,20 @@ } @Override - public Element visitHashes(Hashes_attribute attr, Element p) { + public Element visitModuleHashes(ModuleHashes_attribute attr, Element p) { Element e = new Element(x.getCpString(attr.attribute_name_index)); e.setAttr("Algorithm", x.getCpString(attr.algorithm_index)); for (Entry entry : attr.hashes_table) { Element ee = new Element("Entry"); - String requires = x.getCpString(entry.requires_index); - String hashValue = x.getCpString(entry.hash_index); - ee.setAttr(requires, hashValue); + String mn = x.getCpString(entry.module_name_index); + ee.setAttr("module_name", mn); + ee.setAttr("hash_length", "" + entry.hash.length); + StringBuilder sb = new StringBuilder(); + for (byte b: entry.hash) { + sb.append(String.format("%02x", b & 0xff)); + } + ee.setAttr("hash", sb.toString()); + ee.trimToSize(); e.add(ee); } e.trimToSize(); @@ -1478,7 +1486,7 @@ } @Override - public Element visitMainClass(MainClass_attribute attr, Element p) { + public Element visitModuleMainClass(ModuleMainClass_attribute attr, Element p) { Element e = new Element(x.getCpString(attr.attribute_name_index)); e.add(x.getCpString(attr.main_class_index)); e.trimToSize(); @@ -1487,7 +1495,7 @@ } @Override - public Element visitTargetPlatform(TargetPlatform_attribute attr, Element p) { + public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) { Element e = new Element(x.getCpString(attr.attribute_name_index)); e.add(x.getCpString(attr.os_name_index)); e.add(x.getCpString(attr.os_arch_index)); @@ -1498,7 +1506,7 @@ } @Override - public Element visitVersion(Version_attribute attr, Element p) { + public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) { Element e = new Element(x.getCpString(attr.attribute_name_index)); e.add(x.getCpString(attr.version_index)); e.trimToSize(); @@ -1813,7 +1821,7 @@ @Override public Element visitArray(Array_element_value a, Element p) { - Element el = new Element("Array"); + Element el = new Element("Array"); for (Annotation.element_value v : a.values) { Element child = visit(v, el); if (child != null) {