diff --git a/jdk/make/data/jdwp/jdwp.spec b/jdk/make/data/jdwp/jdwp.spec index a144c896f92..bb1d21f92b9 100644 --- a/jdk/make/data/jdwp/jdwp.spec +++ b/jdk/make/data/jdwp/jdwp.spec @@ -2709,22 +2709,6 @@ JDWP "Java(tm) Debug Wire Protocol" (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 --git a/jdk/make/launcher/Launcher-jdk.jconsole.gmk b/jdk/make/launcher/Launcher-jdk.jconsole.gmk index aa07823c54a..6205ae63d16 100644 --- a/jdk/make/launcher/Launcher-jdk.jconsole.gmk +++ b/jdk/make/launcher/Launcher-jdk.jconsole.gmk @@ -27,7 +27,8 @@ include LauncherCommon.gmk $(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 --git a/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java index 5d212cd70ce..7aa02f365b9 100644 --- a/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java +++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java @@ -65,7 +65,7 @@ public class AddPackagesAttribute { 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 @@ public class AddPackagesAttribute { 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 --git a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java index 04badbd7f3d..bf0f03be6b3 100644 --- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java +++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java @@ -43,7 +43,7 @@ import java.util.Set; 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 @@ public class GenGraphs { 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 @@ public class GenGraphs { /** * 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 @@ public class GenGraphs { .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 --git a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java index 7fb8679a7e0..e55a1c04855 100644 --- a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java +++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java @@ -299,7 +299,7 @@ public class ModuleSummary { 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 class ModuleSummary { 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 @@ public class ModuleSummary { 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 @@ public class ModuleSummary { 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 --git a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java index e7d932d1141..368fcc7271a 100644 --- a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java +++ b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java @@ -30,219 +30,593 @@ import java.io.PrintWriter; 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. * - * The extra exports, uses, provides can be specified in module-info.java.extra - * files and GenModuleInfoSource will be invoked for each module that has + * 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); } + GenModuleInfoSource genModuleInfo = + new GenModuleInfoSource(moduleInfoJava, extras, modules); + // generate new module-info.java - genModuleInfo.generate(moduleInfoJava, outfile); + genModuleInfo.generate(outfile); } - 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() { - } + 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); - private void export(String p) { - Objects.requireNonNull(p); - if (exports.contains(p) || exportsTo.containsKey(p)) { - throw new RuntimeException("duplicated exports: " + p); + // 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); - } - - private void provide(String s, String impl) { - provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl); - } - - private void generate(Path sourcefile, Path outfile) throws IOException { - Path parent = outfile.getParent(); - if (parent != null) - Files.createDirectories(parent); - - List lines = Files.readAllLines(sourcefile); - try (BufferedWriter bw = Files.newBufferedWriter(outfile); + void generate(Path output) throws IOException { + List lines = Files.readAllLines(sourceFile); + try (BufferedWriter bw = Files.newBufferedWriter(output); PrintWriter writer = new PrintWriter(bw)) { - int lineNumber = 0; + // write the copyright header and lines up to module declaration 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 { - throw new RuntimeException(sourcefile + ", line " + - lineNumber + ", is malformed: " + s[2]); - } - } - - // inject the extra targets after "to" - if (inExportsTo) { - writer.println(injectExportTargets(exp, l, n)); - } else { - writer.println(l); - } - 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; + 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; } } + + // 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 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())); + + 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); + + 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"); + } + + 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; + } + + 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 { + // rest of the line + l = l.substring(index, l.length()).trim(); + index = 0; + } + } + + 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++; + } + } + } + + 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 --git a/jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java b/jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java new file mode 100644 index 00000000000..5554c71e1f8 --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java @@ -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 --git a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties index fa9ba74f047..14bc2ad8831 100644 --- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties +++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties @@ -15,12 +15,12 @@ pack.class.attribute.SourceID = RUH 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 --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java index 725d237aff6..700316e91ff 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -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.Set; import java.util.Map; -import java.util.HashMap; import java.util.Objects; +import java.util.Optional; +import java.util.Set; 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 @@ public final class Class implements java.io.Serializable, 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 @@ public final class Class implements java.io.Serializable, } // cached package name - private String packageName; + private transient String packageName; /** * Returns the interfaces directly implemented by the class or interface @@ -1976,6 +1974,22 @@ public final class Class implements java.io.Serializable, 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 @@ public final class Class implements java.io.Serializable, } /** - * 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 @@ public final class Class implements java.io.Serializable, * * * @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 final class Class implements java.io.Serializable, 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 @@ public final class Class implements java.io.Serializable, } /** - * 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 @@ public final class Class implements java.io.Serializable, * * * @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 @@ public final class Class implements java.io.Serializable, * if name is absolute */ private String resolveName(String name) { - if (name == null) { - return name; - } if (!name.startsWith("/")) { Class c = this; while (c.isArray()) { diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index 73fe154586d..0245d371077 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -42,15 +42,14 @@ import java.security.cert.Certificate; 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.Stream; 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 @@ public abstract class ClassLoader { this(checkCreateClassLoader(), null, parent); } - /** * Creates a new class loader using the ClassLoader returned by * the method {@link #getSystemClassLoader() @@ -431,7 +428,6 @@ public abstract class ClassLoader { 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 @@ public abstract class ClassLoader { * @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); @@ -596,34 +592,6 @@ public abstract class ClassLoader { } } - /** - * 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 @@ -724,12 +692,17 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * @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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * @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 @@ public abstract class ClassLoader { * (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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * (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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * @since 1.2 */ protected Enumeration findResources(String name) throws IOException { - return java.util.Collections.emptyEnumeration(); + return Collections.emptyEnumeration(); } /** @@ -1541,14 +1575,21 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { * {@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 @@ public abstract class ClassLoader { /** * 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { 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 --git a/jdk/src/java.base/share/classes/java/lang/Deprecated.java b/jdk/src/java.base/share/classes/java/lang/Deprecated.java index 2177694b24a..673401c8116 100644 --- a/jdk/src/java.base/share/classes/java/lang/Deprecated.java +++ b/jdk/src/java.base/share/classes/java/lang/Deprecated.java @@ -40,6 +40,11 @@ import static java.lang.annotation.ElementType.*; * 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 @@ import static java.lang.annotation.ElementType.*; */ @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 --git a/jdk/src/java.base/share/classes/java/lang/Package.java b/jdk/src/java.base/share/classes/java/lang/Package.java index b4ba45b8f35..5a19f9771f1 100644 --- a/jdk/src/java.base/share/classes/java/lang/Package.java +++ b/jdk/src/java.base/share/classes/java/lang/Package.java @@ -398,10 +398,16 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated 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 --git a/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java b/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java index 84017794166..1f4e0e0d95e 100644 --- a/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java +++ b/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java @@ -35,6 +35,9 @@ import static java.lang.annotation.ElementType.*; * 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 @@ import static java.lang.annotation.ElementType.*; * @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 --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 4bce8bbb48d..18620771d20 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -38,6 +38,7 @@ import java.lang.annotation.Annotation; 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.LazyLoggers; 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 @@ public final class System { 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 final class System { 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 --git a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template index d3c86a2befe..367103a13fc 100644 --- a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template +++ b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template @@ -123,27 +123,25 @@ class VersionProps { /** * 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 @@ class VersionProps { } /* 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 --git a/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java b/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java index c32ae6a0f15..14780fe6827 100644 --- a/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java +++ b/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java @@ -37,10 +37,10 @@ package java.lang.annotation; * 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 @@ public enum ElementType { * * @since 1.8 */ - TYPE_USE + TYPE_USE, + + /** + * Module declaration. + * + * @since 9 + */ + MODULE } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index e1fad4d7dbb..0c9da2c9e80 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -42,6 +42,7 @@ import java.lang.reflect.Field; 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; @@ -141,6 +142,59 @@ public class MethodHandles { } } + /** + * 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. @@ -1807,7 +1861,12 @@ return mh1; 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 --git a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java index d1efde87f50..9753569374d 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java +++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java @@ -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 @@ import java.util.stream.Collectors; * 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 @@ import java.util.stream.Collectors; *

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 @@ import java.util.stream.Collectors; *

{@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 @@ public final class Configuration { // @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 @@ public final class Configuration { * * @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 @@ public final class Configuration { * 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 @@ public final class Configuration { * * @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 @@ public final class Configuration { * 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 @@ public final class Configuration { /** - * 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 @@ public final class Configuration { /** * 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(); } @@ -443,10 +561,47 @@ public final class Configuration { return Collections.unmodifiableSet(graph.get(m)); } + /** + * 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index 60aeea6d85d..b527ffaeafb 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -45,6 +45,8 @@ import java.util.Objects; 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 @@ import jdk.internal.module.ModuleHashes; * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor private final String name; private Requires(Set ms, String mn) { - this(ms, mn, true); - } - private Requires(Set ms, String mn, boolean check) { - if (ms == null || ms.isEmpty()) { - mods = Collections.emptySet(); + if (ms.isEmpty()) { + ms = Collections.emptySet(); } else { - mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms)) - : ms; + ms = Collections.unmodifiableSet(EnumSet.copyOf(ms)); } - this.name = check ? requireModuleName(mn) : mn; + this.mods = ms; + this.name = mn; + } + + private Requires(Set ms, String mn, boolean unused) { + this.mods = ms; + this.name = mn; } /** @@ -223,9 +235,8 @@ public class ModuleDescriptor */ @Override public String toString() { - return Dependence.toString(mods, name); + return ModuleDescriptor.toString(mods, name); } - } @@ -239,36 +250,61 @@ public class ModuleDescriptor 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 @@ public class ModuleDescriptor /** * 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 @@ public class ModuleDescriptor 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 @@ public class ModuleDescriptor */ @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 class ModuleDescriptor 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 class ModuleDescriptor 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 @@ public class ModuleDescriptor */ @Override public int hashCode() { - return hash(service, providers); + return service.hashCode() * 43 + providers.hashCode(); } /** @@ -421,7 +617,7 @@ public class ModuleDescriptor * *

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 @@ public class ModuleDescriptor // 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 @@ public class ModuleDescriptor // 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 @@ public class ModuleDescriptor 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 @@ public class ModuleDescriptor { 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); - - 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); + assert (requires.stream().map(Requires::name).distinct().count() + == requires.size()); + this.requires = emptyOrUnmodifiableSet(requires); + 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 @@ public class ModuleDescriptor */ 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 @@ public class ModuleDescriptor } /** - * 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 uses, Set exports, - Map provides, + Set opens, + Set uses, + 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; } /** @@ -909,6 +1111,19 @@ public class ModuleDescriptor return name; } + /** + *

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.

* @@ -933,8 +1148,6 @@ public class ModuleDescriptor * * @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; @@ -949,6 +1162,33 @@ public class ModuleDescriptor return requires; } + /** + *

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.

* @@ -962,23 +1202,13 @@ public class ModuleDescriptor /** *

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. * @@ -1046,22 +1276,9 @@ public class ModuleDescriptor } /** - * 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 @@ public class ModuleDescriptor /** * 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")
-     *         .requires("m2")
+     * 

Example usage:

+ *
{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
      *         .exports("p")
+     *         .requires("m2")
      *         .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 @@ public class ModuleDescriptor /** * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * @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)); } /** @@ -1208,62 +1430,6 @@ public class ModuleDescriptor return requires(EnumSet.noneOf(Requires.Modifier.class), mn); } - /** - * 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. * @@ -1273,18 +1439,90 @@ public class ModuleDescriptor * @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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor } /** - * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor return this; } - /* package */ Builder synthetic(boolean v) { this.synthetic = v; return this; @@ -1609,16 +1988,24 @@ public class ModuleDescriptor * @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 exports = new HashSet<>(this.exports.values()); + Set opens = new HashSet<>(this.opens.values()); + + Set provides = new HashSet<>(this.provides.values()); - Set packages = new HashSet<>(conceals); - packages.addAll(exportedPackages()); return new ModuleDescriptor(name, + open, automatic, synthetic, requires, - uses, exports, + opens, + uses, provides, version, mainClass, @@ -1631,7 +2018,6 @@ public class ModuleDescriptor } - /** * Compares this module descriptor to another. * @@ -1689,11 +2075,13 @@ public class ModuleDescriptor return false; ModuleDescriptor that = (ModuleDescriptor)ob; return (name.equals(that.name) + && open == that.open && automatic == that.automatic && synthetic == that.synthetic && requires.equals(that.requires) - && uses.equals(that.uses) && exports.equals(that.exports) + && opens.equals(that.opens) + && uses.equals(that.uses) && provides.equals(that.provides) && Objects.equals(version, that.version) && Objects.equals(mainClass, that.mainClass) @@ -1720,11 +2108,13 @@ public class ModuleDescriptor 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 + uses.hashCode(); hc = hc * 43 + exports.hashCode(); + hc = hc * 43 + opens.hashCode(); + hc = hc * 43 + uses.hashCode(); hc = hc * 43 + provides.hashCode(); hc = hc * 43 + Objects.hashCode(version); hc = hc * 43 + Objects.hashCode(mainClass); @@ -1748,36 +2138,101 @@ public class ModuleDescriptor @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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor * 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 @@ public class ModuleDescriptor * * @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 @@ public class ModuleDescriptor } } + /** + * 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 @@ public class ModuleDescriptor */ 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(String source, Set targets) { - return new Exports(source, targets, false); + public Exports newExports(Set ms, String source) { + return new Exports(ms, source, Collections.emptySet(), true); } @Override - public Exports newExports(String source) { - return new Exports(source, false); + public Exports newExports(Set ms, + String source, + Set targets) { + return new Exports(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, + Set targets) { + return new Opens(ms, source, targets, true); + } + + @Override + 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 @@ public class ModuleDescriptor @Override public ModuleDescriptor newModuleDescriptor(String name, + boolean open, boolean automatic, boolean synthetic, Set requires, - Set uses, Set exports, - Map provides, + Set opens, + Set uses, + 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, - uses, exports, + opens, + uses, provides, version, mainClass, @@ -1975,7 +2464,14 @@ public class ModuleDescriptor osArch, osVersion, packages, - hashes); + hashes, + hashCode, + false); + } + + @Override + public Optional hashes(ModuleDescriptor descriptor) { + return descriptor.hashes(); } @Override @@ -1994,11 +2490,6 @@ public class ModuleDescriptor return new ModuleReference(descriptor, location, s, true, null); } - @Override - public Optional hashes(ModuleDescriptor descriptor) { - return descriptor.hashes(); - } - @Override public ModuleFinder newModulePath(Runtime.Version version, boolean isLinkPhase, diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java index 4e72a52cf22..4b98bf48416 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -233,10 +233,11 @@ public interface ModuleFinder { * 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java index 1d0e22fec11..b1c82819aa9 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java @@ -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.EOFException; 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 @@ import static jdk.internal.module.ClassFileConstants.*; 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 @@ final class ModuleInfo { { 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 @@ final class ModuleInfo { { 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 @@ final class ModuleInfo { /** * 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 @@ final class ModuleInfo { { 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 @@ final class ModuleInfo { 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 @@ final class ModuleInfo { // 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 @@ final class ModuleInfo { 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 @@ final class ModuleInfo { } // 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 @@ final class ModuleInfo { 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 @@ final class ModuleInfo { "LineNumberTable", "LocalVariableTable", "LocalVariableTypeTable", - "RuntimeVisibleAnnotations", - "RuntimeInvisibleAnnotations", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "RuntimeVisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", + "Synthetic", "AnnotationDefault", "BootstrapMethods", "MethodParameters"); @@ -495,7 +586,6 @@ final class ModuleInfo { private static volatile Set predefinedNotAllowed; - /** * The constant pool in a class file. */ @@ -628,6 +718,11 @@ final class ModuleInfo { 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 @@ final class ModuleInfo { 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java index fa40f3b7958..15df0307180 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java @@ -40,9 +40,10 @@ import java.nio.file.NoSuchFileException; 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.jar.Manifest; 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 @@ class ModulePath implements ModuleFinder { * * 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 @@ class ModulePath implements ModuleFinder { // 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 @@ class ModulePath implements ModuleFinder { 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 @@ class ModulePath implements ModuleFinder { // 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 @@ class ModulePath implements ModuleFinder { 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 @@ class ModulePath implements ModuleFinder { */ 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 @@ class ModulePath implements ModuleFinder { * 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java index 34d13639736..cbf84cf938d 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java @@ -60,8 +60,8 @@ public final class ModuleReference { // 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 @@ public final class ModuleReference { } /** - * 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 final class ModuleReference { 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 --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java index 8393bd0f223..e53ba0441d3 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java @@ -51,6 +51,7 @@ import java.util.zip.ZipFile; 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 @@ class ModuleReferences { 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 @@ class ModuleReferences { 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 @@ class ModuleReferences { 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 --git a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java index adc60da8892..5f716b131b7 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java +++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java @@ -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 @@ import jdk.internal.module.ModuleHashes; /** * 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 @@ final class Resolver { 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 @@ final class Resolver { // 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 @@ final class Resolver { // 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 @@ final class Resolver { 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 @@ final class Resolver { 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 @@ final class Resolver { } candidateConsumers = resolve(q); - } while (!candidateConsumers.isEmpty()); return this; @@ -429,21 +450,21 @@ final class Resolver { 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 @@ final class Resolver { } } + 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<>(); + Map> g1 = new HashMap<>(capacity); - // the "requires public" graph, contains requires public edges only - Map> g2 = new HashMap<>(); + // the "requires transitive" graph, contains requires transitive edges only + Map> g2; - - // need "requires public" from the modules in parent configurations as - // there may be selected modules that have a dependency on modules in + // 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. - - 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); + 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 @@ final class Resolver { 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 @@ final class Resolver { // 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 @@ final class Resolver { 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 @@ final class Resolver { = 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 @@ final class Resolver { // 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 @@ final class Resolver { } // 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 @@ final class Resolver { } + /** + * 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 @@ final class Resolver { 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 --git a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java index 9fae75cb382..6de8ce824cf 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java @@ -39,6 +39,7 @@ import java.util.HashMap; 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.ImageReader; 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 @@ import jdk.internal.perf.PerfCounter; * 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 @@ class SystemModuleFinder implements ModuleFinder { 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 @@ class SystemModuleFinder implements ModuleFinder { // 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 @@ class SystemModuleFinder implements ModuleFinder { 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 @@ class SystemModuleFinder implements ModuleFinder { 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 @@ class SystemModuleFinder implements ModuleFinder { * 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 @@ class SystemModuleFinder implements ModuleFinder { return new HashSupplier() { @Override - public String generate(String algorithm) { + public byte[] generate(String algorithm) { return hashes.get(name); } }; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java index 353870b37d8..a046a748f7c 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java @@ -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 @@ public class AccessibleObject implements AnnotatedElement { *

    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 @@ public class AccessibleObject implements AnnotatedElement { *

    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 @@ public class AccessibleObject implements AnnotatedElement { * @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 @@ public class AccessibleObject implements AnnotatedElement { 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; + // 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; - 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); - } - } + // 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 --git a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java index 6e220a5e43c..7466c57ae22 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java @@ -27,23 +27,29 @@ package java.lang.reflect; 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 @@ import sun.security.util.SecurityConstants; * 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 @@ import sun.security.util.SecurityConstants; * 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 @@ import sun.security.util.SecurityConstants; * 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 @@ public final class Layer { // 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 @@ public final class Layer { 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 @@ public final class Layer { *

      * *
    • 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 @@ public final class Layer { * * @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 @@ public final class Layer { * * @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 @@ public final class Layer { * * @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 @@ public final class Layer { * * @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 @@ public final class Layer { * * @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 @@ public final class Layer { } 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 @@ public final class Layer { } - 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 @@ public final class Layer { /** - * 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 @@ public final class Layer { /** * 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 @@ public final class Layer { * 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 @@ public final class Layer { * @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 @@ public final class Layer { 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 @@ public final class Layer { } 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 --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java index 26e47245f38..29f21cc0108 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java @@ -27,15 +27,18 @@ package java.lang.reflect; 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 java.util.stream.Stream; 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 @@ import sun.security.util.SecurityConstants; * @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 @@ public final class Module { // 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 @@ public final class Module { 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 @@ public final class Module { // -- - // 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 @@ public final class Module { } // 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 @@ public final class Module { * 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 @@ public final class Module { } // add reflective read - transientReads.putIfAbsent(this, other, Boolean.TRUE); + reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE); } - // -- exports -- + // -- exported and open packages -- - // the packages that are permanently exported - // (will be final when the modules are defined in reverse topology order) - private volatile Map> exports; + // 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; - // additional exports added at run-time - // this module (1st key), other module (2nd key), exported packages (value) + // 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 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 @@ public final class Module { * * @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); - - if ((targets != null) - && (targets.contains(other) || targets.contains(EVERYONE_MODULE))) - return true; + 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 (!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 @@ public final class Module { /** * 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 @@ public final class Module { * 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,17 +664,65 @@ public final class Module { 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 @@ public final class Module { 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 @@ public final class Module { * @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 @@ public final class Module { } } - // 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 @@ public final class Module { * 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 @@ public final class Module { * @see ModuleDescriptor#uses() */ @CallerSensitive - public Module addUses(Class st) { - Objects.requireNonNull(st); - - if (isNamed()) { + public Module addUses(Class service) { + Objects.requireNonNull(service); + 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 @@ public final class Module { 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 @@ public final class Module { * 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 @@ public final class Module { // -- 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 @@ public final class Module { 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 @@ public final class Module { 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 @@ public final class Module { } 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(); + // exports and opens + initExportsAndOpens(descriptor, nameToModule, m); + } + + // 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); + } + catalog.register(m); + } + } + } + + // record that there is a layer with modules defined to the class loader + for (ClassLoader loader : loaders) { + layer.bindToLoader(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; + } - if (export.isQualified()) { + Map> openPackages = new HashMap<>(); + Map> exportedPackages = new HashMap<>(); - // 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); + // 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); + } + } + if (!targets.isEmpty()) { + openPackages.put(source, targets); + } + } else { + // unqualified opens + addExportsToAll0(m, sourceInternalForm); + openPackages.put(source, EVERYONE_SET); + } + } + + // 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()) { - exports.put(source, targets); - } - - } else { - - // unqualified export - exports.put(source, EVERYONE); - addExportsToAll0(m, sourceInternalForm); } - } - m.exports = exports; - } - - // 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); + if (!targets.isEmpty()) { + exportedPackages.put(source, targets); } - catalog.register(m); + + } else { + // unqualified exports + addExportsToAll0(m, sourceInternalForm); + exportedPackages.put(source, EVERYONE_SET); } } - return modules; + 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 @@ public final class Module { /** - * 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. * - *

        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. + *

        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 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 @@ public final class Module { * * @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 @@ public final class Module { // JVM_DefineModule private static native void defineModule0(Module module, + boolean isOpen, String version, String location, String[] pns); @@ -1098,15 +1526,31 @@ public final class Module { } @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 final class Module { 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 --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java index 1d84e2dee6b..f04452664ff 100644 --- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java @@ -42,6 +42,7 @@ package java.util; 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.jar.JarEntry; 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 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * 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 abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { * 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 @@ public abstract class ResourceBundle { * 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 @@ public abstract class ResourceBundle { * 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 @@ public abstract class ResourceBundle { * 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 @@ public abstract class ResourceBundle { // 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 @@ public abstract class ResourceBundle { 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, - Locale locale, - ClassLoader loader, + private static ResourceBundle getBundleImpl(Module callerModule, Module module, + ClassLoader loader, + String baseName, + Locale locale, Control control) { if (locale == null || control == null) { throw new NullPointerException(); @@ -1661,7 +1702,8 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { * 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 @@ public abstract class ResourceBundle { * 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 @@ public abstract class ResourceBundle { /* * 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 @@ public abstract class ResourceBundle { 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 @@ public abstract class ResourceBundle { 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 --git a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java index 081b96158ff..0b437d44e2e 100644 --- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java @@ -32,23 +32,28 @@ import java.io.InputStreamReader; 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.AccessController; import java.security.AccessControlContext; +import java.security.AccessController; 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 @@ import jdk.internal.reflect.Reflection; * 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 @@ import jdk.internal.reflect.Reflection; * *

        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 @@ import jdk.internal.reflect.Reflection; 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 @@ public final class ServiceLoader // 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; - - - /** - * Clear this loader's provider cache so that all providers will be - * reloaded. - * - *

        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. - */ - public void reload() { - providers.clear(); - - assert layer == null || loader == null; - if (layer != null) { - layerLookupIterator = new LayerLookupIterator(); - } else { - providerNames.clear(); - moduleServicesIterator = new ModuleServicesIterator(); - lazyClassPathIterator = new LazyClassPathIterator(); - } - - reloadCount++; + private static JavaLangAccess LANG_ACCESS; + private static JavaLangReflectModuleAccess JLRM_ACCESS; + static { + LANG_ACCESS = SharedSecrets.getJavaLangAccess(); + JLRM_ACCESS = SharedSecrets.getJavaLangReflectModuleAccess(); } + /** + * 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.

        + * + * @param The service type + * @since 9 + */ + 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(); + + /** + * 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 @@ public final class ServiceLoader * 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) { + private ServiceLoader(Class caller, Class svc, ClassLoader cl) { + Objects.requireNonNull(svc); + if (VM.isBooted()) { - - checkModule(callerModule, svc); - + 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 @@ public final class ServiceLoader } 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 @@ public final class ServiceLoader 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); - } - return names.iterator(); - } - - /** - * 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. - */ - private static Constructor checkAndGetConstructor(Class c) - throws NoSuchMethodException, IllegalAccessException - { - Constructor ctor = c.getConstructor(); - - // 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"); - } - - // 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); + 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; + } } + if (clazz == null) + fail(service, "Provider " + cn + " not found"); + return clazz; } /** - * An Iterator that runs the next and hasNext methods with permissions - * restricted by the {@code AccessControlContext} obtained when the - * ServiceLoader was created. + * A Provider implementation that supports invoking, with reduced + * permissions, the static factory to obtain the provider or the + * provider's no-arg constructor. */ - private abstract class RestrictedIterator - implements Iterator - { - /** - * Returns {@code true} if the iteration has more elements. - */ - abstract boolean hasNextService(); + 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 /** - * Returns the next element in the iteration + * 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. */ - abstract S nextService(); + @SuppressWarnings("unchecked") + ProviderImpl(Class service, Class clazz, AccessControlContext acc) { + this.service = (Class) service; + this.acc = acc; - public final boolean hasNext() { - if (acc == null) { - return hasNextService(); + 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 { - PrivilegedAction action = new PrivilegedAction() { - public Boolean run() { return hasNextService(); } - }; - return AccessController.doPrivileged(action, acc); + this.type = (Class) factoryMethod.getReturnType(); + this.ctor = null; } } - public final S next() { - if (acc == null) { - return nextService(); + @Override + public Class type() { + return type; + } + + @Override + public S get() { + if (factoryMethod != null) { + return invokeFactoryMethod(); } else { - PrivilegedAction action = new PrivilegedAction() { - public S run() { return nextService(); } - }; - return AccessController.doPrivileged(action, acc); + return newInstance(); } } + + /** + * 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) { + try { + result = factoryMethod.invoke(null); + } catch (Throwable x) { + exc = x; + } + } else { + PrivilegedExceptionAction pa = new PrivilegedExceptionAction<>() { + @Override + public Object run() throws Exception { + return factoryMethod.invoke(null); + } + }; + // 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 (currentLoader == null) { + if (loader == null) { catalog = BootLoader.getServicesCatalog(); } else { - catalog = langAccess.getServicesCatalog(currentLoader); + catalog = ServicesCatalog.getServicesCatalogOrNull(loader); } + Stream stream1; if (catalog == null) { - return Collections.emptyIterator(); + stream1 = Stream.empty(); } else { - return catalog.findServices(service.getName()).iterator(); + stream1 = catalog.findServices(serviceName).stream(); } + + // modules in custom layers that define modules to the class loader + Stream stream2; + if (loader == null) { + stream2 = Stream.empty(); + } else { + Layer bootLayer = Layer.boot(); + stream2 = JLRM_ACCESS.layers(loader) + .filter(l -> (l != bootLayer)) + .map(l -> providers(l)) + .flatMap(List::stream); + } + + 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 @@ public final class ServiceLoader } @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 - @Override - boolean hasNextService() { - if (nextName != null) { + LazyClassPathLookupIterator() { } + + /** + * 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"); + + // throw any SCE with error recorded by hasNext + if (nextErrorMessage != null) { + String msg = nextErrorMessage; + nextErrorMessage = null; + fail(service, msg); } - if (!service.isAssignableFrom(c)) { - fail(service, - "Provider " + cn + " not a subtype"); + + // 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); } - 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); + } + + @Override + public Provider next() { + if (acc == null) { + return nextService(); + } else { + PrivilegedAction> action = new PrivilegedAction<>() { + public Provider run() { return nextService(); } + }; + return AccessController.doPrivileged(action, acc); } - providers.add(p); - providerNames.add(cn); - return p; } } /** - * 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 @@ public final class ServiceLoader * 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 @@ public final class ServiceLoader * 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 @@ public final class ServiceLoader 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; @@ -931,6 +1264,108 @@ public final class ServiceLoader }; } + /** + * 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 @@ public final class ServiceLoader * * @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 @@ public final class ServiceLoader * 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 @@ public final class ServiceLoader * * @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 @@ public final class ServiceLoader * *

        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 @@ public final class ServiceLoader * * @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 @@ public final class ServiceLoader * * @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 --git a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java index ba4cbdca200..06b6c266c89 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java @@ -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 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
          *         }
          *         return null;
          *     }
        - * }}
        + * }
  • * * @see * Resource Bundles in Named Modules @@ -73,6 +83,9 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * @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 @@ public abstract class AbstractResourceBundleProvider implements ResourceBundlePr /** * 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 @@ public abstract class AbstractResourceBundleProvider implements ResourceBundlePr */ 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 @@ public abstract class AbstractResourceBundleProvider implements ResourceBundlePr 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 @@ public abstract class AbstractResourceBundleProvider implements ResourceBundlePr } 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 --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java index 732248a377c..7885d8e180d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java @@ -71,8 +71,8 @@ public class BootLoader { 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 @@ public class BootLoader { } /** - * 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 @@ public class BootLoader { } /** - * 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 @@ public class BootLoader { /** * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java index e07559803fa..ab052ec0b30 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -29,8 +29,10 @@ import java.io.File; 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 @@ public class BuiltinClassLoader { static { if (!ClassLoader.registerAsParallelCapable()) - throw new InternalError(); + throw new InternalError("Unable to register as parallel capable"); } // parent ClassLoader @@ -117,7 +119,7 @@ public class BuiltinClassLoader 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 @@ public class BuiltinClassLoader // 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 @@ public class BuiltinClassLoader * 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 @@ public class BuiltinClassLoader */ @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 = null; - URL url; - - 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,69 +227,233 @@ public class BuiltinClassLoader { // 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); } } - return Collections.enumeration(result); // checked URLs + } else { - return Collections.emptyEnumeration(); + // 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); + } + } + } + + // 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 @@ public class BuiltinClassLoader } /** - * 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; } /** @@ -440,6 +605,21 @@ public class BuiltinClassLoader return packageToModule.get(pn); } + /** + * 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. @@ -447,8 +627,12 @@ public class BuiltinClassLoader * @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 @@ public class BuiltinClassLoader * @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 @@ public class BuiltinClassLoader } return null; } - }); + }; + return AccessController.doPrivileged(pa); + } } /** @@ -662,13 +859,13 @@ public class BuiltinClassLoader sealBase = url; } return definePackage(pn, - specTitle, - specVersion, - specVendor, - implTitle, - implVersion, - implVendor, - sealBase); + specTitle, + specVersion, + specVendor, + implTitle, + implVersion, + implVendor, + sealBase); } /** @@ -759,6 +956,27 @@ public class BuiltinClassLoader } }; + /** + * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java index 8b2e257d7b8..04285cc4cf1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java @@ -48,13 +48,19 @@ import java.security.PrivilegedAction; 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 @@ public final class Loader extends SecureClassLoader { 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 @@ public final class Loader extends SecureClassLoader { LoaderPool pool, ClassLoader parent) { - super(parent); + super("Loader-" + resolvedModule.name(), parent); this.pool = pool; this.parent = parent; @@ -200,12 +206,12 @@ public final class Loader extends SecureClassLoader { * @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 @@ public final class Loader extends SecureClassLoader { } 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 @@ public final class Loader extends SecureClassLoader { throw new IllegalArgumentException("Package " + pn + " cannot be imported from multiple loaders"); } - } } } @@ -278,6 +281,17 @@ public final class Loader extends SecureClassLoader { return this; } + /** + * 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 @@ public final class Loader extends SecureClassLoader { */ @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 @@ public final class Loader extends SecureClassLoader { 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 @@ public final class Loader extends SecureClassLoader { } } + /** + * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java index a9bbc26a54b..14b088c14a9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java @@ -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 @@ public final class LoaderPool { * 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 @@ public final class LoaderPool { this.loaders = loaders; // complete the initialization - loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer)); + loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayers)); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java new file mode 100644 index 00000000000..a9e0750391a --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java @@ -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 --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java index f9699f7fdc1..6838111c35d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java @@ -29,6 +29,7 @@ import java.io.IOException; 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.Map; 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); @@ -135,17 +143,6 @@ public interface JavaLangAccess { */ 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 --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java index d19579212dd..d0b1c19232f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java @@ -27,24 +27,26 @@ package jdk.internal.misc; 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 @@ import java.util.function.Supplier; 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 @@ public interface JavaLangModuleAccess { * Returns a new {@code ModuleDescriptor} instance. */ ModuleDescriptor newModuleDescriptor(String name, + boolean open, boolean automatic, boolean synthetic, Set requires, - Set uses, Set exports, - Map provides, + Set opens, + Set uses, + 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 --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java index 33c86cf410b..55772793111 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java @@ -29,6 +29,7 @@ import java.lang.module.ModuleDescriptor; import java.lang.reflect.Layer; import java.lang.reflect.Module; import java.net.URI; +import java.util.stream.Stream; import jdk.internal.module.ServicesCatalog; @@ -70,16 +71,37 @@ public interface JavaLangReflectModuleAccess { */ 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. */ @@ -90,4 +112,15 @@ public interface JavaLangReflectModuleAccess { */ 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 --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java index ab76a58e663..b137c3d48c4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java @@ -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 @@ public interface JavaUtilResourceBundleAccess { * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java index d16ce84d3aa..36514cb1065 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java @@ -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 class SharedSecrets { } public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() { + if (javaUtilResourceBundleAccess == null) + unsafe.ensureClassInitialized(ResourceBundle.class); return javaUtilResourceBundleAccess; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java index fa4e752cc45..961dd08f28e 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java @@ -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 @@ package jdk.internal.module; 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 @@ import jdk.internal.misc.SharedSecrets; /** * 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 @@ final class Builder { 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 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 opens(Opens[] opens) { + this.opens = Set.of(opens); + return this; + } + + /** + * Sets module requires. + */ + 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 @@ final class Builder { } /** - * Adds an export to a set of target modules. + * Sets module provides. */ - 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. - */ - 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 @@ final class Builder { /** * 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 @@ final class Builder { /** * 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, - uses, exports, + opens, + uses, provides, version, mainClass, @@ -283,6 +317,7 @@ final class Builder { osArch, osVersion, packages, - moduleHashes); + moduleHashes, + hashCode); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java index 1738bfeba8e..9f02048b5c8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java @@ -25,7 +25,6 @@ package jdk.internal.module; - public final class Checks { private Checks() { } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java index 73a44c8735c..908b137eb5a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java @@ -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 @@ package jdk.internal.module; 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 @@ import static jdk.internal.module.ClassFileConstants.*; * class file attributes in a module-info class file. */ -class ClassFileAttributes { +public final class ClassFileAttributes { private ClassFileAttributes() { } @@ -60,16 +63,18 @@ class ClassFileAttributes { * // 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 @@ class ClassFileAttributes { 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 @@ class ClassFileAttributes { 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 @@ class ClassFileAttributes { 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 @@ class ClassFileAttributes { 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 @@ class ClassFileAttributes { 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 @@ class ClassFileAttributes { } /** - * 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 @@ class ClassFileAttributes {
          *
          * }
    */ - 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 @@ class ClassFileAttributes { off += 2; } - return new ConcealedPackagesAttribute(packages); + return new ModulePackagesAttribute(packages); } @Override @@ -348,13 +435,13 @@ class ClassFileAttributes { } /** - * 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 @@ class ClassFileAttributes {
          *
          * } 
    */ - 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 @@ class ClassFileAttributes { 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 @@ class ClassFileAttributes { } /** - * 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 @@ class ClassFileAttributes {
          *
          * } 
    */ - 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 @@ class ClassFileAttributes { Label[] labels) { String value = cr.readClass(off, buf); - return new MainClassAttribute(value); + return new ModuleMainClassAttribute(value); } @Override @@ -458,13 +545,13 @@ class ClassFileAttributes { } /** - * 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 @@ class ClassFileAttributes {
          *
          * } 
    */ - 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 @@ class ClassFileAttributes { osVersion = cr.readUTF8(off, buf); off += 2; - return new TargetPlatformAttribute(osName, osArch, osVersion); + return new ModuleTargetAttribute(osName, osArch, osVersion); } @Override @@ -554,39 +641,37 @@ class ClassFileAttributes { } /** - * 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 @@ class ClassFileAttributes { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java index 6a61f090e30..bf8955c1cff 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java @@ -35,19 +35,20 @@ public class ClassFileConstants { // 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index cacb97978f3..1a00edec548 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -37,9 +37,11 @@ import java.lang.reflect.Module; 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,9 +83,19 @@ public final class ModuleBootstrap { // 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 */ @@ -101,7 +113,7 @@ public final class ModuleBootstrap { long t0 = System.nanoTime(); - // system modules + // system modules (may be patched) ModuleFinder systemModules = ModuleFinder.ofSystem(); PerfCounters.systemModulesTime.addElapsedTimeFrom(t0); @@ -247,7 +259,7 @@ public final class ModuleBootstrap { if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here && (upgradeModulePath == null) && (appModulePath == null) - && (!ModulePatcher.isBootLayerPatched())) { + && (patcher.isEmpty())) { needPostResolutionChecks = false; } @@ -314,9 +326,9 @@ public final class ModuleBootstrap { 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 @@ public final class ModuleBootstrap { } } + + /** + * 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 @@ public final class ModuleBootstrap { for (String s : value.split(",")) { if (s.length() > 0) modules.add(s); } - index++; value = getAndRemoveProperty(prefix + index); } @@ -423,9 +446,11 @@ public final class ModuleBootstrap { 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 @@ public final class ModuleBootstrap { 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) { - // decode the command line options - Map> map = decode("jdk.module.addexports."); + // --add-exports + String prefix = "jdk.module.addexports."; + Map> extraExports = decode(prefix); + if (!extraExports.isEmpty()) { + addExtraExportsOrOpens(bootLayer, extraExports, false); + } - for (Map.Entry> e : map.entrySet()) { + // --add-opens + prefix = "jdk.module.addopens."; + Map> extraOpens = decode(prefix); + if (!extraOpens.isEmpty()) { + addExtraExportsOrOpens(bootLayer, extraOpens, true); + } + } + + 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 @@ public final class ModuleBootstrap { } } 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 @@ public final class ModuleBootstrap { 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); } @@ -557,6 +611,14 @@ public final class ModuleBootstrap { return map; } + /** + * 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 */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java index 2012c78c4fd..107305e0c79 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java @@ -32,7 +32,6 @@ import java.nio.channels.FileChannel; 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 @@ import java.util.Set; 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 @@ public final class ModuleHashes { } /** - * 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 @@ public final class ModuleHashes { } } - 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 @@ public final class ModuleHashes { * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java index 3c44964ba12..07bb40205cf 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java @@ -53,8 +53,8 @@ public final class ModuleInfoExtender { // 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 @@ public final class ModuleInfoExtender { } /** - * 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 @@ public final class ModuleInfoExtender { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java index a8dda9b8d57..5e4efff1486 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java @@ -27,9 +27,8 @@ package jdk.internal.module; 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 @@ public final class ModuleInfoWriter { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index afee8bf3c36..97966bd0012 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -50,6 +50,7 @@ import java.util.Optional; 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 @@ import sun.net.www.ParseUtil; /** - * 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 @@ public final class ModulePatcher { 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 @@ public final class ModulePatcher { } + /** + * Returns true is this module patcher has no patches. + */ + public boolean isEmpty() { + return map.isEmpty(); + } + /** * A ModuleReader that reads resources from a patched module. @@ -568,13 +533,6 @@ public final class ModulePatcher { } } - /** - * 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. */ @@ -593,9 +551,4 @@ public final class ModulePatcher { System.err.println("WARNING: " + e + " ignored in patch: " + file); return ""; } - - private static void throwIAE(String msg) { - throw new IllegalArgumentException(msg); - } - } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java index 9a0248a52df..9f68cfbc421 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java @@ -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.loader.ClassLoaders; 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 @@ public class Modules { 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 @@ public class Modules { /** * 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 @@ public class Modules { 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,12 +106,20 @@ public class Modules { /** * 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. */ @@ -117,6 +127,13 @@ public class Modules { JLRMA.addExportsToAll(m, pn); } + /** + * 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. */ @@ -124,6 +141,47 @@ public class Modules { JLRMA.addExportsToAllUnnamed(m, pn); } + /** + * 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. * @@ -142,5 +200,4 @@ public class Modules { addReads(m, BootLoader.getUnnamedModule()); addReads(m, ClassLoaders.appClassLoader().getUnnamedModule()); } - } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java index 92b80581d3c..d4425aadbb8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java @@ -28,20 +28,24 @@ package jdk.internal.module; 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 @@ public interface ServicesCatalog { } } - /** - * 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 */ - static ServicesCatalog create() { - return new ServicesCatalog() { - - private Map> map = new ConcurrentHashMap<>(); - - @Override - public void register(Module m) { - ModuleDescriptor descriptor = m.getDescriptor(); - - for (Provides provides : descriptor.provides().values()) { - String service = provides.service(); - Set providerNames = provides.providers(); - - // 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)); - } - - } - - @Override - public Set findServices(String service) { - return map.getOrDefault(service, Collections.emptySet()); - } - - }; + public static ServicesCatalog create() { + return new ServicesCatalog(); } + + /** + * Returns the list of service provides for the given service type + * name, creating it if needed. + */ + 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; + } + + /** + * 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); + } + } + } + + /** + * 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); + } + + /** + * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java index 78619f09f4d..299c6220450 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java @@ -51,7 +51,7 @@ public final class SystemModules { /** * 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 --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java index 2e3d62b0369..a577f933270 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -695,7 +695,7 @@ public class ClassWriter extends ClassVisitor { 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 --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index b97c5f6da8c..0c4cb744578 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -112,10 +112,13 @@ public class Reflection { } } - 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 --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 0e4c0354ee2..0d6402fe7d2 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -115,16 +115,16 @@ module java.base { // 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 @@ module java.base { 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 @@ module java.base { // 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 @@ module java.base { provides java.nio.file.spi.FileSystemProvider with jdk.internal.jrtfs.JrtFileSystemProvider; + provides sun.security.util.AuthResourcesProvider with + sun.security.util.AuthResourcesProviderImpl; } diff --git a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 45e781b9b4a..ba4ac2362ba 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -48,6 +48,7 @@ import java.lang.module.ModuleReference; 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.Files; 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 @@ public final class LauncherHelper { 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 @@ public final class LauncherHelper { 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 @@ public final class LauncherHelper { 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 @@ public final class LauncherHelper { 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 @@ public final class LauncherHelper { 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)); - - Map provides = md.provides(); - for (Provides ps : provides.values()) { - for (String impl : ps.providers()) - ostream.format(" provides %s with %s%n", ps.service(), impl); + // 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(); } + + // 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 --git a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties index f66bfa92461..4fd4346a5bc 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -28,8 +28,8 @@ java.launcher.opt.header = Usage: {0} [options] class [args...]\n\ \ (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 @@ java.launcher.opt.footer =\ -cp ...|:]\n\ \ -enableassertions[:...|:]\n\ \ enable assertions with specified granularity\n\ @@ -98,14 +103,12 @@ java.launcher.opt.footer =\ -cp 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 @@ java.launcher.X.usage=\ \ 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 --git a/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java new file mode 100644 index 00000000000..126286a6ff1 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java @@ -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 --git a/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java new file mode 100644 index 00000000000..6572ad0113d --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java @@ -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 --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java deleted file mode 100644 index 114a7fa63c7..00000000000 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java +++ /dev/null @@ -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 --git a/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java index 5966bb59acc..a62f90469d0 100644 --- a/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java +++ b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java @@ -58,8 +58,6 @@ import java.util.concurrent.ConcurrentMap; 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 @@ public abstract class Bundles { 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 --git a/jdk/src/java.base/share/native/include/jni.h b/jdk/src/java.base/share/native/include/jni.h index dc86df3d0b1..e29bf04b4cc 100644 --- a/jdk/src/java.base/share/native/include/jni.h +++ b/jdk/src/java.base/share/native/include/jni.h @@ -770,12 +770,6 @@ struct JNINativeInterface_ { 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 @@ struct JNIEnv_ { 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 --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 3d7fd391c25..848fe83d240 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -402,8 +402,8 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, */ 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 @@ JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); 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 @@ JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); 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 --git a/jdk/src/java.base/share/native/libjava/Module.c b/jdk/src/java.base/share/native/libjava/Module.c index c31491e5036..cb6057a5f86 100644 --- a/jdk/src/java.base/share/native/libjava/Module.c +++ b/jdk/src/java.base/share/native/libjava/Module.c @@ -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 --git a/jdk/src/java.base/share/native/libjli/java.c b/jdk/src/java.base/share/native/libjli/java.c index 914dbb4a7b7..d3f05a60d4b 100644 --- a/jdk/src/java.base/share/native/libjli/java.c +++ b/jdk/src/java.base/share/native/libjli/java.c @@ -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 @@ IsModuleOption(const char* name) { 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 @@ SetJvmEnvironment(int argc, char **argv) { 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 @@ ParseArguments(int *pargc, char ***pargv, } 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 @@ ParseArguments(int *pargc, char ***pargv, /* * 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 @@ ParseArguments(int *pargc, char ***pargv, } 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 @@ PrintJavaVersion(JNIEnv *env, jboolean extraLF) 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(JNIEnv *env, char *optString) "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 @@ PrintUsage(JNIEnv* env, jboolean doXUsage) 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 @@ PrintUsage(JNIEnv* env, jboolean doXUsage) } /* 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 @@ JLI_ReportMessage(const char* fmt, ...) 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 --git a/jdk/src/java.base/share/native/libjli/java.h b/jdk/src/java.base/share/native/libjli/java.h index 189bffc5285..81f86a04fe3 100644 --- a/jdk/src/java.base/share/native/libjli/java.h +++ b/jdk/src/java.base/share/native/libjli/java.h @@ -140,6 +140,9 @@ void JLI_ReportErrorMessageSys(const char * message, ...); /* 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 --git a/jdk/src/java.compact1/share/classes/module-info.java b/jdk/src/java.compact1/share/classes/module-info.java index 112c71b66e0..72d4357759a 100644 --- a/jdk/src/java.compact1/share/classes/module-info.java +++ b/jdk/src/java.compact1/share/classes/module-info.java @@ -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 --git a/jdk/src/java.compact2/share/classes/module-info.java b/jdk/src/java.compact2/share/classes/module-info.java index b19902435d7..0666be8fc10 100644 --- a/jdk/src/java.compact2/share/classes/module-info.java +++ b/jdk/src/java.compact2/share/classes/module-info.java @@ -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 --git a/jdk/src/java.compact3/share/classes/module-info.java b/jdk/src/java.compact3/share/classes/module-info.java index 05f33c0da0e..9783a406a54 100644 --- a/jdk/src/java.compact3/share/classes/module-info.java +++ b/jdk/src/java.compact3/share/classes/module-info.java @@ -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 --git a/jdk/src/java.desktop/share/classes/module-info.java b/jdk/src/java.desktop/share/classes/module-info.java index 0a49c8b981c..bb7abf11909 100644 --- a/jdk/src/java.desktop/share/classes/module-info.java +++ b/jdk/src/java.desktop/share/classes/module-info.java @@ -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 @@ module java.desktop { 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 @@ module java.desktop { 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 --git a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java index 6ac092ed32e..0b175c35b6b 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java +++ b/jdk/src/java.desktop/share/classes/sun/font/SunFontManager.java @@ -362,6 +362,14 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE { }); } + /** + * 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 --git a/jdk/src/java.base/share/classes/java/lang/module/Dependence.java b/jdk/src/java.desktop/share/classes/sun/font/lookup/JDKFontLookup.java similarity index 68% rename from jdk/src/java.base/share/classes/java/lang/module/Dependence.java rename to jdk/src/java.desktop/share/classes/sun/font/lookup/JDKFontLookup.java index 24538c056d6..83af637cfb0 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/Dependence.java +++ b/jdk/src/java.desktop/share/classes/sun/font/lookup/JDKFontLookup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,23 +23,17 @@ * questions. */ -package java.lang.module; +package sun.font.lookup; -import java.util.*; -import java.util.stream.*; +import sun.font.SunFontManager; +/** + * Implementation-class accessed by other JDK modules to + * locate the JDK-provided fonts. + */ +public final class JDKFontLookup { -class Dependence { - - private Dependence() { } - - static Stream toStringStream(Set s) { - return s.stream().map(e -> e.toString().toLowerCase()); + public final static String getJDKFontDir() { + return SunFontManager.getJDKFontDir(); } - - static String toString(Set mods, String what) { - return (Stream.concat(toStringStream(mods), Stream.of(what))) - .collect(Collectors.joining(" ")); - } - } diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java index eef1b6e83db..97986c2e610 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java @@ -27,6 +27,9 @@ package java.lang.instrument; 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 @@ public interface Instrumentation { 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. * - * 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}. + *

    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.

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

    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.

    + * + *

    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 --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html index c1f6c852982..e7f8d8f6996 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html @@ -277,15 +277,6 @@ the Agent-Class attribute specifies the name of the agent class

    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 --git a/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java b/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java index 80c2e7433b8..b2c2a24e50d 100644 --- a/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java +++ b/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java @@ -29,18 +29,23 @@ package sun.instrument; 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.Objects; +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 jdk.internal.module.Modules; + /* * Copyright 2003 Wily Technology, Inc. */ @@ -228,10 +233,100 @@ public class InstrumentationImpl implements Instrumentation { } @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 --git a/jdk/src/java.logging/share/classes/java/util/logging/Level.java b/jdk/src/java.logging/share/classes/java/util/logging/Level.java index f7f7a4380be..98597d3c677 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/Level.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/Level.java @@ -40,6 +40,8 @@ import java.util.Optional; 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 @@ import jdk.internal.loader.ClassLoaderValue; */ 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 @@ public class Level implements java.io.Serializable { // 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 --git a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java index b196283a6bd..dce8c4c7f2d 100644 --- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java +++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java @@ -38,6 +38,9 @@ import java.util.Objects; 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 @@ public class Logger { 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 @@ public class Logger { 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 @@ public class Logger { // 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 --git a/jdk/src/java.management/share/classes/module-info.java b/jdk/src/java.management/share/classes/module-info.java index 54ccb16107a..705e3ef2098 100644 --- a/jdk/src/java.management/share/classes/module-info.java +++ b/jdk/src/java.management/share/classes/module-info.java @@ -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 --git a/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java b/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java index 2de0e00758b..c53f4e2b519 100644 --- a/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java +++ b/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java @@ -625,26 +625,6 @@ public abstract class MappedMXBeanType { // 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 --git a/jdk/src/java.se.ee/share/classes/module-info.java b/jdk/src/java.se.ee/share/classes/module-info.java index d611f5ef522..6e2bc056afa 100644 --- a/jdk/src/java.se.ee/share/classes/module-info.java +++ b/jdk/src/java.se.ee/share/classes/module-info.java @@ -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 --git a/jdk/src/java.se/share/classes/module-info.java b/jdk/src/java.se/share/classes/module-info.java index 26aeb030675..3894c4fe43b 100644 --- a/jdk/src/java.se/share/classes/module-info.java +++ b/jdk/src/java.se/share/classes/module-info.java @@ -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 --git a/jdk/src/java.sql.rowset/share/classes/module-info.java b/jdk/src/java.sql.rowset/share/classes/module-info.java index 8d24418b6f2..b2c27bc40cb 100644 --- a/jdk/src/java.sql.rowset/share/classes/module-info.java +++ b/jdk/src/java.sql.rowset/share/classes/module-info.java @@ -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 --git a/jdk/src/java.sql/share/classes/module-info.java b/jdk/src/java.sql/share/classes/module-info.java index 70764a06d73..14491db0b56 100644 --- a/jdk/src/java.sql/share/classes/module-info.java +++ b/jdk/src/java.sql/share/classes/module-info.java @@ -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 --git a/jdk/src/java.transaction/share/classes/module-info.java b/jdk/src/java.transaction/share/classes/module-info.java index 84daf74a27d..4e245123b4b 100644 --- a/jdk/src/java.transaction/share/classes/module-info.java +++ b/jdk/src/java.transaction/share/classes/module-info.java @@ -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 --git a/jdk/src/java.xml.crypto/share/classes/module-info.java b/jdk/src/java.xml.crypto/share/classes/module-info.java index 62694bba195..4bd55f98b59 100644 --- a/jdk/src/java.xml.crypto/share/classes/module-info.java +++ b/jdk/src/java.xml.crypto/share/classes/module-info.java @@ -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 --git a/jdk/src/jdk.accessibility/share/classes/module-info.java b/jdk/src/jdk.accessibility/share/classes/module-info.java index e72b5b7efb5..5f0b63f94bc 100644 --- a/jdk/src/jdk.accessibility/share/classes/module-info.java +++ b/jdk/src/jdk.accessibility/share/classes/module-info.java @@ -24,7 +24,7 @@ */ module jdk.accessibility { - requires public java.desktop; + requires transitive java.desktop; exports com.sun.java.accessibility.util; } diff --git a/jdk/src/jdk.attach/share/classes/module-info.java b/jdk/src/jdk.attach/share/classes/module-info.java index a6f7a7e9937..6cb8c007fd6 100644 --- a/jdk/src/jdk.attach/share/classes/module-info.java +++ b/jdk/src/jdk.attach/share/classes/module-info.java @@ -23,6 +23,9 @@ * questions. */ +/** + * Defines the attach API. + */ module jdk.attach { requires jdk.jvmstat; diff --git a/jdk/src/jdk.desktop/share/classes/module-info.java b/jdk/src/jdk.desktop/share/classes/module-info.java index d02b6b4626c..2aac00da299 100644 --- a/jdk/src/jdk.desktop/share/classes/module-info.java +++ b/jdk/src/jdk.desktop/share/classes/module-info.java @@ -28,7 +28,7 @@ */ module jdk.desktop { - requires public java.desktop; + requires transitive java.desktop; exports jdk.awt; } diff --git a/jdk/src/jdk.internal.le/share/classes/module-info.java b/jdk/src/jdk.internal.le/share/classes/module-info.java index d52b3b5f98d..db859df2a8c 100644 --- a/jdk/src/jdk.internal.le/share/classes/module-info.java +++ b/jdk/src/jdk.internal.le/share/classes/module-info.java @@ -23,6 +23,9 @@ * questions. */ +/** + * Internal API for line editing + */ module jdk.internal.le { exports jdk.internal.jline to jdk.scripting.nashorn.shell, diff --git a/jdk/src/jdk.internal.opt/share/classes/module-info.java b/jdk/src/jdk.internal.opt/share/classes/module-info.java index dc5d39b6453..be862b7d532 100644 --- a/jdk/src/jdk.internal.opt/share/classes/module-info.java +++ b/jdk/src/jdk.internal.opt/share/classes/module-info.java @@ -23,6 +23,9 @@ * questions. */ +/** + * Internal option processing API + */ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell; } diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 28e0752fe0a..566b99ba0f3 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -30,6 +30,7 @@ import java.lang.module.Configuration; 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 java.text.MessageFormat; 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 @@ class Main { 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 @@ class Main { 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 @@ class Main { 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 @@ class Main { } 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 @@ class Main { 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 @@ class Main { } } + /* + * 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 @@ class Main { 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 @@ class Main { } 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 @@ class Main { 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 @@ class Main { // 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 @@ class Main { 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 @@ class Main { { 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 @@ class Main { .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 @@ class Main { { 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 @@ class Main { 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 @@ class Main { 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 @@ class Main { 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 @@ class Main { 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 --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties index d43231e21d2..7e2f6e6a164 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties @@ -67,14 +67,16 @@ error.versioned.info.without.root=\ 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 @@ error.release.value.notnumber=\ 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.incompatible.class.version=\ 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 --git a/jdk/src/jdk.jconsole/share/classes/module-info.java b/jdk/src/jdk.jconsole/share/classes/module-info.java index 6dfeca0f91e..bd10ffb739d 100644 --- a/jdk/src/jdk.jconsole/share/classes/module-info.java +++ b/jdk/src/jdk.jconsole/share/classes/module-info.java @@ -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 --git a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java index 4c9d421da27..88c5129f4b9 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java @@ -30,17 +30,17 @@ package com.sun.jdi; * 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 @@ public interface ModuleReference extends ObjectReference { * @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 --git a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java index 6c32368d18e..da5ffb2aab4 100644 --- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java +++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java @@ -75,15 +75,4 @@ class ModuleReferenceImpl extends ObjectReferenceImpl implements ModuleReference } 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 --git a/jdk/src/jdk.jdi/share/classes/module-info.java b/jdk/src/jdk.jdi/share/classes/module-info.java index a7bd83d6fc2..0dd61c61c49 100644 --- a/jdk/src/jdk.jdi/share/classes/module-info.java +++ b/jdk/src/jdk.jdi/share/classes/module-info.java @@ -23,6 +23,9 @@ * questions. */ +/** + * Defines the Java Debugger Interface. + */ module jdk.jdi { requires jdk.attach; requires jdk.jdwp.agent; @@ -37,10 +40,11 @@ module jdk.jdi { 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 --git a/jdk/src/jdk.jdi/windows/classes/module-info.java.extra b/jdk/src/jdk.jdi/windows/classes/module-info.java.extra index d048daa7438..e438e2c5260 100644 --- a/jdk/src/jdk.jdi/windows/classes/module-info.java.extra +++ b/jdk/src/jdk.jdi/windows/classes/module-info.java.extra @@ -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 --git a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java index c456bbc0099..ee7a047fa3f 100644 --- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java +++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java @@ -23,6 +23,9 @@ * questions. */ +/** + * Java Debug Wire Protocol. + */ module jdk.jdwp.agent { } diff --git a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c index 20cd986cd60..047796421a7 100644 --- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c +++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c @@ -83,36 +83,8 @@ getClassLoader(PacketInputStream *in, PacketOutputStream *out) 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index bf7e9e03e55..ecf19a69700 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -29,6 +29,7 @@ import java.io.IOException; 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 @@ public class JlinkTask { 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 @@ public class JlinkTask { ImageProvider imageProvider = createImageProvider(finder, config.getModules(), - config.getLimitmods(), config.getByteOrder(), null, IGNORE_SIGNING_DEFAULT); @@ -291,23 +292,43 @@ public class JlinkTask { 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 @@ public class JlinkTask { } 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 @@ public class JlinkTask { * 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 @@ public class JlinkTask { 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java index 11af53af6c1..63ce3cd7593 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java @@ -50,24 +50,23 @@ final class ResourcePoolConfiguration { 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java index 6647df0dff2..06e7bce13cc 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java @@ -35,6 +35,7 @@ import java.util.Optional; 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 @@ public class ResourcePoolManager { 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 @@ public class ResourcePoolManager { .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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java index 0d2adf63221..a7dd9278ffb 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java @@ -118,7 +118,7 @@ public final class AppRuntimeImageBuilder { 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java index 7dd77feb4f5..6be8c5f2acf 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java @@ -28,17 +28,18 @@ import java.io.ByteArrayInputStream; 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.MethodVisitor; 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 @@ import jdk.tools.jlink.plugin.ResourcePoolEntry; * @see SystemModules */ public final class SystemModuleDescriptorPlugin implements Plugin { - private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); + private static final JavaLangModuleAccess JLMA = + SharedSecrets.getJavaLangModuleAccess(); + + private static final String NAME = "system-modules"; + private static final String DESCRIPTION = + PluginsResourceBundle.getDescription(NAME); - // 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 boolean enabled; - public SystemModuleDescriptorPlugin() { this.enabled = true; } @@ -106,39 +106,38 @@ public final class SystemModuleDescriptorPlugin implements Plugin { } } - @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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { }); // 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { } /* - * 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { } /** - * 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<>(); - // map Set to a specialized builder to allow them to be - // deduplicated as they are requested - private final Map, StringSetBuilder> stringSets = new HashMap<>(); + // module name to index in MODULES_TO_HASH + private final Map modulesToHashIndex = new HashMap<>(); - public Builder() { - this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES); + // 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 SystemModulesClassGenerator() { + this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); + } + + private int getNextLocalVar() { + return nextLocalVar++; } /* @@ -270,16 +286,16 @@ public final class SystemModuleDescriptorPlugin implements Plugin { */ 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { // 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { } /* - * 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { } 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { 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) - */ - void requires(String name) { - mv.visitVarInsn(ALOAD, BUILDER_VAR); - mv.visitLdcInsn(name); - 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); - } - - /* - * Invoke Builder.requires(Set mods, String mn) + * Call Builder::newRequires to create Requires instances and + * then pass it to the builder by calling: + * Builder.requires(Requires[]) * - * EnumSet mods = EnumSet.of(mod,....); - * Buidler.requires(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;"; + void requires(Set requires) { + mv.visitVarInsn(ALOAD, BUILDER_VAR); + 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); } - 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); - mv.visitLdcInsn(name); mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "requires", SET_STRING_SIG, false); - mv.visitInsn(POP); + "requires", REQUIRES_ARRAY_SIG, false); } /* - * Invoke Builder.exports(String pn) + * Invoke Builder.newRequires(Set mods, String mn) + * + * Set mods = ... + * Builder.newRequires(mods, mn); */ - void exports(String pn) { - mv.visitVarInsn(ALOAD, BUILDER_VAR); - - mv.visitLdcInsn(pn); - mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER, - "exports", STRING_SIG, false); - mv.visitInsn(POP); + void newRequires(Set mods, String name) { + int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods); + mv.visitVarInsn(ALOAD, varIndex); + mv.visitLdcInsn(name); + mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER, + "newRequires", REQUIRES_SET_STRING_SIG, false); } /* - * Invoke Builder.exports(String pn, Set targets) + * Call Builder::newExports to create Exports instances and + * then pass it to the builder by calling: + * Builder.exports(Exports[]) + * + */ + void exports(Set exports) { + mv.visitVarInsn(ALOAD, BUILDER_VAR); + 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", EXPORTS_ARRAY_SIG, false); + } + + /* + * 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { /* * 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 @@ public final class SystemModuleDescriptorPlugin implements Plugin { 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<>(); - StringSetBuilder(Set names, boolean linked) { - this.names = names; - this.linked = linked; - } + // map Set to a specialized builder to allow them to be + // deduplicated as they are requested + final Map, EnumSetBuilder> + requiresModifiersSets = new HashMap<>(); - StringSetBuilder(Set names) { - this(names, false); - } + // map Set to a specialized builder to allow them to be + // deduplicated as they are requested + final Map, EnumSetBuilder> + exportsModifiersSets = new HashMap<>(); - void increment() { - refCount++; + // 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; + + DedupSetBuilder(IntSupplier localVarSupplier) { + this.stringSetVar = localVarSupplier.getAsInt(); + this.enumSetVar = localVarSupplier.getAsInt(); + this.localVarSupplier = localVarSupplier; } /* - * Build bytecode for the Set represented by this builder, + * 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(); + } + + /* + * 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(); + } + + + /* + * 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, * 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index 3fcda64dcda..3e685254537 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -80,7 +80,7 @@ generate-jli-classes.description=\ 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 --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index e0d071d634a..5d4b1d32aab 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -40,6 +40,7 @@ import java.lang.module.ModuleReference; 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.jar.JarOutputStream; 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.OptionParser; 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 @@ public class JmodTask { } } - 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 @@ public class JmodTask { .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 @@ public class JmodTask { 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 @@ public class JmodTask { /** * 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 @@ public class JmodTask { 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 @@ public class JmodTask { 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 @@ public class JmodTask { */ 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 @@ public class JmodTask { 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 --git a/jdk/src/jdk.jlink/share/classes/module-info.java b/jdk/src/jdk.jlink/share/classes/module-info.java index 37fced0d189..e20c763b256 100644 --- a/jdk/src/jdk.jlink/share/classes/module-info.java +++ b/jdk/src/jdk.jlink/share/classes/module-info.java @@ -31,21 +31,23 @@ module jdk.jlink { 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 --git a/jdk/src/jdk.jvmstat/share/classes/module-info.java b/jdk/src/jdk.jvmstat/share/classes/module-info.java index d0038c242b2..fc82760b9ba 100644 --- a/jdk/src/jdk.jvmstat/share/classes/module-info.java +++ b/jdk/src/jdk.jvmstat/share/classes/module-info.java @@ -36,7 +36,8 @@ module jdk.jvmstat { 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 --git a/jdk/src/jdk.localedata/share/classes/module-info.java b/jdk/src/jdk.localedata/share/classes/module-info.java index 6af3dd770ad..324e14b928f 100644 --- a/jdk/src/jdk.localedata/share/classes/module-info.java +++ b/jdk/src/jdk.localedata/share/classes/module-info.java @@ -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 --git a/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java b/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java index 72e2870532e..69a8e94beca 100644 --- a/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java +++ b/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java @@ -238,9 +238,4 @@ public class VMOption { } } - - // for sun.management.MappedMXBeanType - static CompositeData toCompositeData(VMOption option) { - return VMOptionCompositeData.toCompositeData(option); - } } diff --git a/jdk/src/jdk.management/share/classes/module-info.java b/jdk/src/jdk.management/share/classes/module-info.java index 34e371b721a..327d31ebda8 100644 --- a/jdk/src/jdk.management/share/classes/module-info.java +++ b/jdk/src/jdk.management/share/classes/module-info.java @@ -24,7 +24,7 @@ */ module jdk.management { - requires public java.management; + requires transitive java.management; exports com.sun.management; diff --git a/jdk/src/jdk.naming.dns/share/classes/module-info.java b/jdk/src/jdk.naming.dns/share/classes/module-info.java index 1d367eed0d0..abe26ec2644 100644 --- a/jdk/src/jdk.naming.dns/share/classes/module-info.java +++ b/jdk/src/jdk.naming.dns/share/classes/module-info.java @@ -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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java index f3183e3ed5f..0dcde2dd744 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java @@ -54,14 +54,7 @@ public class SolarisNumericGroupPrincipal implements 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java index 858f9564665..806f62187c4 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java @@ -53,15 +53,7 @@ public class SolarisNumericUserPrincipal implements 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java index 6cbc103ea81..f4491db4dc8 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java @@ -51,14 +51,7 @@ public class SolarisPrincipal implements Principal, java.io.Serializable { 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java index 1bf2e3e92a8..a3a04a04fa1 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java @@ -56,14 +56,7 @@ public class X500Principal implements Principal, java.io.Serializable { 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java index 24eb6225fd5..4e0225372b7 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java @@ -153,15 +153,8 @@ import com.sun.security.auth.UnixNumericGroupPrincipal; */ 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java index b79d6cc0f08..34f98390ee2 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java @@ -112,15 +112,8 @@ import sun.security.util.Password; */ 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index d59e2a8dbfe..2aa1e8ae65d 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -419,15 +419,8 @@ public class Krb5LoginModule implements LoginModule { 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 --git a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java index 29db6c34577..ff60810021b 100644 --- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java +++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java @@ -306,15 +306,8 @@ import com.sun.security.auth.UserPrincipal; 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 --git a/jdk/src/jdk.security.auth/share/classes/module-info.java b/jdk/src/jdk.security.auth/share/classes/module-info.java index 8f97ca43956..5181d23f513 100644 --- a/jdk/src/jdk.security.auth/share/classes/module-info.java +++ b/jdk/src/jdk.security.auth/share/classes/module-info.java @@ -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; + + uses sun.security.util.AuthResourcesProvider; + 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; - 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 --git a/jdk/src/jdk.security.jgss/share/classes/module-info.java b/jdk/src/jdk.security.jgss/share/classes/module-info.java index 9701e2a2b82..e66017f0102 100644 --- a/jdk/src/jdk.security.jgss/share/classes/module-info.java +++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java @@ -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 --git a/jdk/src/jdk.unsupported/share/classes/module-info.java b/jdk/src/jdk.unsupported/share/classes/module-info.java index 5ad248766ae..7cd9691671d 100644 --- a/jdk/src/jdk.unsupported/share/classes/module-info.java +++ b/jdk/src/jdk.unsupported/share/classes/module-info.java @@ -27,5 +27,8 @@ module jdk.unsupported { exports sun.misc; exports sun.reflect; exports com.sun.nio.file; + + opens sun.misc; + opens sun.reflect; } diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 42066777eee..7257db13fc3 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -145,10 +145,17 @@ java/io/pathNames/GeneralWin32.java 8156595 windows- ############################################################################ -# 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 @@ demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java 8151899 generic- com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java 8141370 linux-i586,macosx-all +javax/xml/ws/clientjar/TestWsImport.java 8170370 generic-all + ############################################################################ diff --git a/jdk/test/TEST.ROOT b/jdk/test/TEST.ROOT index 1e703488ea6..c61b9bca4e1 100644 --- a/jdk/test/TEST.ROOT +++ b/jdk/test/TEST.ROOT @@ -26,8 +26,8 @@ groups=TEST.groups [closed/TEST.groups] # 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 --git a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java index 6aebc550cf0..17cd517d03c 100644 --- a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java +++ b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java @@ -62,9 +62,10 @@ import org.testng.TestNG; * @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 --git a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java index e58acb24872..71e01a4fdbd 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java @@ -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 --git a/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java b/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java index 324d80441fb..1f12f889c65 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java @@ -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 --git a/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java b/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java index 0408d7596df..9c4cc3663c1 100644 --- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java +++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java @@ -24,6 +24,7 @@ /* * @test * @bug 8001596 + * @modules java.base/javax.crypto.spec:open * @summary Incorrect condition check in PBKDF2KeyImpl.java */ diff --git a/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java b/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java index 307d9fa3504..aacf78765a0 100644 --- a/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java +++ b/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java @@ -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 --git a/jdk/test/com/sun/jdi/ModulesTest.java b/jdk/test/com/sun/jdi/ModulesTest.java index e9c8cff173f..359293f6297 100644 --- a/jdk/test/com/sun/jdi/ModulesTest.java +++ b/jdk/test/com/sun/jdi/ModulesTest.java @@ -78,7 +78,6 @@ public class ModulesTest extends TestScaffold { } // 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 @@ public class ModulesTest extends TestScaffold { } 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 @@ public class ModulesTest extends TestScaffold { 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 --git a/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java b/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java index b2faba83049..dd3dec369fa 100644 --- a/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java +++ b/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java @@ -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 --git a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java index 3784c9392eb..6a96e9ec2d5 100644 --- a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java +++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java @@ -33,7 +33,7 @@ import java.lang.reflect.Method; * 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 --git a/jdk/test/com/sun/jndi/dns/Parser.java b/jdk/test/com/sun/jndi/dns/Parser.java index 04846173875..58c7bd578b3 100644 --- a/jdk/test/com/sun/jndi/dns/Parser.java +++ b/jdk/test/com/sun/jndi/dns/Parser.java @@ -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 --git a/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java b/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java index 956e2c4aea8..b43440a4154 100644 --- a/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java +++ b/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java @@ -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 --git a/jdk/test/com/sun/management/VMOptionOpenDataTest.java b/jdk/test/com/sun/management/VMOptionOpenDataTest.java index 3436c67fa20..5d255085250 100644 --- a/jdk/test/com/sun/management/VMOptionOpenDataTest.java +++ b/jdk/test/com/sun/management/VMOptionOpenDataTest.java @@ -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 +" \""); - 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."); - } - } - } catch (OpenDataException | InvalidObjectException ode) { - failed = ode; + String[] signatures = new String[] { + String.class.getName() + }; + Object obj = msc.invoke(mxbean.getObjectName(), "getVMOption", + new String[] { "PrintVMOptions"}, signatures); + + 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()); } - if (failed == null) { - System.out.println("--- PASSED!"); - } else { - System.out.println("--- Failed: "+failed.getMessage()); - throw failed; + 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]); + } } } + + 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 --git a/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java b/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java index c2d01180ca8..4666c833af3 100644 --- a/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java +++ b/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java @@ -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 --git a/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java b/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java index a6730e07816..4c03da8fd6b 100644 --- a/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java +++ b/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java @@ -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 --git a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html index 25b96afb568..7240f441887 100644 --- a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html +++ b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html @@ -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 --git a/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java b/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java index dd7829b283f..de14ff7d565 100644 --- a/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java +++ b/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java @@ -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 --git a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java index 32217e8de3d..1ef644b3212 100644 --- a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java +++ b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java @@ -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 --git a/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh b/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh index 1683ba94a58..714d10007e5 100644 --- a/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh +++ b/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh @@ -154,16 +154,16 @@ chmod 777 ./* 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 @@ case "$OS" in 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 @@ case "$OS" in 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 @@ case "$OS" in 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 --git a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java index 25254d531c2..bf79e9886fa 100644 --- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java +++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java @@ -30,6 +30,7 @@ import java.awt.image.BufferedImage; * 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 --git a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java index e8710edf6e9..77afc31f34e 100644 --- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java +++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java @@ -33,6 +33,7 @@ import java.awt.image.BufferedImage; * 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 --git a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java index 95879ce4f80..56f07856437 100644 --- a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java +++ b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java @@ -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 --git a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java index dca4ef0dbb2..9413915b208 100644 --- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java +++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java @@ -29,6 +29,7 @@ import java.awt.image.BufferedImage; * @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 --git a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java index c530d284f02..7996c4f005a 100644 --- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java +++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java @@ -32,6 +32,7 @@ import java.awt.image.BufferedImage; * 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 --git a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java index 4f8b91c98ed..5e71ac756ff 100644 --- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java +++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java @@ -29,6 +29,7 @@ import java.awt.image.BufferedImage; * @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 --git a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java index 453b4677145..bca5af9a190 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java @@ -39,6 +39,7 @@ import java.awt.image.BufferedImage; * @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 --git a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java index 72a8fe535c7..c1e60d48396 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java @@ -30,6 +30,7 @@ import java.awt.image.BufferedImage; * @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 --git a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java index f7549a385eb..3d6d224fb9b 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java @@ -34,6 +34,7 @@ import java.awt.image.BufferedImage; * 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 --git a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java index f59ff63fd76..f09219cdf6f 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java @@ -29,6 +29,7 @@ import java.awt.image.BufferedImage; * @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 --git a/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java b/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java index 81fdd4b049b..588f6b61354 100644 --- a/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java +++ b/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java @@ -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 --git a/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java b/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java index 25884f9fadd..384a4ea43a6 100644 --- a/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java +++ b/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java @@ -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 --git a/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java b/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java index 879aee525fd..8770a72eae5 100644 --- a/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java +++ b/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java @@ -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 --git a/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java b/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java index ef220b90775..8c49d4462cd 100644 --- a/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java +++ b/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java @@ -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 --git a/jdk/test/java/awt/image/MultiResolutionImageTest.java b/jdk/test/java/awt/image/MultiResolutionImageTest.java index a1f70e52b91..a1e85c9335e 100644 --- a/jdk/test/java/awt/image/MultiResolutionImageTest.java +++ b/jdk/test/java/awt/image/MultiResolutionImageTest.java @@ -48,7 +48,7 @@ import java.awt.image.MultiResolutionImage; * @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 --git a/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java index c16e58076c1..6d8dbc4b227 100644 --- a/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java +++ b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java @@ -26,6 +26,6 @@ import java.lang.reflect.Module; 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 --git a/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java index 883e6d00d59..2739f450d69 100644 --- a/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java +++ b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java @@ -25,6 +25,7 @@ * @test * @bug 6380849 * @summary Tests BeanInfo finder + * @modules java.desktop/java.beans:open * @author Sergey Malenkov */ diff --git a/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java b/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java index aa6a3fc5fe3..382bba5addd 100644 --- a/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java +++ b/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java @@ -25,6 +25,7 @@ * @test * @bug 8007458 * @summary Tests CardLayout encoding + * @modules java.desktop/java.awt:open * @author Sergey Malenkov */ diff --git a/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java b/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java index 7011dbd739f..12af8203fb4 100644 --- a/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java +++ b/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java @@ -25,6 +25,7 @@ * @test * @bug 8007458 * @summary Tests GridBagLayout encoding + * @modules java.desktop/java.awt:open * @author Sergey Malenkov */ diff --git a/jdk/test/java/io/FilePermission/Correctness.java b/jdk/test/java/io/FilePermission/Correctness.java index 7911dd60b1e..140aa8b03f9 100644 --- a/jdk/test/java/io/FilePermission/Correctness.java +++ b/jdk/test/java/io/FilePermission/Correctness.java @@ -25,6 +25,7 @@ * * @test * @bug 8164705 + * @modules java.base/java.io:open * @summary Remove pathname canonicalization from FilePermission */ diff --git a/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java b/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java index 86e8001a63e..b3880666a6c 100644 --- a/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java +++ b/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java @@ -30,6 +30,7 @@ import java.lang.reflect.Method; /* * @test * @bug 8067870 + * @modules java.base/java.io:open * @summary verifies java.io.ObjectInputStream.PeekInputStream.skip works * as intended */ diff --git a/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java index 0a4905d6046..9a7811e5590 100644 --- a/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java +++ b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java @@ -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 --git a/jdk/test/java/lang/Class/GetModuleTest.java b/jdk/test/java/lang/Class/GetModuleTest.java index 3feb9985681..f0d7477c074 100644 --- a/jdk/test/java/lang/Class/GetModuleTest.java +++ b/jdk/test/java/lang/Class/GetModuleTest.java @@ -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 @@ import static org.testng.Assert.*; 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 --git a/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java index 83856c6d814..56cec626fa0 100644 --- a/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java +++ b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java @@ -44,7 +44,7 @@ public class Main { 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 --git a/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java b/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java index 2441a17ad00..0c53acc9f25 100644 --- a/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java +++ b/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java @@ -40,6 +40,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * 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 --git a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java index 5f4dcea191e..90a34a58d6b 100644 --- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java +++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java @@ -58,9 +58,9 @@ import jdk.internal.module.Modules; /** * @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 @@ public class FieldSetAccessibleTest { // 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 class FieldSetAccessibleTest { 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 --git a/jdk/test/java/lang/Class/getResource/Main.java b/jdk/test/java/lang/Class/getResource/Main.java index b1b45f3933e..96d4e68ac15 100644 --- a/jdk/test/java/lang/Class/getResource/Main.java +++ b/jdk/test/java/lang/Class/getResource/Main.java @@ -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.Path; 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 class Main { 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 Class getResource from the unnamed module - URL url0 = Main.class.getResource("/" + NAME); - assertNull(url0); + // invoke Class getResource from an unnamed module. + URL url = Main.class.getResource("/" + NAME); + assertNotNull(url); - // 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); + url = Main.class.getResource("/p1/" + NAME); + assertNull(url); - // check contents of resurces at url1 and url2 - assertEquals(new String(readAll(url1), "UTF-8"), "m1"); - assertEquals(new String(readAll(url2), "UTF-8"), "m2"); + url = Main.class.getResource("/p1/impl/" + NAME); + assertNull(url); - // invoke Class getResourceAsStream from the unnamed module - InputStream in0 = Main.class.getResourceAsStream("/" + NAME); - assertNull(in0); + url = Main.class.getResource("/p1/resources/" + NAME); + assertEquals(readAllAsString(url), "m1/p1.resources"); - // 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); + url = Main.class.getResource("/p2/" + NAME); + assertNull(url); - // 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); + url = Main.class.getResource("/p2/impl/" + NAME); + assertNull(url); - // 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"); + // 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"); + + 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 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"); + + // 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 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); + + 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); + + 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"); + + + // 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,16 +235,23 @@ public class Main { 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). */ @@ -130,12 +266,21 @@ public class Main { 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 --git a/jdk/test/java/lang/Class/getResource/ResourcesTest.java b/jdk/test/java/lang/Class/getResource/ResourcesTest.java index 97fdae6f575..7d155765c1b 100644 --- a/jdk/test/java/lang/Class/getResource/ResourcesTest.java +++ b/jdk/test/java/lang/Class/getResource/ResourcesTest.java @@ -68,7 +68,7 @@ public class ResourcesTest { .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 @@ public class ResourcesTest { 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 --git a/jdk/test/java/lang/Class/getResource/src/m1/module-info.java b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java index 47a2c4c1f77..e29065ed157 100644 --- a/jdk/test/java/lang/Class/getResource/src/m1/module-info.java +++ b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java @@ -23,4 +23,5 @@ module m1 { exports p1; + opens p1.resources; } diff --git a/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java index afc13950f4c..370c294310f 100644 --- a/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java @@ -36,4 +36,12 @@ public class Main { 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 --git a/jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java b/jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java new file mode 100644 index 00000000000..12820db66b3 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java @@ -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 --git a/jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java b/jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java new file mode 100644 index 00000000000..6dcc132acdd --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java @@ -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 --git a/jdk/test/java/lang/Class/getResource/src/m2/module-info.java b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java index e28b2202567..6b7c3ef5fa8 100644 --- a/jdk/test/java/lang/Class/getResource/src/m2/module-info.java +++ b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java @@ -23,4 +23,6 @@ module m2 { exports p2; + exports p2.impl to m1; + opens p2.resources to m1; } diff --git a/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java index 51bdcf62cc5..f24e5fd8a72 100644 --- a/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java @@ -36,4 +36,12 @@ public class Main { 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 --git a/jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java b/jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java new file mode 100644 index 00000000000..93a3e3153a3 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java @@ -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 --git a/jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java b/jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java new file mode 100644 index 00000000000..fa35bbfaaaf --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java b/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java index 684ccb22687..85c21d2e59e 100644 --- a/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java +++ b/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh index a00c14077d6..ffaf9f3ac16 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh @@ -106,6 +106,7 @@ done # 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 --git a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh index 1289b4c861e..b080e01fd77 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh @@ -102,6 +102,7 @@ done # 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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java index a6436aff42e..e816f31fc8b 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java @@ -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 class Main { 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")); + + 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 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)); // 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); + + 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); - // 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)); // SecurityManager case System.setSecurityManager(new SecurityManager()); @@ -77,16 +288,23 @@ public class Main { 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). */ @@ -101,12 +319,60 @@ public class Main { 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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java index 3eafa822766..65f0d371a82 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java @@ -68,7 +68,7 @@ public class ResourcesTest { .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 class ResourcesTest { 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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java index 47a2c4c1f77..e29065ed157 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java @@ -23,4 +23,5 @@ module m1 { exports p1; + opens p1.resources; } diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java index 9e14eb0c226..9d5c3ea05fb 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java @@ -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 @@ public class Main { 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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java new file mode 100644 index 00000000000..12820db66b3 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java new file mode 100644 index 00000000000..6dcc132acdd --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java index e28b2202567..6b7c3ef5fa8 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java @@ -23,4 +23,6 @@ module m2 { exports p2; + exports p2.impl to m1; + opens p2.resources to m1; } diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java index 6f291a21969..e3d61beddc1 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java @@ -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 @@ public class Main { 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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java new file mode 100644 index 00000000000..93a3e3153a3 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java new file mode 100644 index 00000000000..fa35bbfaaaf --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java @@ -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 --git a/jdk/test/java/lang/ProcessBuilder/Basic.java b/jdk/test/java/lang/ProcessBuilder/Basic.java index c04e085ef43..729b24995ad 100644 --- a/jdk/test/java/lang/ProcessBuilder/Basic.java +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java @@ -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 --git a/jdk/test/java/lang/Runtime/Version/VersionProps.java b/jdk/test/java/lang/Runtime/Version/VersionProps.java index ddbaa081d4f..b0c98d244c9 100644 --- a/jdk/test/java/lang/Runtime/Version/VersionProps.java +++ b/jdk/test/java/lang/Runtime/Version/VersionProps.java @@ -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 --git a/jdk/test/java/lang/StackWalker/CountLocalSlots.java b/jdk/test/java/lang/StackWalker/CountLocalSlots.java index 066055b0a1d..dfb1698d188 100644 --- a/jdk/test/java/lang/StackWalker/CountLocalSlots.java +++ b/jdk/test/java/lang/StackWalker/CountLocalSlots.java @@ -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 --git a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java index f4f646549ec..ab07c7d9ad8 100644 --- a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java +++ b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java @@ -25,6 +25,7 @@ * @test * @bug 8020968 8147039 * @summary Tests for locals and operands + * @modules java.base/java.lang:open * @run testng LocalsAndOperands */ diff --git a/jdk/test/java/lang/StackWalker/LocalsCrash.java b/jdk/test/java/lang/StackWalker/LocalsCrash.java index 87415e4df0c..178e07c34f3 100644 --- a/jdk/test/java/lang/StackWalker/LocalsCrash.java +++ b/jdk/test/java/lang/StackWalker/LocalsCrash.java @@ -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 --git a/jdk/test/java/lang/String/CompactString/VMOptionsTest.java b/jdk/test/java/lang/String/CompactString/VMOptionsTest.java index 01eed446292..04fc008ea62 100644 --- a/jdk/test/java/lang/String/CompactString/VMOptionsTest.java +++ b/jdk/test/java/lang/String/CompactString/VMOptionsTest.java @@ -37,6 +37,7 @@ import static org.testng.Assert.*; * 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 --git a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java index bedd6117ae8..1b6a5c6e145 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java @@ -39,7 +39,7 @@ import jdk.internal.logger.LazyLoggers; * @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 --git a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java index e2f6d4b009d..f34ab76400b 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java @@ -52,7 +52,7 @@ import java.lang.reflect.Module; * @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 --git a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java index 28bca5cf39c..0262efac8cc 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java @@ -34,6 +34,7 @@ import java.lang.reflect.Method; * @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 --git a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java index eb3f07c3ec3..6abc3c58e73 100644 --- a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java +++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java @@ -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 --git a/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java b/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java index 982852c8dfb..586c0e4fa6c 100644 --- a/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java +++ b/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/MiscTests.java b/jdk/test/java/lang/instrument/RedefineModuleAgent.java similarity index 52% rename from jdk/test/java/util/ServiceLoader/modules/MiscTests.java rename to jdk/test/java/lang/instrument/RedefineModuleAgent.java index 5a99a30737c..8d96db1c205 100644 --- a/jdk/test/java/util/ServiceLoader/modules/MiscTests.java +++ b/jdk/test/java/lang/instrument/RedefineModuleAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,36 +21,30 @@ * questions. */ -import java.lang.reflect.Layer; -import java.security.Provider; -import java.util.ServiceLoader; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Module; +import java.util.List; +import java.util.Map; +import java.util.Set; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/* - * @test - * @run testng MiscTests - * @summary Basic test of ServiceLoader with modules +/** + * Agent used by RedefineModuleTest */ -public class MiscTests { +public class RedefineModuleAgent { - @Test - public void testEmptyLayer() { - ServiceLoader sl - = ServiceLoader.load(Layer.empty(), Provider.class); - assertFalse(sl.iterator().hasNext()); + private static Instrumentation inst; + + public static void premain(String args, Instrumentation inst) throws Exception { + RedefineModuleAgent.inst = inst; } - @Test(expectedExceptions = { NullPointerException.class }) - public void testNullLayer() { - ServiceLoader.load(null, Provider.class); + static void redefineModule(Module module, + Set extraReads, + Map> extraExports, + Map> extraOpens, + Set> extraUses, + Map, List>> extraProvides) { + inst.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testNullService() { - ServiceLoader.load(Layer.empty(), null); - } - } diff --git a/jdk/test/java/lang/instrument/RedefineModuleTest.java b/jdk/test/java/lang/instrument/RedefineModuleTest.java new file mode 100644 index 00000000000..bf54daf78cf --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineModuleTest.java @@ -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 --git a/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java b/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java index 1571774b45c..4cdbeb6beac 100644 --- a/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java +++ b/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java @@ -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 --git a/jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java b/jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java new file mode 100644 index 00000000000..696d2e9f798 --- /dev/null +++ b/jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java @@ -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 --git a/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java new file mode 100644 index 00000000000..24eb296f2ba --- /dev/null +++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java @@ -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 --git a/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java new file mode 100644 index 00000000000..dd4be4ecf77 --- /dev/null +++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java @@ -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 --git a/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java index 464b275412d..d453caf18f8 100644 --- a/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java +++ b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java @@ -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 --git a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java index 08bce54147f..bef4d5ebc27 100644 --- a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java +++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java @@ -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 --git a/jdk/test/java/lang/invoke/LambdaFormTest.java b/jdk/test/java/lang/invoke/LambdaFormTest.java index f078189c5c0..5ebf2ddd838 100644 --- a/jdk/test/java/lang/invoke/LambdaFormTest.java +++ b/jdk/test/java/lang/invoke/LambdaFormTest.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java new file mode 100644 index 00000000000..5abe4eb2383 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java new file mode 100644 index 00000000000..9f209a53689 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java new file mode 100644 index 00000000000..4517ab35a62 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java new file mode 100644 index 00000000000..4a0a37afa51 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java new file mode 100644 index 00000000000..006eb3a52b0 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java @@ -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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java similarity index 92% rename from jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java rename to jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java index f9754a0a870..5603ddd2f35 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -20,7 +20,5 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - module m3 { - exports p3; } diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java new file mode 100644 index 00000000000..0869c201368 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java similarity index 87% rename from jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java rename to jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java index a43887ccd04..fd92c00e53c 100644 --- a/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -22,8 +22,6 @@ */ module test { - requires java.scripting; - - uses javax.script.ScriptEngineFactory; + requires testng; + exports p to testng; // TestNG invokes the public methods } - diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java new file mode 100644 index 00000000000..87dfbd7f06e --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java new file mode 100644 index 00000000000..5b7ce90acac --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java @@ -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 --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java new file mode 100644 index 00000000000..ff64d737497 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java @@ -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 --git a/jdk/test/java/lang/invoke/PrivateInvokeTest.java b/jdk/test/java/lang/invoke/PrivateInvokeTest.java index fdcb2ef6765..12edf8e3263 100644 --- a/jdk/test/java/lang/invoke/PrivateInvokeTest.java +++ b/jdk/test/java/lang/invoke/PrivateInvokeTest.java @@ -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 --git a/jdk/test/java/lang/invoke/VMAnonymousClass.java b/jdk/test/java/lang/invoke/VMAnonymousClass.java index 300e056477a..a76c4962a71 100644 --- a/jdk/test/java/lang/invoke/VMAnonymousClass.java +++ b/jdk/test/java/lang/invoke/VMAnonymousClass.java @@ -32,7 +32,6 @@ package test.java.lang.invoke; 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 @@ public class VMAnonymousClass { 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 @@ public class VMAnonymousClass { 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 --git a/jdk/test/java/lang/module/AutomaticModulesTest.java b/jdk/test/java/lang/module/AutomaticModulesTest.java index 3ad04a2a943..07d25b9be85 100644 --- a/jdk/test/java/lang/module/AutomaticModulesTest.java +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java @@ -67,6 +67,15 @@ public class AutomaticModulesTest { // 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 @@ public class AutomaticModulesTest { 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 @@ public class AutomaticModulesTest { 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 @@ public class AutomaticModulesTest { 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 @@ public class AutomaticModulesTest { /** * 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 class AutomaticModulesTest { */ 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 @@ public class AutomaticModulesTest { // 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 class AutomaticModulesTest { */ 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 @@ public class AutomaticModulesTest { * 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 @@ public class AutomaticModulesTest { * 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 @@ public class AutomaticModulesTest { * in the resulting JAR file. */ static Path createDummyJarFile(Path jarfile, String... entries) - throws IOException + throws IOException { return createDummyJarFile(jarfile, null, entries); } diff --git a/jdk/test/java/lang/module/ConfigurationTest.java b/jdk/test/java/lang/module/ConfigurationTest.java index a73987545e5..7ae867217c6 100644 --- a/jdk/test/java/lang/module/ConfigurationTest.java +++ b/jdk/test/java/lang/module/ConfigurationTest.java @@ -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 class ConfigurationTest { */ 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { /** - * 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() { + public void testRequiresTransitive2() { - // 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(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -179,7 +183,8 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { // cf2: m3, m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -204,7 +209,8 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { // cf3: m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -343,7 +353,8 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { /** - * 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() { + public void testRequiresTransitive5() { - // 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(Modifier.PUBLIC, "m1") + = ModuleDescriptor.module("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); @@ -381,7 +392,8 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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(); @@ -434,6 +447,362 @@ public class ConfigurationTest { } + /** + * 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 @@ -442,15 +811,15 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 class ConfigurationTest { public void testServiceBindingWithConfigurations1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .exports("p") .uses("p.S") .build(); @@ -555,9 +926,9 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { 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 class ConfigurationTest { 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 class ConfigurationTest { 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 class ConfigurationTest { public void testResolvedInParent1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); @@ -847,7 +1224,7 @@ public class ConfigurationTest { public void testResolvedInParent2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -859,7 +1236,7 @@ public class ConfigurationTest { ModuleDescriptor descriptor2 - = new ModuleDescriptor.Builder("m2") + = ModuleDescriptor.module("m2") .requires("m1") .build(); @@ -880,12 +1257,221 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { * 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 @@ public class ConfigurationTest { // cf2: m3 requires m2, m1 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -939,7 +1558,8 @@ public class ConfigurationTest { 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 @@ public class ConfigurationTest { @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 @@ public class ConfigurationTest { @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 @@ public class ConfigurationTest { // 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 @@ public class ConfigurationTest { @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 class ConfigurationTest { 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 class ConfigurationTest { 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { @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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { /** - * 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 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .uses("p.S") .build(); @@ -1292,8 +1911,8 @@ public class ConfigurationTest { @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 @@ public class ConfigurationTest { @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 class ConfigurationTest { 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 class ConfigurationTest { 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 @@ public class ConfigurationTest { ModuleDescriptor descriptor1 = builder.build(); - builder = new ModuleDescriptor.Builder("m2"); + builder = ModuleDescriptor.module("m2"); s = s2.split("-"); if (!s[0].equals("*")) @@ -1433,6 +2052,21 @@ public class ConfigurationTest { } + // 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 @@ -1448,6 +2082,31 @@ public class ConfigurationTest { resolveRequires(ModuleFinder.of(), (ModuleFinder)null); } + @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()); @@ -1458,6 +2117,31 @@ public class ConfigurationTest { resolveRequiresAndUses(ModuleFinder.of(), (ModuleFinder) null); } + @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 --git a/jdk/test/java/lang/module/ModuleDescriptorTest.java b/jdk/test/java/lang/module/ModuleDescriptorTest.java index 402d645ba6c..efaa498d558 100644 --- a/jdk/test/java/lang/module/ModuleDescriptorTest.java +++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java @@ -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 @@ public class ModuleDescriptorTest { // 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 @@ public class ModuleDescriptorTest { .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 class ModuleDescriptorTest { } 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 @@ public class ModuleDescriptorTest { 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 @@ public class ModuleDescriptorTest { @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 class ModuleDescriptorTest { } 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 @@ public class ModuleDescriptorTest { 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 @@ public class ModuleDescriptorTest { // 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 @@ public class ModuleDescriptorTest { } 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 class ModuleDescriptorTest { 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 class ModuleDescriptorTest { 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 @@ public class ModuleDescriptorTest { 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 @@ public class ModuleDescriptorTest { 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 @@ public class ModuleDescriptorTest { } + // 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 @@ public class ModuleDescriptorTest { @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) + public void testProvides() { + 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; - // conceals + p1 = provides("p.S", "q.S1"); + p2 = provides("p.S", "q.S1"); + assertEquals(p1, p2); + assertTrue(p1.hashCode() == p2.hashCode()); - 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")); + 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); } - public void testConcealsWithEmptySet() { - Set conceals - = new Builder("foo").conceals(Collections.emptySet()).build().conceals(); - assertTrue(conceals.size() == 0); + // contains + + 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 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 @@ public class ModuleDescriptorTest { // 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 class ModuleDescriptorTest { 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 class ModuleDescriptorTest { 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 class ModuleDescriptorTest { } }; - 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 class ModuleDescriptorTest { } } - 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 @@ public class ModuleDescriptorTest { @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 @@ public class ModuleDescriptorTest { // 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 @@ public class ModuleDescriptorTest { @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 @@ public class ModuleDescriptorTest { // 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 --git a/jdk/test/java/lang/module/ModuleFinderTest.java b/jdk/test/java/lang/module/ModuleFinderTest.java index 9a79a5757de..278b4b98714 100644 --- a/jdk/test/java/lang/module/ModuleFinderTest.java +++ b/jdk/test/java/lang/module/ModuleFinderTest.java @@ -335,7 +335,7 @@ public class ModuleFinderTest { 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 @@ public class ModuleFinderTest { 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 --git a/jdk/test/java/lang/module/ModuleReferenceTest.java b/jdk/test/java/lang/module/ModuleReferenceTest.java index fca7cc77c8a..6b480bb8b2c 100644 --- a/jdk/test/java/lang/module/ModuleReferenceTest.java +++ b/jdk/test/java/lang/module/ModuleReferenceTest.java @@ -45,10 +45,10 @@ public class ModuleReferenceTest { 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 class ModuleReferenceTest { public void testNullLocation() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("m") + = ModuleDescriptor.module("m") .exports("p") .build(); Supplier supplier = makeSupplier(); @@ -86,7 +86,7 @@ public class ModuleReferenceTest { @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 class ModuleReferenceTest { 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 class ModuleReferenceTest { 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 --git a/jdk/test/java/lang/module/MultiReleaseJarTest.java b/jdk/test/java/lang/module/MultiReleaseJarTest.java index ad982650334..7daddb11993 100644 --- a/jdk/test/java/lang/module/MultiReleaseJarTest.java +++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java @@ -80,7 +80,7 @@ public class MultiReleaseJarTest { 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 class MultiReleaseJarTest { 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 class MultiReleaseJarTest { 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 --git a/jdk/test/java/lang/ref/FinalizerHistogramTest.java b/jdk/test/java/lang/ref/FinalizerHistogramTest.java index a201331f47a..66cf76ea7f2 100644 --- a/jdk/test/java/lang/ref/FinalizerHistogramTest.java +++ b/jdk/test/java/lang/ref/FinalizerHistogramTest.java @@ -31,6 +31,7 @@ import java.lang.reflect.Field; /* * @test * @summary Unit test for FinalizerHistogram + * @modules java.base/java.lang.ref:open * @run main FinalizerHistogramTest */ diff --git a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java index 8d9196658b5..da5d264b1fd 100644 --- a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java +++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -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 */ @@ -141,81 +142,6 @@ public class ModuleSetAccessibleTest { } - /** - * 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. */ diff --git a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java index 1241f235325..8f14171ce87 100644 --- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java +++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java @@ -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 class BasicLayerTest { public void testEmpty() { Layer emptyLayer = Layer.empty(); - assertFalse(emptyLayer.parent().isPresent()); + assertTrue(emptyLayer.parents().isEmpty()); assertTrue(emptyLayer.configuration() == Configuration.empty()); @@ -97,8 +99,9 @@ public class BasicLayerTest { // 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 class BasicLayerTest { */ 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 @@ public class BasicLayerTest { 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 class BasicLayerTest { */ 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 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { * 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 @@ public class BasicLayerTest { // 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 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { /** - * 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 @@ public class BasicLayerTest { * 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 @@ public class BasicLayerTest { // cf2: m3, m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -408,8 +413,11 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { * * 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 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { * * 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 @@ public class BasicLayerTest { // cf1: m1 ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); @@ -528,11 +539,11 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { // cf3: m3 requires m2 ModuleDescriptor descriptor3 - = new ModuleDescriptor.Builder("m3") + = ModuleDescriptor.module("m3") .requires("m2") .build(); @@ -557,9 +568,14 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { * 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 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { 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 class BasicLayerTest { public void testModuleAlreadyDefinedToLoader() { ModuleDescriptor md - = new ModuleDescriptor.Builder("m") + = ModuleDescriptor.module("m") .requires("java.base") .build(); @@ -704,14 +723,14 @@ public class BasicLayerTest { 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 @@ public class BasicLayerTest { 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 class BasicLayerTest { */ public void testLayerWithJavaBase() { ModuleDescriptor descriptor - = new ModuleDescriptor.Builder("java.base") + = ModuleDescriptor.module("java.base") .exports("java.lang") .build(); @@ -782,12 +801,7 @@ public class BasicLayerTest { 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) { } @@ -803,6 +817,74 @@ public class BasicLayerTest { } + /** + * 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 */ @@ -810,7 +892,7 @@ public class BasicLayerTest { public void testIncorrectParent1() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .requires("java.base") .build(); @@ -831,7 +913,7 @@ public class BasicLayerTest { public void testIncorrectParent2() { ModuleDescriptor descriptor1 - = new ModuleDescriptor.Builder("m1") + = ModuleDescriptor.module("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); diff --git a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java index a3305d521ac..23c7d06d15d 100644 --- a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java +++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java @@ -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.Layer; 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 class LayerAndLoadersTest { 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 class LayerAndLoadersTest { 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 @@ public class LayerAndLoadersTest { 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 @@ public class LayerAndLoadersTest { } + /** + * 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 --git a/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java new file mode 100644 index 00000000000..6582e493c07 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java new file mode 100644 index 00000000000..1746d6d40e9 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java index 32a945a5ce4..bafa57ba3a8 100644 --- a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java +++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java @@ -174,8 +174,24 @@ public class BasicModuleTest { // 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 --git a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java index 9c95fee5113..dfb6b760f10 100644 --- a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java +++ b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java @@ -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 @@ import java.util.Set; 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 @@ public class WithSecurityManager { throw new RuntimeException(); } -} \ No newline at end of file +} diff --git a/jdk/test/java/lang/reflect/Module/access/AccessTest.java b/jdk/test/java/lang/reflect/Module/access/AccessTest.java index 1e6e98a2cc6..4bd3f2bf39b 100644 --- a/jdk/test/java/lang/reflect/Module/access/AccessTest.java +++ b/jdk/test/java/lang/reflect/Module/access/AccessTest.java @@ -38,8 +38,8 @@ import static org.testng.Assert.*; * @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 @@ public class AccessTest { 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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java index 9c987c725fc..dfca72010cd 100644 --- a/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java +++ b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java similarity index 76% rename from jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java rename to jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java index b834364d4fd..e0e45e82a06 100644 --- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java @@ -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,14 +21,22 @@ * questions. */ -package p; +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 exportPackage(String pn, Module who) { + 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 --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java similarity index 68% rename from jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java rename to jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java index 55a23b9efbe..8ee138b280a 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java @@ -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,19 +21,25 @@ * questions. */ -package p3; +package p1; -import java.io.InputStream; -import java.net.URL; +public class Public { -public class Main { - private Main() { } + // public constructor + public Public() { } - public static URL getResourceInClassLoader(String name) { - return Main.class.getClassLoader().getResource(name); - } + // non-public constructor + private Public(Void ignore) { } - public static InputStream getResourceAsStreamInClassLoader(String name) { - return Main.class.getClassLoader().getResourceAsStream(name); - } + // 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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java b/jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java new file mode 100644 index 00000000000..5b5d120d324 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java b/jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java new file mode 100644 index 00000000000..85ff95bb0b8 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java b/jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java new file mode 100644 index 00000000000..78cba18ce47 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java index 0ba28a775df..c58b8e202dd 100644 --- a/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java +++ b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java @@ -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(); - Optional om = Layer.boot().findModule("target"); - assertTrue(om.isPresent()); + assertTrue(targetModule.isExported("p1")); + assertTrue(targetModule.isExported("p1", thisModule)); + assertTrue(targetModule.isExported("p1", targetModule)); - Module target = om.get(); + assertFalse(targetModule.isOpen("p1")); + assertFalse(targetModule.isOpen("p1", thisModule)); + assertTrue(targetModule.isOpen("p1", targetModule)); - assertTrue(target.isExported("p")); - assertTrue(target.isExported("p", thisModule)); + Class clazz = Class.forName("p1.Public"); + Constructor ctor1 = clazz.getConstructor(); // public + Constructor ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public - assertFalse(target.isExported("q")); - assertFalse(target.isExported("q", thisModule)); + 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 - // thisModule does not read the target module + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); - assertFalse(thisModule.canRead(target)); + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, false); + trySetAccessible(m1, true); + trySetAccessible(m2, false); + trySetAccessible(f1, true); + trySetAccessible(f2, false); - tryAccessPublicMembers("p.Exported", true); - tryAccessPublicMembers("q.Internal", false); + targetAddOpens("p1", thisModule); + 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); + } - // thisModule reads the target module + static void testNonPublicClassInExportedPackage() throws Exception { + Module thisModule = Main.class.getModule(); + Module targetModule = getTargetModule(); - thisModule.addReads(target); - assertTrue(thisModule.canRead(target)); + assertTrue(targetModule.isExported("p2")); + assertTrue(targetModule.isExported("p2", thisModule)); + assertTrue(targetModule.isExported("p2", targetModule)); - tryAccessPublicMembers("p.Exported", true); - tryAccessPublicMembers("q.Internal", false); + 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 - // change target module to export its internal package to thisModule + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public - targetAddExports("q", thisModule); - assertFalse(target.isExported("q")); - assertTrue(target.isExported("q", 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); + + targetAddExports("p2", 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); + + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); + + 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(); + + 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); + + 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); + + 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); + } + + 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 + + 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("q2", 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("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 - { + static Module getTargetModule() { + return Layer.boot().findModule("target").get(); + } - Class clazz = Class.forName(cn); - - Module thisModule = Main.class.getModule(); - Module targetModule = clazz.getModule(); - - // 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); } + } + + static void tryAccessMethod(Method method, boolean shouldSucceed) { try { - ctor.setAccessible(true); + method.invoke(null); assertTrue(shouldSucceed); - ctor.newInstance(); - } catch (InaccessibleObjectException e) { - assertTrue(shouldFail); + } catch (Exception e) { + e.printStackTrace(); + assertFalse(shouldSucceed); } + } - - // Method.invoke and Method.setAccessible - - Method m = clazz.getDeclaredMethod("run"); - try { - m.invoke(null); - assertTrue(shouldSucceed); - } catch (IllegalAccessException e) { - assertTrue(shouldFail); - } - try { - m.setAccessible(true); - assertTrue(shouldSucceed); - m.invoke(null); - } catch (InaccessibleObjectException e) { - assertTrue(shouldFail); - } - - // 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); - } - try { - f.setAccessible(true); - f.get(null); - f.set(null, 100); - assertTrue(shouldSucceed); - } catch (InaccessibleObjectException e) { - assertTrue(shouldFail); + } catch (Exception e) { + assertFalse(shouldSucceed); } + } + static void trySetAccessible(AccessibleObject ao, boolean shouldSucceed) { + try { + ao.setAccessible(true); + assertTrue(shouldSucceed); + } 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 --git a/jdk/test/java/lang/reflect/Module/annotation/Basic.java b/jdk/test/java/lang/reflect/Module/annotation/Basic.java new file mode 100644 index 00000000000..43733782d58 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/annotation/Basic.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java b/jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java new file mode 100644 index 00000000000..e6cb17c5491 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java new file mode 100644 index 00000000000..c6d48a3efda --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java new file mode 100644 index 00000000000..887e616be15 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java new file mode 100644 index 00000000000..c1075c7684f --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java @@ -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 --git a/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java index cf4da7cc254..a772b41692c 100644 --- a/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java +++ b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java @@ -22,6 +22,6 @@ */ module m3 { - requires public m2; + requires transitive m2; exports p.three; } diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java index 75c2d33dfd6..5e636327356 100644 --- a/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java +++ b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java @@ -23,7 +23,7 @@ module test { requires m1; - requires m3; // requires public m2 + requires m3; // requires transitive m2 exports jdk.test; } diff --git a/jdk/test/java/net/InterfaceAddress/Equals.java b/jdk/test/java/net/InterfaceAddress/Equals.java index 16511d5d080..b12e084ec9b 100644 --- a/jdk/test/java/net/InterfaceAddress/Equals.java +++ b/jdk/test/java/net/InterfaceAddress/Equals.java @@ -23,6 +23,7 @@ /* @test * @bug 6628576 + * @modules java.base/java.net:open * @summary InterfaceAddress.equals() NPE when broadcast field == null */ diff --git a/jdk/test/java/nio/Buffer/Basic.java b/jdk/test/java/nio/Buffer/Basic.java index 957d1fc12e4..7d5f85e532d 100644 --- a/jdk/test/java/nio/Buffer/Basic.java +++ b/jdk/test/java/nio/Buffer/Basic.java @@ -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 --git a/jdk/test/java/nio/channels/Selector/TemporarySelector.java b/jdk/test/java/nio/channels/Selector/TemporarySelector.java index c131c327fa7..fe2a5555960 100644 --- a/jdk/test/java/nio/channels/Selector/TemporarySelector.java +++ b/jdk/test/java/nio/channels/Selector/TemporarySelector.java @@ -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 --git a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh index 46ecc310161..9b01503fe5d 100644 --- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh +++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh @@ -109,7 +109,8 @@ failures=0 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 --git a/jdk/test/java/nio/file/etc/Exceptions.java b/jdk/test/java/nio/file/etc/Exceptions.java index 28d9459a93d..b1feae26f8a 100644 --- a/jdk/test/java/nio/file/etc/Exceptions.java +++ b/jdk/test/java/nio/file/etc/Exceptions.java @@ -23,6 +23,7 @@ /* @test * @bug 4313887 6881498 + * @modules java.base/java.lang:open * @summary Miscellenous tests on exceptions in java.nio.file */ diff --git a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java index 85e22e4bea0..9311879886e 100644 --- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java +++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java @@ -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 --git a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java index f30be86df4d..bb0394a435a 100644 --- a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java +++ b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java @@ -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 --git a/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java index 6520d26bec1..7fc99f41eec 100644 --- a/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java +++ b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java @@ -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 --git a/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java b/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java index ee2df053706..a6245974a18 100644 --- a/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java +++ b/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java @@ -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 --git a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java index 181b1d0256e..5e0f69ace45 100644 --- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java +++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java @@ -77,7 +77,7 @@ public class DGCDeadLock implements Runnable { 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 --git a/jdk/test/java/security/modules/ModularTest.java b/jdk/test/java/security/modules/ModularTest.java index 356bb0882cd..9e67094944f 100644 --- a/jdk/test/java/security/modules/ModularTest.java +++ b/jdk/test/java/security/modules/ModularTest.java @@ -164,7 +164,7 @@ public abstract class ModularTest { 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 --git a/jdk/test/java/security/testlibrary/Proc.java b/jdk/test/java/security/testlibrary/Proc.java index ec5fae6800c..7248757e0cd 100644 --- a/jdk/test/java/security/testlibrary/Proc.java +++ b/jdk/test/java/security/testlibrary/Proc.java @@ -257,7 +257,8 @@ public class Proc { 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 --git a/jdk/test/java/time/TEST.properties b/jdk/test/java/time/TEST.properties index 82224020e8e..49d8c3ce5d4 100644 --- a/jdk/test/java/time/TEST.properties +++ b/jdk/test/java/time/TEST.properties @@ -4,3 +4,4 @@ othervm.dirs = tck/java/time/chrono test/java/time/chrono test/java/time/format 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 --git a/jdk/test/java/util/ArrayList/ArrayManagement.java b/jdk/test/java/util/ArrayList/ArrayManagement.java index 81adc716013..e63a25a464e 100644 --- a/jdk/test/java/util/ArrayList/ArrayManagement.java +++ b/jdk/test/java/util/ArrayList/ArrayManagement.java @@ -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 --git a/jdk/test/java/util/Calendar/StampOverflow.java b/jdk/test/java/util/Calendar/StampOverflow.java index fc10595c87f..f234d4ebdc1 100644 --- a/jdk/test/java/util/Calendar/StampOverflow.java +++ b/jdk/test/java/util/Calendar/StampOverflow.java @@ -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 --git a/jdk/test/java/util/Collection/MOAT.java b/jdk/test/java/util/Collection/MOAT.java index f74a1785e26..b007f69159e 100644 --- a/jdk/test/java/util/Collection/MOAT.java +++ b/jdk/test/java/util/Collection/MOAT.java @@ -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 --git a/jdk/test/java/util/Collections/SyncSubMutexes.java b/jdk/test/java/util/Collections/SyncSubMutexes.java index 05dbcc3df71..dc2e7e3a951 100644 --- a/jdk/test/java/util/Collections/SyncSubMutexes.java +++ b/jdk/test/java/util/Collections/SyncSubMutexes.java @@ -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 --git a/jdk/test/java/util/Currency/CurrencyTest.java b/jdk/test/java/util/Currency/CurrencyTest.java index 2a4b6eaeb94..58839392e6d 100644 --- a/jdk/test/java/util/Currency/CurrencyTest.java +++ b/jdk/test/java/util/Currency/CurrencyTest.java @@ -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 --git a/jdk/test/java/util/Currency/ValidateISO4217.java b/jdk/test/java/util/Currency/ValidateISO4217.java index f482cfd66c8..33cca06219c 100644 --- a/jdk/test/java/util/Currency/ValidateISO4217.java +++ b/jdk/test/java/util/Currency/ValidateISO4217.java @@ -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 --git a/jdk/test/java/util/EnumSet/OneUniverse.java b/jdk/test/java/util/EnumSet/OneUniverse.java index 8ab3de5acf0..d907a7c6f79 100644 --- a/jdk/test/java/util/EnumSet/OneUniverse.java +++ b/jdk/test/java/util/EnumSet/OneUniverse.java @@ -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 --git a/jdk/test/java/util/Hashtable/DeserializedLength.java b/jdk/test/java/util/Hashtable/DeserializedLength.java index 1497eb8d00f..376c1f026d0 100644 --- a/jdk/test/java/util/Hashtable/DeserializedLength.java +++ b/jdk/test/java/util/Hashtable/DeserializedLength.java @@ -29,6 +29,7 @@ import java.util.Hashtable; * @test * @bug 8068427 * @summary Hashtable deserialization reconstitutes table with wrong capacity + * @modules java.base/java.util:open */ public class DeserializedLength { diff --git a/jdk/test/java/util/IdentityHashMap/Capacity.java b/jdk/test/java/util/IdentityHashMap/Capacity.java index 1be172efc49..dc7558959f1 100644 --- a/jdk/test/java/util/IdentityHashMap/Capacity.java +++ b/jdk/test/java/util/IdentityHashMap/Capacity.java @@ -38,6 +38,7 @@ import static org.testng.Assert.*; * @bug 6904367 * @summary IdentityHashMap reallocates storage when inserting expected * number of elements + * @modules java.base/java.util:open * @run testng Capacity * @key randomness */ diff --git a/jdk/test/java/util/Locale/bug6312358.java b/jdk/test/java/util/Locale/bug6312358.java index 74a5cd2e5ff..ff2ad347f60 100644 --- a/jdk/test/java/util/Locale/bug6312358.java +++ b/jdk/test/java/util/Locale/bug6312358.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/ReferencesTest.java b/jdk/test/java/util/ResourceBundle/ReferencesTest.java index 45074d5fe00..7c3a2b2a23d 100644 --- a/jdk/test/java/util/ResourceBundle/ReferencesTest.java +++ b/jdk/test/java/util/ResourceBundle/ReferencesTest.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh index e4a58121087..bc75ee61c93 100644 --- a/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh @@ -71,7 +71,8 @@ STATUS=0 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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java new file mode 100644 index 00000000000..29ef7f10557 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java new file mode 100644 index 00000000000..0f82e895663 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java new file mode 100644 index 00000000000..f45e6675ca4 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java new file mode 100644 index 00000000000..78109a76bf3 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java new file mode 100644 index 00000000000..8c2bbd9491e --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties new file mode 100644 index 00000000000..19792459e73 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties new file mode 100644 index 00000000000..c15ed5b1c53 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties new file mode 100644 index 00000000000..245da340796 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java new file mode 100644 index 00000000000..8947749dc0b --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java new file mode 100644 index 00000000000..1b366568b93 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java new file mode 100644 index 00000000000..672dafe5692 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java new file mode 100644 index 00000000000..5d7181ef616 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties new file mode 100644 index 00000000000..19792459e73 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties new file mode 100644 index 00000000000..c15ed5b1c53 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties new file mode 100644 index 00000000000..245da340796 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java new file mode 100644 index 00000000000..bc7232fb929 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh b/jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh new file mode 100644 index 00000000000..1860589f7f1 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh @@ -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 --git a/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh index c37949e0255..7aeaf827d60 100644 --- a/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh @@ -111,9 +111,9 @@ runJava -cp mods/named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \ 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 @@ runJava -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \ # 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 --git a/jdk/test/java/util/ServiceLoader/basic/BarProvider.java b/jdk/test/java/util/ServiceLoader/basic/BarProvider.java new file mode 100644 index 00000000000..912172be63c --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/basic/BarProvider.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/Basic.java b/jdk/test/java/util/ServiceLoader/basic/Basic.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/Basic.java rename to jdk/test/java/util/ServiceLoader/basic/Basic.java diff --git a/jdk/test/java/util/ServiceLoader/FooProvider1.java b/jdk/test/java/util/ServiceLoader/basic/FooProvider1.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/FooProvider1.java rename to jdk/test/java/util/ServiceLoader/basic/FooProvider1.java diff --git a/jdk/test/java/util/ServiceLoader/FooProvider2.java b/jdk/test/java/util/ServiceLoader/basic/FooProvider2.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/FooProvider2.java rename to jdk/test/java/util/ServiceLoader/basic/FooProvider2.java diff --git a/jdk/test/java/util/ServiceLoader/FooProvider3.java b/jdk/test/java/util/ServiceLoader/basic/FooProvider3.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/FooProvider3.java rename to jdk/test/java/util/ServiceLoader/basic/FooProvider3.java diff --git a/jdk/test/java/util/ServiceLoader/FooService.java b/jdk/test/java/util/ServiceLoader/basic/FooService.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/FooService.java rename to jdk/test/java/util/ServiceLoader/basic/FooService.java diff --git a/jdk/test/java/util/ServiceLoader/Load.java b/jdk/test/java/util/ServiceLoader/basic/Load.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/Load.java rename to jdk/test/java/util/ServiceLoader/basic/Load.java diff --git a/jdk/test/java/util/ServiceLoader/basic.sh b/jdk/test/java/util/ServiceLoader/basic/basic.sh similarity index 97% rename from jdk/test/java/util/ServiceLoader/basic.sh rename to jdk/test/java/util/ServiceLoader/basic/basic.sh index 3976e0d3c8b..4ffd56a4411 100644 --- a/jdk/test/java/util/ServiceLoader/basic.sh +++ b/jdk/test/java/util/ServiceLoader/basic/basic.sh @@ -25,7 +25,7 @@ # @bug 4640520 6354623 7198496 # @summary Unit test for java.util.ServiceLoader # -# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3 +# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3 BarProvider # @run shell basic.sh # Command-line usage: sh basic.sh /path/to/build @@ -131,7 +131,7 @@ go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \ mkdir -p x.meta/META-INF/services # Simple failures -for p in FooProvider42 'blah blah' 9234 'X!' java.lang.Object; do +for p in FooProvider42 'blah blah' 9234 'X!' BarProvider; do echo $p >x.meta/META-INF/services/FooService go ".${SEP}x.meta" "" fail done diff --git a/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java new file mode 100644 index 00000000000..c28e3b91911 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/Basic.java b/jdk/test/java/util/ServiceLoader/modules/Basic.java new file mode 100644 index 00000000000..7833c0e2771 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/Basic.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java b/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java deleted file mode 100644 index ff6d1bc1726..00000000000 --- a/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java +++ /dev/null @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java new file mode 100644 index 00000000000..86ca004aeef --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java similarity index 77% rename from jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java rename to jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java index 73bdb3405c3..3ec2391e6d4 100644 --- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -23,21 +23,15 @@ package p; -public class Exported { +/** + * Not a provider factory because the class is not public. + */ - /** - * Public constructor - */ - public Exported() { } +class ProviderFactory { + ProviderFactory() { } - /** - * Public field - */ - public static Object field; - - /** - * Public method - */ - public static void run() { + public static Service provider() { + throw new RuntimeException("Should not be called"); } } + diff --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java @@ -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 --git a/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java similarity index 76% rename from jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java rename to jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java index f0dabdd1653..249593d8f96 100644 --- a/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,23 +21,17 @@ * questions. */ -package q; +package p; -public class Internal { +/** + * Not a provider factory because the static provider() method is not public. + */ - /** - * Public constructor - */ - public Internal() { } +public class ProviderFactory { + ProviderFactory() { } - /** - * Public field - */ - public static Object field; - - /** - * Public method - */ - public static void run() { + static Service provider() { + throw new RuntimeException("Should not be called"); } } + diff --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java new file mode 100644 index 00000000000..73eaedc63af --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java new file mode 100644 index 00000000000..3eb8eebdc99 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java new file mode 100644 index 00000000000..8b38169fad3 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java new file mode 100644 index 00000000000..a684e47e19a --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java new file mode 100644 index 00000000000..7d6cd6a043e --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java new file mode 100644 index 00000000000..2a9092f08de --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java new file mode 100644 index 00000000000..e8394be4724 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java similarity index 90% rename from jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java rename to jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java index d599d4421a8..3ed6f7ba11e 100644 --- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java +++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -25,6 +25,6 @@ module bananascript { requires java.scripting; provides javax.script.ScriptEngineFactory - with org.banana.BananaScriptEngineFactory; + with org.banana.BananaScriptEngineFactory; } diff --git a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScript.java similarity index 100% rename from jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java rename to jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScript.java diff --git a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java similarity index 87% rename from jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java rename to jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java index 443415c1706..2f68f9e832d 100644 --- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java +++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java @@ -30,6 +30,18 @@ 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"; diff --git a/jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java b/jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java new file mode 100644 index 00000000000..d65b467cd2c --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java new file mode 100644 index 00000000000..c2f988a7991 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java new file mode 100644 index 00000000000..c0023951fe8 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java b/jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java new file mode 100644 index 00000000000..473df98933e --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java new file mode 100644 index 00000000000..42e1bdfb801 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java new file mode 100644 index 00000000000..c0023951fe8 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java @@ -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 --git a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java index c00c4b16d04..c731ff10523 100644 --- a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java +++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java @@ -30,6 +30,12 @@ import javax.script.ScriptEngineFactory; 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 --git a/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java b/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java index 1fd7b3b8cc8..3ddce835633 100644 --- a/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java +++ b/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java @@ -49,6 +49,7 @@ import java.util.concurrent.CountDownLatch; /* * @test * @bug 7014263 + * @modules java.base/java.util.concurrent:open * @summary White box testing of ArrayBlockingQueue iterators. */ diff --git a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java index 545201c3d14..804cd0862ec 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java @@ -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 --git a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java index 070ee1e002d..22d080d215f 100644 --- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java +++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java @@ -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 --git a/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java b/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java index 558cfb60981..b3c77e09854 100644 --- a/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java +++ b/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java @@ -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 --git a/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java b/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java index 093d9497cc8..a08e37f6c85 100644 --- a/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java +++ b/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java @@ -34,6 +34,7 @@ /* * @test + * @modules java.base/java.util.concurrent:open * @summary Test Phaser phase integer overflow behavior */ diff --git a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java index 87dfd6ed4bd..44ccbb36ff2 100644 --- a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java +++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java @@ -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 --git a/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java b/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java index 144e6d8d41f..e50becd2c3d 100644 --- a/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java +++ b/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java @@ -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 --git a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java index b218aded0f8..5ba9e867ba0 100644 --- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java +++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java @@ -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 --git a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java index 8a0360f9b99..f6a79727bb1 100644 --- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java +++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java @@ -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 --git a/jdk/test/java/util/logging/FileHandlerLongLimit.java b/jdk/test/java/util/logging/FileHandlerLongLimit.java index d081af50aaf..028e14ef9c2 100644 --- a/jdk/test/java/util/logging/FileHandlerLongLimit.java +++ b/jdk/test/java/util/logging/FileHandlerLongLimit.java @@ -52,6 +52,7 @@ import java.util.logging.LoggingPermission; * @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 --git a/jdk/test/java/util/logging/HandlersConfigTest.java b/jdk/test/java/util/logging/HandlersConfigTest.java index 7d122cd9f86..705c451db9f 100644 --- a/jdk/test/java/util/logging/HandlersConfigTest.java +++ b/jdk/test/java/util/logging/HandlersConfigTest.java @@ -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 --git a/jdk/test/java/util/logging/LocalizedLevelName.java b/jdk/test/java/util/logging/LocalizedLevelName.java index 561e2d17b75..627789f200e 100644 --- a/jdk/test/java/util/logging/LocalizedLevelName.java +++ b/jdk/test/java/util/logging/LocalizedLevelName.java @@ -29,6 +29,7 @@ import java.util.logging.*; * @test * @bug 8016127 8024131 * @summary test logging.properties localized + * @modules java.logging/sun.util.logging.resources:open * @run main/othervm LocalizedLevelName */ diff --git a/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java b/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java index 7022593f322..b456518edc5 100644 --- a/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java +++ b/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java @@ -61,6 +61,7 @@ import java.util.stream.Stream; * @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 --git a/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java index 2989a785505..03d26146837 100644 --- a/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java +++ b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java @@ -136,10 +136,6 @@ public class ResourceBundleTest { // 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 @@ public class ResourceBundleTest { // 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 --git a/jdk/test/javax/management/ObjectName/CompressedStorageTest.java b/jdk/test/javax/management/ObjectName/CompressedStorageTest.java index eac3d352472..a7f3d36fb7f 100644 --- a/jdk/test/javax/management/ObjectName/CompressedStorageTest.java +++ b/jdk/test/javax/management/ObjectName/CompressedStorageTest.java @@ -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 --git a/jdk/test/javax/management/loading/MLetInternalsTest.java b/jdk/test/javax/management/loading/MLetInternalsTest.java index 48318ac602c..4d312728dcf 100644 --- a/jdk/test/javax/management/loading/MLetInternalsTest.java +++ b/jdk/test/javax/management/loading/MLetInternalsTest.java @@ -36,7 +36,7 @@ import static org.testng.Assert.*; * @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 --git a/jdk/test/javax/management/openmbean/TabularDataOrderTest.java b/jdk/test/javax/management/openmbean/TabularDataOrderTest.java index 32ce7a3db00..68e9fefdc7c 100644 --- a/jdk/test/javax/management/openmbean/TabularDataOrderTest.java +++ b/jdk/test/javax/management/openmbean/TabularDataOrderTest.java @@ -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 --git a/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java b/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java index 44a59113732..acf21cb2793 100644 --- a/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java +++ b/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java @@ -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 --git a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java index 276e231cf85..a6063f1d306 100644 --- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java @@ -42,7 +42,7 @@ import javax.security.auth.Subject; * @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 --git a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java index 1872a13c3f7..5b616a7eb98 100644 --- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java @@ -38,7 +38,7 @@ import javax.management.remote.rmi.RMIConnector; * @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 --git a/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java b/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java index 50777b00220..b202163e3eb 100644 --- a/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java +++ b/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java @@ -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 --git a/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java index 8ebbc44e461..ea34bf8bd11 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java @@ -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 --git a/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java index 94f3a1ba170..d7123797f83 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java index fc987a3e5c1..25a3a68348d 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java index aaf155d5444..5215d82fbb0 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java index b3b26bc75cc..d3db82cefe6 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java index 9bc2b10a725..c19e58a73b6 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java index e44246fc3a6..bfeb6c90b4f 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java b/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java index 3b5bee35e95..a7614d28c4a 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS DTLSNotEnabledRC4Test diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java index 2e1c9d56cc4..a1ef8ce4dc8 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java index ff7bac90ea3..bfe5b7e9b2c 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java index dff5a8a0c1f..5a761043e26 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java index 7eb019d95df..1475f8b8f05 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS diff --git a/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java b/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java index e7c51741e69..3eef84e94e9 100644 --- a/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java +++ b/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLS DTLSUnsupportedCiphersTest diff --git a/jdk/test/javax/net/ssl/DTLS/TEST.properties b/jdk/test/javax/net/ssl/DTLS/TEST.properties index 080af05306b..7f6fae9daff 100644 --- a/jdk/test/javax/net/ssl/DTLS/TEST.properties +++ b/jdk/test/javax/net/ssl/DTLS/TEST.properties @@ -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 --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java index bcbdd753389..be6601a323b 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java index 0a73dbf61b9..95bf8ed9bc6 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java index c84c364af48..7976c9d1c3f 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java index 9ed88f685af..d85d91149a2 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java index 92b5dab1880..66bcc2e290d 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java index 43567e5c0d9..baec575c1cc 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java index 61a38889c06..620ff49ba2a 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java index a4d4f4394f3..33316753cd1 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 DTLSv10NotEnabledRC4Test diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java index 4af0fc0e0af..3349cb67b9d 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java index 7677baa76c5..f69afe69057 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java index 560e924d322..ccaefc41d4a 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java index edf14364002..ea707361335 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java index 2d10634c71e..685bac2dc1e 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java +++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=DTLSv1.0 diff --git a/jdk/test/javax/net/ssl/DTLSv10/TEST.properties b/jdk/test/javax/net/ssl/DTLSv10/TEST.properties index 080af05306b..7f6fae9daff 100644 --- a/jdk/test/javax/net/ssl/DTLSv10/TEST.properties +++ b/jdk/test/javax/net/ssl/DTLSv10/TEST.properties @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TEST.properties b/jdk/test/javax/net/ssl/TLS/TEST.properties index 8c058b4a7d0..a007063b293 100644 --- a/jdk/test/javax/net/ssl/TLS/TEST.properties +++ b/jdk/test/javax/net/ssl/TLS/TEST.properties @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java b/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java index 0f51afd3959..674cf523af6 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java b/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java index 8a2957b2f5d..f226f526ea6 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java b/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java index 65d8d6c4990..e5c8db98282 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java b/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java index 9b09fe2a928..19917c1a6f4 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java b/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java index edd8898f4a5..3b42c31ae0f 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java b/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java index 38b7116f71c..ad9b2fd3eab 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java +++ b/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java index 36be822b53e..ef3f98fd630 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java index cc8fc79d994..8221c8d1a2c 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java index 0b277b2432a..d1e15cb43b3 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java b/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java index 843f9678574..f91518854c1 100644 --- a/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java +++ b/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java @@ -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 --git a/jdk/test/javax/net/ssl/TLSv1/TEST.properties b/jdk/test/javax/net/ssl/TLSv1/TEST.properties index 080af05306b..7f6fae9daff 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TEST.properties +++ b/jdk/test/javax/net/ssl/TLSv1/TEST.properties @@ -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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java index 4e357e5755d..0d19c6b7ec8 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java index e0418c495d0..07db56ac79e 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java index bddcc189a39..a1a9bd33212 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java index 8b213eb1e2a..10d8cbfb1e4 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java b/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java index 1a8f544ab84..e6b16688c55 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 TLSNotEnabledRC4Test diff --git a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java index 8208b6bf255..7f880525ccf 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java index 3eb59d07cfe..cdbc16f5c46 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 TLSRehandshakeWithCipherChangeTest diff --git a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java index 17cce20c001..46b50da7ad3 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java b/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java index 357b9e4dab8..b3e3e605545 100644 --- a/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java +++ b/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1 TLSUnsupportedCiphersTest diff --git a/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java b/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java index 3e86849470c..ca6b0d7ccf6 100644 --- a/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java +++ b/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @author Xuelei Fan diff --git a/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java index a8f944084a6..6ea71c0a137 100644 --- a/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java +++ b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @author Xuelei Fan diff --git a/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java index 47939ecdd76..df08c5dbff6 100644 --- a/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java +++ b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm ExportableStreamCipher diff --git a/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java b/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java index 067da2ab322..286992d93d3 100644 --- a/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java +++ b/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm GenericBlockCipher diff --git a/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java b/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java index e84f0149982..2c61321d6d3 100644 --- a/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java +++ b/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm GenericStreamCipher diff --git a/jdk/test/javax/net/ssl/TLSv11/TEST.properties b/jdk/test/javax/net/ssl/TLSv11/TEST.properties index 080af05306b..7f6fae9daff 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TEST.properties +++ b/jdk/test/javax/net/ssl/TLSv11/TEST.properties @@ -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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java index fa3051fcb1b..7bb0abf5bd5 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java index d56b2c79656..8c942c5b55e 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java index 437181e0d0a..390b480a1ff 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java index 1a0abbbca2c..f1dc84eefeb 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java b/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java index 629edfab22f..6dad7ac0c38 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSNotEnabledRC4Test diff --git a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java index b4b2b784521..ff18d91f5ba 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java index bd537156fe8..c42454a9043 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSRehandshakeWithCipherChangeTest diff --git a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java index 43df7e98184..73fc73cb87a 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * 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 --git a/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java b/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java index afab2fda060..7d270f50655 100644 --- a/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java +++ b/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java @@ -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.internal.crypto + * 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 + * java.security.jgss/sun.security.krb5.internal.crypto * java.security.jgss/sun.security.krb5.internal.ktab * java.base/sun.security.util * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSUnsupportedCiphersTest diff --git a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java index d3219521d74..1309d74ee79 100644 --- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java @@ -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 --git a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java index 3ca088de0ec..e3b23493f3e 100644 --- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java @@ -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 --git a/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java b/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java index 0b62dda59d0..9f7e5d2ffd9 100644 --- a/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java +++ b/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java @@ -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 --git a/jdk/test/javax/swing/JLabel/7004134/bug7004134.java b/jdk/test/javax/swing/JLabel/7004134/bug7004134.java index 9440d142ef6..7190dc9e010 100644 --- a/jdk/test/javax/swing/JLabel/7004134/bug7004134.java +++ b/jdk/test/javax/swing/JLabel/7004134/bug7004134.java @@ -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 --git a/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java b/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java index b15194aef4d..6a8c132c4e4 100644 --- a/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java +++ b/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java @@ -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 --git a/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java b/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java index 098defe2eb7..4d16656628a 100644 --- a/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java +++ b/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java @@ -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 --git a/jdk/test/javax/swing/JSlider/6794836/bug6794836.java b/jdk/test/javax/swing/JSlider/6794836/bug6794836.java index 0f4258d83d3..5c84aa1b444 100644 --- a/jdk/test/javax/swing/JSlider/6794836/bug6794836.java +++ b/jdk/test/javax/swing/JSlider/6794836/bug6794836.java @@ -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 --git a/jdk/test/javax/swing/JSlider/6848475/bug6848475.java b/jdk/test/javax/swing/JSlider/6848475/bug6848475.java index e4f5bfccc69..4fb81d34dcd 100644 --- a/jdk/test/javax/swing/JSlider/6848475/bug6848475.java +++ b/jdk/test/javax/swing/JSlider/6848475/bug6848475.java @@ -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 --git a/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java b/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java index c79a398b0e9..16164ab8ff0 100644 --- a/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java +++ b/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java @@ -29,6 +29,7 @@ import java.lang.reflect.Method; /* @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 --git a/jdk/test/javax/swing/JTree/6263446/bug6263446.java b/jdk/test/javax/swing/JTree/6263446/bug6263446.java index 698255a44e4..7094971e383 100644 --- a/jdk/test/javax/swing/JTree/6263446/bug6263446.java +++ b/jdk/test/javax/swing/JTree/6263446/bug6263446.java @@ -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 --git a/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java index 2314e3d749b..3a6c25f1eec 100644 --- a/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java +++ b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java @@ -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 --git a/jdk/test/javax/swing/Security/6938813/bug6938813.java b/jdk/test/javax/swing/Security/6938813/bug6938813.java index ba71ec990b1..21aed3f418c 100644 --- a/jdk/test/javax/swing/Security/6938813/bug6938813.java +++ b/jdk/test/javax/swing/Security/6938813/bug6938813.java @@ -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 --git a/jdk/test/javax/swing/border/Test7149090.java b/jdk/test/javax/swing/border/Test7149090.java index f93dc8ecd2e..11d33ecb1fe 100644 --- a/jdk/test/javax/swing/border/Test7149090.java +++ b/jdk/test/javax/swing/border/Test7149090.java @@ -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 --git a/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java b/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java index be1b983b195..f1e1cbb94aa 100644 --- a/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java +++ b/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java @@ -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 --git a/jdk/test/javax/swing/text/View/8014863/bug8014863.java b/jdk/test/javax/swing/text/View/8014863/bug8014863.java index 9205349895e..30e54b69c69 100644 --- a/jdk/test/javax/swing/text/View/8014863/bug8014863.java +++ b/jdk/test/javax/swing/text/View/8014863/bug8014863.java @@ -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 --git a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java index daa9451acf1..d5c31961aca 100644 --- a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java +++ b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java @@ -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 --git a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java index 32254e4fb4d..015b49ace73 100644 --- a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java +++ b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java @@ -31,7 +31,7 @@ import java.lang.reflect.Method; * 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 --git a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java index 46f919e0a12..7d13864872c 100644 --- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java +++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java @@ -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 --git a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java index 65e2b587388..2d575be55d9 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java @@ -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 @@ public class CopyCommon { 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 --git a/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java index 2be9c57a649..ab573e3247d 100644 --- a/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java +++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java @@ -152,6 +152,9 @@ public class CallerSensitiveFinder { 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 --git a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java index a0a32fce292..cd25a49c31c 100644 --- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java +++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java @@ -50,15 +50,15 @@ public class VerifyModuleDelegation { 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 --git a/jdk/test/jdk/modules/open/Basic.java b/jdk/test/jdk/modules/open/Basic.java new file mode 100644 index 00000000000..2af576e61e1 --- /dev/null +++ b/jdk/test/jdk/modules/open/Basic.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m1/module-info.java b/jdk/test/jdk/modules/open/modules/m1/module-info.java new file mode 100644 index 00000000000..222a167f080 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m1/module-info.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java b/jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java new file mode 100644 index 00000000000..ab6a41742c1 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m1/p/PublicType.java b/jdk/test/jdk/modules/open/modules/m1/p/PublicType.java new file mode 100644 index 00000000000..77ab58e2fb5 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m1/p/PublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java b/jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java new file mode 100644 index 00000000000..2509f4e4982 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java b/jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java new file mode 100644 index 00000000000..0f6202373ed --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m2/module-info.java b/jdk/test/jdk/modules/open/modules/m2/module-info.java new file mode 100644 index 00000000000..a55d4f5df5d --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m2/module-info.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java b/jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java new file mode 100644 index 00000000000..43f252b1aab --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m2/q/PublicType.java b/jdk/test/jdk/modules/open/modules/m2/q/PublicType.java new file mode 100644 index 00000000000..4a14f4b1532 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m2/q/PublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java b/jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java new file mode 100644 index 00000000000..4ddfe2903d9 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java @@ -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 --git a/jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java b/jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java new file mode 100644 index 00000000000..a7df382cc11 --- /dev/null +++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java @@ -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 --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java index 05ff04d6700..5897d671321 100644 --- a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java @@ -58,10 +58,10 @@ public class Main { 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 --git a/jdk/test/sun/net/idn/TestStringPrep.java b/jdk/test/sun/net/idn/TestStringPrep.java index 493d4bff041..95340ae720f 100644 --- a/jdk/test/sun/net/idn/TestStringPrep.java +++ b/jdk/test/sun/net/idn/TestStringPrep.java @@ -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 --git a/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java b/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java index 8a509cb82ba..4396e0edab3 100644 --- a/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java +++ b/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java @@ -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 --git a/jdk/test/sun/net/www/protocol/http/NoNTLM.java b/jdk/test/sun/net/www/protocol/http/NoNTLM.java index a0b74a36b30..cc71619604a 100644 --- a/jdk/test/sun/net/www/protocol/http/NoNTLM.java +++ b/jdk/test/sun/net/www/protocol/http/NoNTLM.java @@ -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 --git a/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java b/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java index bbe5024e501..d057e95a695 100644 --- a/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java +++ b/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java @@ -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 --git a/jdk/test/sun/security/krb5/RFC396xTest.java b/jdk/test/sun/security/krb5/RFC396xTest.java index 186a624803b..18814aca89a 100644 --- a/jdk/test/sun/security/krb5/RFC396xTest.java +++ b/jdk/test/sun/security/krb5/RFC396xTest.java @@ -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 --git a/jdk/test/sun/security/krb5/auto/Renew.java b/jdk/test/sun/security/krb5/auto/Renew.java index f6c8932289b..41e3fcde6b5 100644 --- a/jdk/test/sun/security/krb5/auto/Renew.java +++ b/jdk/test/sun/security/krb5/auto/Renew.java @@ -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 --git a/jdk/test/sun/security/krb5/auto/TEST.properties b/jdk/test/sun/security/krb5/auto/TEST.properties index 35a55e5d17c..777c20d8233 100644 --- a/jdk/test/sun/security/krb5/auto/TEST.properties +++ b/jdk/test/sun/security/krb5/auto/TEST.properties @@ -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 --git a/jdk/test/sun/security/krb5/ccache/TimeInCCache.java b/jdk/test/sun/security/krb5/ccache/TimeInCCache.java index 5a9364fd8e1..e88c6b0583b 100644 --- a/jdk/test/sun/security/krb5/ccache/TimeInCCache.java +++ b/jdk/test/sun/security/krb5/ccache/TimeInCCache.java @@ -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 --git a/jdk/test/sun/security/krb5/config/DefUdpLimit.java b/jdk/test/sun/security/krb5/config/DefUdpLimit.java index 58c6c6dacfb..0674f2439bb 100644 --- a/jdk/test/sun/security/krb5/config/DefUdpLimit.java +++ b/jdk/test/sun/security/krb5/config/DefUdpLimit.java @@ -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 --git a/jdk/test/sun/security/krb5/config/DnsFallback.java b/jdk/test/sun/security/krb5/config/DnsFallback.java index 1def972f7d6..57ecafea0a2 100644 --- a/jdk/test/sun/security/krb5/config/DnsFallback.java +++ b/jdk/test/sun/security/krb5/config/DnsFallback.java @@ -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 --git a/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java index 40ec7d6c386..c8dd06427b9 100644 --- a/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java +++ b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java @@ -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 --git a/jdk/test/sun/security/krb5/tools/KtabZero.java b/jdk/test/sun/security/krb5/tools/KtabZero.java index 6cc2a527380..3f4246e65e2 100644 --- a/jdk/test/sun/security/krb5/tools/KtabZero.java +++ b/jdk/test/sun/security/krb5/tools/KtabZero.java @@ -34,7 +34,7 @@ import java.nio.file.Paths; * @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 --git a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java index 55811ddaf53..e7fafc10fb5 100644 --- a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java +++ b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java @@ -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 --git a/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java b/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java index 22f1f0c66b9..8908149de54 100644 --- a/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java +++ b/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java @@ -33,7 +33,8 @@ import java.security.Security; /** * @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 --git a/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java index aaf005d44bb..410bf0cacb2 100644 --- a/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java +++ b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java @@ -32,7 +32,7 @@ import java.lang.reflect.Field; /** * @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 --git a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java index d6b5280f98b..89c50b26027 100644 --- a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java +++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java @@ -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 --git a/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java b/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java index c10835066ff..c07124087f8 100644 --- a/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java +++ b/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java @@ -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 --git a/jdk/test/sun/security/tools/keytool/StartDateTest.java b/jdk/test/sun/security/tools/keytool/StartDateTest.java index d558ff6a49f..64f88603ec8 100644 --- a/jdk/test/sun/security/tools/keytool/StartDateTest.java +++ b/jdk/test/sun/security/tools/keytool/StartDateTest.java @@ -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 --git a/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java b/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java index 77cea3ffe3f..2d040923a4f 100644 --- a/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java +++ b/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java @@ -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 --git a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java index 046a7edb39c..6d91b5b3eff 100644 --- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java +++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java @@ -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 --git a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java index 0c1d7650c48..14cbfe8c77d 100644 --- a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java +++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java @@ -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 --git a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java index cbe449ad4ed..fce5344acbf 100644 --- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java +++ b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java @@ -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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { 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 @@ public class ConcealedPackage { ); 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 --git a/jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java b/jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java new file mode 100644 index 00000000000..9bb4385e983 --- /dev/null +++ b/jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java @@ -0,0 +1,7 @@ +package p.internal.bar; + +public class Gee { + public void geeWhiz() { + System.out.println("Gee whiz"); + } +} diff --git a/jdk/test/tools/jar/modularJar/Basic.java b/jdk/test/tools/jar/modularJar/Basic.java index 073eabc9896..45ef7897b43 100644 --- a/jdk/test/tools/jar/modularJar/Basic.java +++ b/jdk/test/tools/jar/modularJar/Basic.java @@ -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 @@ public class Basic { 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 @@ public class Basic { 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 @@ public class Basic { 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 @@ public class Basic { 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 @@ public class Basic { 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 @@ public class Basic { "--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 @@ public class Basic { "--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 @@ public class Basic { "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 @@ public class Basic { .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 @@ public class Basic { "-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 @@ public class Basic { 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 @@ public class Basic { } } + 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, @@ -816,6 +901,8 @@ public class Basic { commands.add("-d"); 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"); } @@ -848,17 +935,10 @@ public class Basic { 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 --git a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java index 5267814d711..92329265533 100644 --- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java +++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java @@ -26,10 +26,14 @@ package jdk.test.bar; 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 @@ public class Bar { 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 --git a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java index 3e0ce9fa601..7366bc85c3c 100644 --- a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java +++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java @@ -26,7 +26,10 @@ package jdk.test.foo; 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 @@ public class Foo { 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 --git a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties new file mode 100644 index 00000000000..99b4d5bfb92 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties @@ -0,0 +1 @@ +name = foo diff --git a/jdk/test/tools/jar/multiRelease/Basic.java b/jdk/test/tools/jar/multiRelease/Basic.java index 0c7f77eb5d9..1d559ad1262 100644 --- a/jdk/test/tools/jar/multiRelease/Basic.java +++ b/jdk/test/tools/jar/multiRelease/Basic.java @@ -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.nio.file.attribute.*; 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 @@ public class Basic { "--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 @@ public class Basic { "--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 @@ public class Basic { 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 --git a/jdk/test/tools/jar/multiRelease/Basic1.java b/jdk/test/tools/jar/multiRelease/Basic1.java new file mode 100644 index 00000000000..792b128d3bd --- /dev/null +++ b/jdk/test/tools/jar/multiRelease/Basic1.java @@ -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 --git a/jdk/test/tools/jlink/IntegrationTest.java b/jdk/test/tools/jlink/IntegrationTest.java index 17dcfdec5a9..8d6bb303bdc 100644 --- a/jdk/test/tools/jlink/IntegrationTest.java +++ b/jdk/test/tools/jlink/IntegrationTest.java @@ -59,7 +59,6 @@ import tests.JImageGenerator; * @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 --git a/jdk/test/tools/jlink/JLinkNegativeTest.java b/jdk/test/tools/jlink/JLinkNegativeTest.java index 95ed27b5510..f8ac8093f33 100644 --- a/jdk/test/tools/jlink/JLinkNegativeTest.java +++ b/jdk/test/tools/jlink/JLinkNegativeTest.java @@ -274,7 +274,7 @@ public class JLinkNegativeTest { 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 @@ public class JLinkNegativeTest { 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 --git a/jdk/test/tools/jlink/JLinkTest.java b/jdk/test/tools/jlink/JLinkTest.java index 79a920b4be6..4d12ddcb3bc 100644 --- a/jdk/test/tools/jlink/JLinkTest.java +++ b/jdk/test/tools/jlink/JLinkTest.java @@ -62,9 +62,11 @@ public class JLinkTest { // 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 --git a/jdk/test/tools/jlink/basic/AllModulePath.java b/jdk/test/tools/jlink/basic/AllModulePath.java new file mode 100644 index 00000000000..3053c34121a --- /dev/null +++ b/jdk/test/tools/jlink/basic/AllModulePath.java @@ -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 --git a/jdk/test/tools/jlink/basic/BasicTest.java b/jdk/test/tools/jlink/basic/BasicTest.java index 6ddc4a190f9..87b2b0ef69d 100644 --- a/jdk/test/tools/jlink/basic/BasicTest.java +++ b/jdk/test/tools/jlink/basic/BasicTest.java @@ -59,10 +59,11 @@ public class BasicTest { 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 @@ public class BasicTest { 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 --git a/jdk/test/java/lang/Class/getResource/src/m3/module-info.java b/jdk/test/tools/jlink/basic/src/m1/module-info.java similarity index 91% rename from jdk/test/java/lang/Class/getResource/src/m3/module-info.java rename to jdk/test/tools/jlink/basic/src/m1/module-info.java index f9754a0a870..f6ecf6b2bf5 100644 --- a/jdk/test/java/lang/Class/getResource/src/m3/module-info.java +++ b/jdk/test/tools/jlink/basic/src/m1/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,6 +21,5 @@ * questions. */ -module m3 { - exports p3; +module m1 { } diff --git a/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java b/jdk/test/tools/jlink/basic/src/m1/p/ListModules.java similarity index 57% rename from jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java rename to jdk/test/tools/jlink/basic/src/m1/p/ListModules.java index a03d8eb2c7e..611946c59e0 100644 --- a/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java +++ b/jdk/test/tools/jlink/basic/src/m1/p/ListModules.java @@ -1,5 +1,5 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +/** + * 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 @@ -21,24 +21,28 @@ * questions. */ -package test; +package p; -import java.util.HashSet; -import java.util.ServiceLoader; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.util.Arrays; import java.util.Set; -import javax.script.ScriptEngineFactory; +import java.util.stream.Collectors; -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()); +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); } - for (String engine: args) { - if (!engines.contains(engine)) - throw new RuntimeException(engine + " not found"); - } } } diff --git a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java index 712f9878c47..9137ed30e1e 100644 --- a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java +++ b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java @@ -75,11 +75,11 @@ public class FileCopierPluginTest { 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 @@ public class FileCopierPluginTest { 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 --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java index 7b4a1bc785c..d74b6b84152 100644 --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java @@ -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 @@ public class SystemModulesTest { } 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 @@ public class SystemModulesTest { } } + 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 --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java index a56da486ba0..0875db2585c 100644 --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java @@ -52,9 +52,11 @@ public class UserModuleTest { 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 @@ public class UserModuleTest { FileUtils.deleteFileTreeUnchecked(IMAGE); } - createImage(IMAGE, "java.base", "m1"); + createImage(IMAGE, "java.base", "m1", "m3"); } private void createImage(Path outputDir, String... modules) throws Throwable { @@ -96,19 +98,33 @@ public class UserModuleTest { /* * 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 @@ public class UserModuleTest { 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 @@ public class UserModuleTest { 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 --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java index 40bb1ca9249..d19856a3703 100644 --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java @@ -48,7 +48,6 @@ public class Main { } static void validate(ModuleDescriptor md) { - checkPackages(md.conceals(), "p1", "p2"); checkPackages(md.packages(), "p1", "p2"); } diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java index b164b24e95c..c2e7fb62e4c 100644 --- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java @@ -22,4 +22,5 @@ */ module m3 { + requires m4; } diff --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java new file mode 100644 index 00000000000..c7ff38e6d50 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java @@ -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 --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java new file mode 100644 index 00000000000..c57da1b82bd --- /dev/null +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java @@ -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 --git a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java new file mode 100644 index 00000000000..84447c5ea90 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java @@ -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 --git a/jdk/test/tools/jmod/JmodTest.java b/jdk/test/tools/jmod/JmodTest.java index f3224c26904..46a9217d4f0 100644 --- a/jdk/test/tools/jmod/JmodTest.java +++ b/jdk/test/tools/jmod/JmodTest.java @@ -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 @@ public class JmodTest { 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 @@ public class JmodTest { 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 @@ public class JmodTest { 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 @@ public class JmodTest { .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 + "]"); }); } @@ -368,6 +373,26 @@ public class JmodTest { ); } + @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") @@ -557,6 +582,14 @@ public class JmodTest { } } + 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 --git a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java b/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java index a269fd5ea8c..8a130077fec 100644 --- a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java +++ b/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java @@ -22,5 +22,5 @@ */ module org.bar { - requires public m1; + requires transitive m1; } diff --git a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java b/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java index b143d5b0ece..056399028b6 100644 --- a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java +++ b/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java @@ -22,5 +22,5 @@ */ module org.foo { - requires public org.bar; + requires transitive org.bar; } diff --git a/jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties b/jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties new file mode 100644 index 00000000000..8f6224de144 --- /dev/null +++ b/jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties @@ -0,0 +1 @@ +name = foo diff --git a/jdk/test/tools/launcher/InfoStreams.java b/jdk/test/tools/launcher/InfoStreams.java new file mode 100644 index 00000000000..dc0e2da00b9 --- /dev/null +++ b/jdk/test/tools/launcher/InfoStreams.java @@ -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 --git a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java index cc9b1743855..c92824f39da 100644 --- a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java +++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java @@ -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 @@ public class AddExportsTest { /** - * --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,24 +222,34 @@ public class AddExportsTest { } + 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() { return new Object[][]{ @@ -250,20 +264,20 @@ public class AddExportsTest { /** - * 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 --git a/jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java b/jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java new file mode 100644 index 00000000000..c9abb2cf067 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java @@ -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 --git a/jdk/test/tools/launcher/modules/addexports/manifest/Test1.java b/jdk/test/tools/launcher/modules/addexports/manifest/Test1.java new file mode 100644 index 00000000000..1d9aaf6565d --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test1.java @@ -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 --git a/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java b/jdk/test/tools/launcher/modules/addexports/manifest/Test2.java similarity index 69% rename from jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java rename to jdk/test/tools/launcher/modules/addexports/manifest/Test2.java index 08062e1d831..2d9fba1c14f 100644 --- a/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java +++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test2.java @@ -1,5 +1,5 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +/** + * 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 @@ -21,19 +21,17 @@ * questions. */ -package p3; +import java.lang.reflect.Field; -import java.io.InputStream; -import java.net.URL; +/** + * Use core reflection and setAccessible(true) to access private field. + */ -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); +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 --git a/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java index 6efbbdf90fa..e3d3936fea2 100644 --- a/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java +++ b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java @@ -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 --git a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java index 793e12efe57..eb21d2d5333 100644 --- a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java +++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java @@ -115,7 +115,7 @@ public class ListModsTest { .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 --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java index 746ce3f974b..b5fdfea89a7 100644 --- a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java @@ -22,6 +22,6 @@ */ module java.transaction { - requires public java.enterprise; + requires transitive java.enterprise; exports javax.transaction; } diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java index ac54c143435..144405e5ddf 100644 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java @@ -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.CharacterRangeTable_attribute; 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.Descriptor.InvalidDescriptor; 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.Instruction.TypeKind; 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_ 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 @@ class AttributeVisitor implements Attribute.Visitor { } @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 @@ class AttributeVisitor implements Attribute.Visitor { 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 @@ class AttributeVisitor implements Attribute.Visitor { 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 @@ class AttributeVisitor implements Attribute.Visitor { } @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 @@ class AttributeVisitor implements Attribute.Visitor { } @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 @@ class AttributeVisitor implements Attribute.Visitor { } @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 @@ class AttributeVisitor implements Attribute.Visitor { } @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 @@ class AnnotationsElementVisitor implements Annotation.element_value.Visitor