Mercurial > hg > openjdk > jdk9 > jdk
changeset 16959:fa3c4a60a616
8177530: Module system implementation refresh (4/2017)
Reviewed-by: mchung, alanb
Contributed-by: alan.bateman@oracle.com, mandy.chung@oracle.com
line wrap: on
line diff
--- a/make/mapfiles/libjava/mapfile-vers Thu Apr 06 17:01:03 2017 +0000 +++ b/make/mapfiles/libjava/mapfile-vers Fri Apr 07 08:05:54 2017 +0000 @@ -273,12 +273,12 @@ Java_jdk_internal_misc_VM_getRuntimeArguments; Java_jdk_internal_misc_VM_initialize; - Java_java_lang_reflect_Module_defineModule0; - Java_java_lang_reflect_Module_addReads0; - Java_java_lang_reflect_Module_addExports0; - Java_java_lang_reflect_Module_addExportsToAll0; - Java_java_lang_reflect_Module_addExportsToAllUnnamed0; - Java_java_lang_reflect_Module_addPackage0; + Java_java_lang_Module_defineModule0; + Java_java_lang_Module_addReads0; + Java_java_lang_Module_addExports0; + Java_java_lang_Module_addExportsToAll0; + Java_java_lang_Module_addExportsToAllUnnamed0; + Java_java_lang_Module_addPackage0; Java_jdk_internal_loader_BootLoader_getSystemPackageLocation; Java_jdk_internal_loader_BootLoader_getSystemPackageNames;
--- a/src/java.base/share/classes/java/io/ObjectInputFilter.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/io/ObjectInputFilter.java Fri Apr 07 08:05:54 2017 +0000 @@ -322,7 +322,7 @@ * Other patterns match or reject class or package name * as returned from {@link Class#getName() Class.getName()} and * if an optional module name is present - * {@link java.lang.reflect.Module#getName() class.getModule().getName()}. + * {@link Module#getName() class.getModule().getName()}. * Note that for arrays the element type is used in the pattern, * not the array type. * <ul>
--- a/src/java.base/share/classes/java/lang/Class.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/Class.java Fri Apr 07 08:05:54 2017 +0000 @@ -43,7 +43,6 @@ 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; @@ -2561,21 +2560,16 @@ public InputStream getResourceAsStream(String name) { name = resolveName(name); - Module module = getModule(); - if (module.isNamed()) { - if (Resources.canEncapsulate(name)) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != module) { - Set<String> packages = module.getDescriptor().packages(); - String pn = Resources.toPackageName(name); - if (packages.contains(pn) && !module.isOpen(pn, caller)) { - // resource is in package not open to caller - return null; - } - } + Module thisModule = getModule(); + if (thisModule.isNamed()) { + // check if resource can be located by caller + if (Resources.canEncapsulate(name) + && !isOpenToCaller(name, Reflection.getCallerClass())) { + return null; } - String mn = module.getName(); + // resource not encapsulated or in package open to caller + String mn = thisModule.getName(); ClassLoader cl = getClassLoader0(); try { @@ -2663,20 +2657,16 @@ public URL getResource(String name) { name = resolveName(name); - Module module = getModule(); - if (module.isNamed()) { - if (Resources.canEncapsulate(name)) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != module) { - Set<String> packages = module.getDescriptor().packages(); - String pn = Resources.toPackageName(name); - if (packages.contains(pn) && !module.isOpen(pn, caller)) { - // resource is in package not open to caller - return null; - } - } + Module thisModule = getModule(); + if (thisModule.isNamed()) { + // check if resource can be located by caller + if (Resources.canEncapsulate(name) + && !isOpenToCaller(name, Reflection.getCallerClass())) { + return null; } - String mn = getModule().getName(); + + // resource not encapsulated or in package open to caller + String mn = thisModule.getName(); ClassLoader cl = getClassLoader0(); try { if (cl == null) { @@ -2698,10 +2688,36 @@ } } + /** + * Returns true if a resource with the given name can be located by the + * given caller. All resources in a module can be located by code in + * the module. For other callers, then the package needs to be open to + * the caller. + */ + private boolean isOpenToCaller(String name, Class<?> caller) { + // assert getModule().isNamed(); + Module thisModule = getModule(); + Module callerModule = (caller != null) ? caller.getModule() : null; + if (callerModule != thisModule) { + String pn = Resources.toPackageName(name); + if (thisModule.getDescriptor().packages().contains(pn)) { + if (callerModule == null && !thisModule.isOpen(pn)) { + // no caller, package not open + return false; + } + if (!thisModule.isOpen(pn, callerModule)) { + // package not open to caller + return false; + } + } + } + return true; + } + + /** protection domain returned when the internal domain is null */ private static java.security.ProtectionDomain allPermDomain; - /** * Returns the {@code ProtectionDomain} of this class. If there is a * security manager installed, this method first calls the security
--- a/src/java.base/share/classes/java/lang/ClassLoader.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/ClassLoader.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,7 +31,6 @@ import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.Module; import java.net.URL; import java.security.AccessController; import java.security.AccessControlContext; @@ -352,9 +351,7 @@ private ClassLoader(Void unused, String name, ClassLoader parent) { this.name = name; this.parent = parent; - this.unnamedModule - = SharedSecrets.getJavaLangReflectModuleAccess() - .defineUnnamedModule(this); + this.unnamedModule = new Module(this); if (ParallelLoaders.isRegistered(this.getClass())) { parallelLockMap = new ConcurrentHashMap<>(); package2certs = new ConcurrentHashMap<>();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/lang/LayerInstantiationException.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when creating a {@linkplain ModuleLayer module layer} fails. + * + * @see ModuleLayer + * @since 9 + * @spec JPMS + */ +public class LayerInstantiationException extends RuntimeException { + private static final long serialVersionUID = -906239691613568347L; + + /** + * Constructs a {@code LayerInstantiationException} with no detail message. + */ + public LayerInstantiationException() { + } + + /** + * Constructs a {@code LayerInstantiationException} with the given detail + * message. + * + * @param msg + * The detail message; can be {@code null} + */ + public LayerInstantiationException(String msg) { + super(msg); + } + + /** + * Constructs a {@code LayerInstantiationException} with the given cause. + * + * @param cause + * The cause; can be {@code null} + */ + public LayerInstantiationException(Throwable cause) { + super(cause); + } + + /** + * Constructs a {@code FindException} with the given detail message + * and cause. + * + * @param msg + * The detail message; can be {@code null} + * @param cause + * The cause; can be {@code null} + */ + public LayerInstantiationException(String msg, Throwable cause) { + super(msg, cause); + } + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/lang/Module.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,1586 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +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.Opens; +import java.lang.module.ModuleDescriptor.Version; +import java.lang.module.ResolvedModule; +import java.lang.reflect.AnnotatedElement; +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; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.loader.BootLoader; +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.ServicesCatalog; +import jdk.internal.module.Resources; +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; + +/** + * Represents a run-time module, either {@link #isNamed() named} or unnamed. + * + * <p> Named modules have a {@link #getName() name} and are constructed by the + * Java Virtual Machine when a graph of modules is defined to the Java virtual + * machine to create a {@linkplain ModuleLayer module layer}. </p> + * + * <p> An unnamed module does not have a name. There is an unnamed module for + * each {@link ClassLoader ClassLoader}, obtained by invoking its {@link + * ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are + * not in a named module are members of their defining class loader's unnamed + * module. </p> + * + * <p> The package names that are parameters or returned by methods defined in + * this class are the fully-qualified names of the packages as defined in + * section 6.5.3 of <cite>The Java™ Language Specification</cite>, for + * example, {@code "java.lang"}. </p> + * + * <p> Unless otherwise specified, passing a {@code null} argument to a method + * in this class causes a {@link NullPointerException NullPointerException} to + * be thrown. </p> + * + * @since 9 + * @spec JPMS + * @see Class#getModule() + */ + +public final class Module implements AnnotatedElement { + + // the layer that contains this module, can be null + private final ModuleLayer layer; + + // module name and loader, these fields are read by VM + private final String name; + private final ClassLoader loader; + + // the module descriptor + private final ModuleDescriptor descriptor; + + + /** + * Creates a new named Module. The resulting Module will be defined to the + * VM but will not read any other modules, will not have any exports setup + * and will not be registered in the service catalog. + */ + Module(ModuleLayer layer, + ClassLoader loader, + ModuleDescriptor descriptor, + URI uri) + { + this.layer = layer; + this.name = descriptor.name(); + this.loader = loader; + this.descriptor = descriptor; + + // 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); + String[] packages = descriptor.packages().toArray(new String[0]); + defineModule0(this, isOpen, vs, loc, packages); + } + + + /** + * Create the unnamed Module for the given ClassLoader. + * + * @see ClassLoader#getUnnamedModule + */ + Module(ClassLoader loader) { + this.layer = null; + this.name = null; + this.loader = loader; + this.descriptor = null; + } + + + /** + * Creates a named module but without defining the module to the VM. + * + * @apiNote This constructor is for VM white-box testing. + */ + Module(ClassLoader loader, ModuleDescriptor descriptor) { + this.layer = null; + this.name = descriptor.name(); + this.loader = loader; + this.descriptor = descriptor; + } + + + + /** + * Returns {@code true} if this module is a named module. + * + * @return {@code true} if this is a named module + * + * @see ClassLoader#getUnnamedModule() + */ + public boolean isNamed() { + return name != null; + } + + /** + * Returns the module name or {@code null} if this module is an unnamed + * module. + * + * @return The module name + */ + public String getName() { + return name; + } + + /** + * Returns the {@code ClassLoader} for this module. + * + * <p> If there is a security manager then its {@code checkPermission} + * method if first called with a {@code RuntimePermission("getClassLoader")} + * permission to check that the caller is allowed to get access to the + * class loader. </p> + * + * @return The class loader for this module + * + * @throws SecurityException + * If denied by the security manager + */ + public ClassLoader getClassLoader() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + return loader; + } + + /** + * Returns the module descriptor for this module or {@code null} if this + * module is an unnamed module. + * + * @return The module descriptor for this module + */ + public ModuleDescriptor getDescriptor() { + return descriptor; + } + + /** + * Returns the layer that contains this module or {@code null} if this + * module is not in a layer. + * + * A module layer contains named modules and therefore this method always + * returns {@code null} when invoked on an unnamed module. + * + * <p> <a href="reflect/Proxy.html#dynamicmodule">Dynamic modules</a> are + * named modules that are generated at runtime. A dynamic module may or may + * not be in a module layer. </p> + * + * @return The module layer that contains this module + * + * @see java.lang.reflect.Proxy + */ + public ModuleLayer getLayer() { + if (isNamed()) { + ModuleLayer layer = this.layer; + if (layer != null) + return layer; + + // special-case java.base as it is created before the boot layer + if (loader == null && name.equals("java.base")) { + return ModuleLayer.boot(); + } + } + return null; + } + + + // -- + + // special Module to mean "all unnamed modules" + private static final Module ALL_UNNAMED_MODULE = new Module(null); + + // special Module to mean "everyone" + private static final Module EVERYONE_MODULE = new Module(null); + + // set contains EVERYONE_MODULE, used when a package is opened or + // exported unconditionally + private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE); + + + // -- readability -- + + // the modules that this module reads + private volatile Set<Module> reads; + + // additional module (2nd key) that some module (1st key) reflectively reads + private static final WeakPairMap<Module, Module, Boolean> reflectivelyReads + = new WeakPairMap<>(); + + + /** + * Indicates if this module reads the given module. This method returns + * {@code true} if invoked to test if this module reads itself. It also + * returns {@code true} if invoked on an unnamed module (as unnamed + * modules read all modules). + * + * @param other + * The other module + * + * @return {@code true} if this module reads {@code other} + * + * @see #addReads(Module) + */ + public boolean canRead(Module other) { + Objects.requireNonNull(other); + + // an unnamed module reads all modules + if (!this.isNamed()) + return true; + + // all modules read themselves + if (other == this) + return true; + + // check if this module reads other + if (other.isNamed()) { + Set<Module> reads = this.reads; // volatile read + if (reads != null && reads.contains(other)) + return true; + } + + // check if this module reads the other module reflectively + 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() + && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE)) + return true; + + return false; + } + + /** + * 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 read + * themselves), this module is an unnamed module (as unnamed modules read + * all modules), or this module already reads {@code other}. + * + * @implNote <em>Read edges</em> added by this method are <em>weak</em> and + * do not prevent {@code other} from being GC'ed when this module is + * strongly reachable. + * + * @param other + * The other module + * + * @return this module + * + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module + * + * @see #canRead + */ + @CallerSensitive + public Module addReads(Module other) { + Objects.requireNonNull(other); + if (this.isNamed()) { + Module caller = getCallerModule(Reflection.getCallerClass()); + if (caller != this) { + throw new IllegalCallerException(caller + " != " + this); + } + implAddReads(other, true); + } + return this; + } + + /** + * Updates this module to read another module. + * + * @apiNote Used by the --add-reads command line option. + */ + void implAddReads(Module other) { + implAddReads(other, true); + } + + /** + * Updates this module to read all unnamed modules. + * + * @apiNote Used by the --add-reads command line option. + */ + void implAddReadsAllUnnamed() { + implAddReads(Module.ALL_UNNAMED_MODULE, true); + } + + /** + * Updates this module to read another module without notifying the VM. + * + * @apiNote This method is for VM white-box testing. + */ + void implAddReadsNoSync(Module other) { + implAddReads(other, false); + } + + /** + * Makes the given {@code Module} readable to this module. + * + * If {@code syncVM} is {@code true} then the VM is notified. + */ + private void implAddReads(Module other, boolean syncVM) { + Objects.requireNonNull(other); + if (!canRead(other)) { + // update VM first, just in case it fails + if (syncVM) { + if (other == ALL_UNNAMED_MODULE) { + addReads0(this, null); + } else { + addReads0(this, other); + } + } + + // add reflective read + reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE); + } + } + + + // -- exported and open packages -- + + // the packages are open to other modules, can be null + // if the value contains EVERYONE_MODULE then the package is open to all + private volatile Map<String, Set<Module>> openPackages; + + // the packages that are exported, can be null + // if the value contains EVERYONE_MODULE then the package is exported to all + private volatile Map<String, Set<Module>> 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<Module, Module, Map<String, Boolean>> + reflectivelyExports = new WeakPairMap<>(); + + + /** + * Returns {@code true} if this module exports the given package to at + * least the given module. + * + * <p> 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. </p> + * + * <p> This method does not check if the given module reads this module. </p> + * + * @param pn + * The package name + * @param other + * The other 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 implIsExportedOrOpen(pn, other, /*open*/false); + } + + /** + * Returns {@code true} if this module has <em>opened</em> a package to at + * least the given module. + * + * <p> 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. </p> + * + * <p> This method does not check if the given module reads this module. </p> + * + * @param pn + * The package name + * @param other + * The other module + * + * @return {@code true} if this module has <em>opened</em> 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. + * + * <p> 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. </p> + * + * <p> This method does not check if the given module reads this module. </p> + * + * @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 implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/false); + } + + /** + * Returns {@code true} if this module has <em>opened</em> a package + * unconditionally. + * + * <p> 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. </p> + * + * <p> This method does not check if the given module reads this module. </p> + * + * @param pn + * The package name + * + * @return {@code true} if this module has <em>opened</em> the package + * unconditionally + * + * @see ModuleDescriptor#opens() + */ + public boolean isOpen(String pn) { + Objects.requireNonNull(pn); + return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/true); + } + + + /** + * 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; + + // all packages are exported/open to self + if (other == this && containsPackage(pn)) + return true; + + // all packages in open and automatic modules are open + if (descriptor.isOpen() || descriptor.isAutomatic()) + return containsPackage(pn); + + // exported/opened via module declaration/descriptor + if (isStaticallyExportedOrOpen(pn, other, open)) + return true; + + // 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 exports or opens a package to + * the given module via its module declaration. + */ + private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) { + // package is open to everyone or <other> + Map<String, Set<Module>> openPackages = this.openPackages; + if (openPackages != null) { + Set<Module> 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 <other> + Map<String, Set<Module>> exportedPackages = this.exportedPackages; + if (exportedPackages != null) { + Set<Module> 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 or opens given + * package package to the given module. + */ + private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) { + // exported or open to all modules + Map<String, Boolean> 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 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 or open to all unnamed + if (!other.isNamed()) { + 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; + } + } + } + + } + + return false; + } + + + /** + * If the caller's module is this module then update this module to export + * the given package to the given module. + * + * <p> This method has no effect if the package is already exported (or + * <em>open</em>) to the given module. </p> + * + * @apiNote As specified in section 5.4.3 of the <cite>The Java™ + * Virtual Machine Specification </cite>, if an attempt to resolve a + * symbolic reference fails because of a linkage error, then subsequent + * attempts to resolve the reference always fail with the same error that + * was thrown as a result of the initial resolution attempt. + * + * @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 IllegalCallerException + * If this is a named module and the caller's module is not this + * module + * + * @jvms 5.4.3 Resolution + * @see #isExported(String,Module) + */ + @CallerSensitive + public Module addExports(String pn, Module other) { + if (pn == null) + throw new IllegalArgumentException("package is null"); + Objects.requireNonNull(other); + + if (isNamed()) { + Module caller = getCallerModule(Reflection.getCallerClass()); + if (caller != this) { + throw new IllegalCallerException(caller + " != " + this); + } + implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true); + } + + return this; + } + + /** + * If this module has <em>opened</em> a package to at least the caller + * module then update this module to open the 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. + * + * <p> This method has no effect if the package is already <em>open</em> + * to the given module. </p> + * + * @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 IllegalCallerException + * If this is a named module and this module has not opened the + * package to at least the caller's 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()) { + Module caller = getCallerModule(Reflection.getCallerClass()); + if (caller != this && (caller == null || !isOpen(pn, caller))) + throw new IllegalCallerException(pn + " is not open to " + caller); + implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true); + } + + return this; + } + + + /** + * Updates this module to export a package unconditionally. + * + * @apiNote This method is for JDK tests only. + */ + void implAddExports(String pn) { + implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true); + } + + /** + * Updates this module to export a package to another module. + * + * @apiNote Used by Instrumentation::redefineModule and --add-exports + */ + void implAddExports(String pn, Module other) { + implAddExportsOrOpens(pn, other, false, true); + } + + /** + * Updates this module to export a package to all unnamed modules. + * + * @apiNote Used by the --add-exports command line option. + */ + void implAddExportsToAllUnnamed(String pn) { + implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true); + } + + /** + * Updates this export to export a package unconditionally without + * notifying the VM. + * + * @apiNote This method is for VM white-box testing. + */ + void implAddExportsNoSync(String pn) { + implAddExportsOrOpens(pn.replace('/', '.'), Module.EVERYONE_MODULE, false, false); + } + + /** + * Updates a module to export a package to another module without + * notifying the VM. + * + * @apiNote This method is for VM white-box testing. + */ + void implAddExportsNoSync(String pn, Module other) { + implAddExportsOrOpens(pn.replace('/', '.'), other, false, false); + } + + /** + * Updates this module to open a package unconditionally. + * + * @apiNote This method is for JDK tests only. + */ + void implAddOpens(String pn) { + implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true); + } + + /** + * Updates this module to open a package to another module. + * + * @apiNote Used by Instrumentation::redefineModule and --add-opens + */ + void implAddOpens(String pn, Module other) { + implAddExportsOrOpens(pn, other, true, true); + } + + /** + * Updates this module to export a package to all unnamed modules. + * + * @apiNote Used by the --add-opens command line option. + */ + void implAddOpensToAllUnnamed(String pn) { + implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, 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 implAddExportsOrOpens(String pn, + Module other, + boolean open, + boolean syncVM) { + Objects.requireNonNull(other); + Objects.requireNonNull(pn); + + // all packages are open in unnamed, open, and automatic modules + if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic()) + return; + + // nothing to do if already exported/open to other + if (implIsExportedOrOpen(pn, other, open)) + return; + + // can only export a package in the module + if (!containsPackage(pn)) { + throw new IllegalArgumentException("package " + pn + + " not in contents"); + } + + // update VM first, just in case it fails + if (syncVM) { + if (other == EVERYONE_MODULE) { + addExportsToAll0(this, pn); + } else if (other == ALL_UNNAMED_MODULE) { + addExportsToAllUnnamed0(this, pn); + } else { + addExports0(this, pn, other); + } + } + + // add package name to reflectivelyExports if absent + Map<String, Boolean> map = reflectivelyExports + .computeIfAbsent(this, other, + (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<Module, Class<?>, Boolean> reflectivelyUses + = new WeakPairMap<>(); + + /** + * If the caller's module is this module then update this module to add a + * service dependence on the given service type. This method is intended + * 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 or an automatic module. + * + * <p> This method does not cause {@link Configuration#resolveAndBind + * resolveAndBind} to be re-run. </p> + * + * @param service + * The service type + * + * @return this module + * + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module + * + * @see #canUse(Class) + * @see ModuleDescriptor#uses() + */ + @CallerSensitive + public Module addUses(Class<?> service) { + Objects.requireNonNull(service); + + if (isNamed() && !descriptor.isAutomatic()) { + Module caller = getCallerModule(Reflection.getCallerClass()); + if (caller != this) { + throw new IllegalCallerException(caller + " != " + this); + } + 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 or an automatic module. + * + * @param service + * The service type + * + * @return {@code true} if this module uses service type {@code st} + * + * @see #addUses(Class) + */ + public boolean canUse(Class<?> service) { + Objects.requireNonNull(service); + + if (!isNamed()) + return true; + + if (descriptor.isAutomatic()) + return true; + + // uses was declared + if (descriptor.uses().contains(service.getName())) + return true; + + // uses added via addUses + return reflectivelyUses.containsKeyPair(this, service); + } + + + + // -- packages -- + + // Additional packages that are added to the module at run-time. + private volatile Map<String, Boolean> extraPackages; + + private boolean containsPackage(String pn) { + if (descriptor.packages().contains(pn)) + return true; + Map<String, Boolean> extraPackages = this.extraPackages; + if (extraPackages != null && extraPackages.containsKey(pn)) + return true; + return false; + } + + + /** + * Returns the set of package names for the packages in this module. + * + * <p> For named modules, the returned set contains an element for each + * package in the module. </p> + * + * <p> For unnamed modules, this method is the equivalent to invoking the + * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of + * this module's class loader and returning the set of package names. </p> + * + * @return the set of the package names of the packages in this module + */ + public Set<String> getPackages() { + if (isNamed()) { + + Set<String> packages = descriptor.packages(); + Map<String, Boolean> extraPackages = this.extraPackages; + if (extraPackages == null) { + return packages; + } else { + return Stream.concat(packages.stream(), + extraPackages.keySet().stream()) + .collect(Collectors.toSet()); + } + + } else { + // unnamed module + Stream<Package> packages; + if (loader == null) { + packages = BootLoader.packages(); + } else { + packages = SharedSecrets.getJavaLangAccess().packages(loader); + } + return packages.map(Package::getName).collect(Collectors.toSet()); + } + } + + /** + * Add a package to this module without notifying the VM. + * + * @apiNote This method is VM white-box testing. + */ + void implAddPackageNoSync(String pn) { + implAddPackage(pn.replace('/', '.'), false); + } + + /** + * Add a package to this module. + * + * If {@code syncVM} is {@code true} then the VM is notified. This method is + * a no-op if this is an unnamed module or the module already contains the + * package. + * + * @throws IllegalArgumentException if the package name is not legal + * @throws IllegalStateException if the package is defined to another module + */ + private void implAddPackage(String pn, boolean syncVM) { + // no-op if unnamed module + if (!isNamed()) + return; + + // no-op if module contains the package + if (containsPackage(pn)) + return; + + // check package name is legal for named modules + if (pn.isEmpty()) + throw new IllegalArgumentException("Cannot add <unnamed> package"); + for (int i=0; i<pn.length(); i++) { + char c = pn.charAt(i); + if (c == '/' || c == ';' || c == '[') { + throw new IllegalArgumentException("Illegal character: " + c); + } + } + + // create extraPackages if needed + Map<String, Boolean> extraPackages = this.extraPackages; + if (extraPackages == null) { + synchronized (this) { + extraPackages = this.extraPackages; + if (extraPackages == null) + this.extraPackages = extraPackages = new ConcurrentHashMap<>(); + } + } + + // update VM first in case it fails. This is a no-op if another thread + // beats us to add the package first + if (syncVM) { + // throws IllegalStateException if defined to another module + addPackage0(this, pn); + if (descriptor.isOpen() || descriptor.isAutomatic()) { + addExportsToAll0(this, pn); + } + } + extraPackages.putIfAbsent(pn, Boolean.TRUE); + } + + + // -- creating Module objects -- + + /** + * Defines all module in a configuration to the runtime. + * + * @return a map of module name to runtime {@code Module} + * + * @throws IllegalArgumentException + * If defining any of the modules to the VM fails + */ + static Map<String, Module> defineModules(Configuration cf, + Function<String, ClassLoader> clf, + ModuleLayer layer) + { + Map<String, Module> nameToModule = new HashMap<>(); + Map<String, ClassLoader> moduleToLoader = new HashMap<>(); + + boolean isBootLayer = (ModuleLayer.boot() == null); + Set<ClassLoader> 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(); + URI uri = mref.location().orElse(null); + ClassLoader loader = moduleToLoader.get(resolvedModule.name()); + Module m; + 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); + } + nameToModule.put(name, m); + moduleToLoader.put(name, loader); + } + + // setup readability and exports + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + + String mn = descriptor.name(); + Module m = nameToModule.get(mn); + assert m != null; + + // reads + Set<Module> reads = new HashSet<>(); + + // name -> source Module when in parent layer + Map<String, Module> nameToSource = Collections.emptyMap(); + + for (ResolvedModule other : resolvedModule.reads()) { + Module m2 = null; + if (other.configuration() == cf) { + // this configuration + m2 = nameToModule.get(other.name()); + assert m2 != null; + } else { + // parent layer + for (ModuleLayer parent: layer.parents()) { + m2 = findModule(parent, other); + if (m2 != null) + break; + } + assert m2 != null; + if (nameToSource.isEmpty()) + nameToSource = new HashMap<>(); + nameToSource.put(other.name(), m2); + } + reads.add(m2); + + // update VM view + addReads0(m, m2); + } + m.reads = reads; + + // automatic modules read all unnamed modules + if (descriptor.isAutomatic()) { + m.implAddReads(ALL_UNNAMED_MODULE, true); + } + + // exports and opens + initExportsAndOpens(m, nameToSource, nameToModule, layer.parents()); + } + + // 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(ModuleLayer parent, + ResolvedModule resolvedModule) { + Configuration cf = resolvedModule.configuration(); + String dn = resolvedModule.name(); + return parent.layers() + .filter(l -> l.configuration() == cf) + .findAny() + .map(layer -> { + Optional<Module> 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(Module m, + Map<String, Module> nameToSource, + Map<String, Module> nameToModule, + List<ModuleLayer> parents) { + // The VM doesn't special case open or automatic modules so need to + // export all packages + ModuleDescriptor descriptor = m.getDescriptor(); + if (descriptor.isOpen() || descriptor.isAutomatic()) { + assert descriptor.opens().isEmpty(); + for (String source : descriptor.packages()) { + addExportsToAll0(m, source); + } + return; + } + + Map<String, Set<Module>> openPackages = new HashMap<>(); + Map<String, Set<Module>> exportedPackages = new HashMap<>(); + + // process the open packages first + for (Opens opens : descriptor.opens()) { + String source = opens.source(); + + if (opens.isQualified()) { + // qualified opens + Set<Module> targets = new HashSet<>(); + for (String target : opens.targets()) { + Module m2 = findModule(target, nameToSource, nameToModule, parents); + if (m2 != null) { + addExports0(m, source, m2); + targets.add(m2); + } + } + if (!targets.isEmpty()) { + openPackages.put(source, targets); + } + } else { + // unqualified opens + addExportsToAll0(m, source); + openPackages.put(source, EVERYONE_SET); + } + } + + // next the exports, skipping exports when the package is open + for (Exports exports : descriptor.exports()) { + String source = exports.source(); + + // skip export if package is already open to everyone + Set<Module> openToTargets = openPackages.get(source); + if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE)) + continue; + + if (exports.isQualified()) { + // qualified exports + Set<Module> targets = new HashSet<>(); + for (String target : exports.targets()) { + Module m2 = findModule(target, nameToSource, nameToModule, parents); + if (m2 != null) { + // skip qualified export if already open to m2 + if (openToTargets == null || !openToTargets.contains(m2)) { + addExports0(m, source, m2); + targets.add(m2); + } + } + } + if (!targets.isEmpty()) { + exportedPackages.put(source, targets); + } + + } else { + // unqualified exports + addExportsToAll0(m, source); + exportedPackages.put(source, EVERYONE_SET); + } + } + + if (!openPackages.isEmpty()) + m.openPackages = openPackages; + if (!exportedPackages.isEmpty()) + m.exportedPackages = exportedPackages; + } + + /** + * Find the runtime Module with the given name. The module name is the + * name of a target module in a qualified exports or opens directive. + * + * @param target The target module to find + * @param nameToSource The modules in parent layers that are read + * @param nameToModule The modules in the layer under construction + * @param parents The parent layers + */ + private static Module findModule(String target, + Map<String, Module> nameToSource, + Map<String, Module> nameToModule, + List<ModuleLayer> parents) { + Module m = nameToSource.get(target); + if (m == null) { + m = nameToModule.get(target); + if (m == null) { + for (ModuleLayer parent : parents) { + m = parent.findModule(target).orElse(null); + if (m != null) break; + } + } + } + return m; + } + + + // -- annotations -- + + /** + * {@inheritDoc} + * This method returns {@code null} when invoked on an unnamed module. + */ + @Override + public <T extends Annotation> T getAnnotation(Class<T> 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<Class<?>> 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); + } + } + + + // -- misc -- + + + /** + * 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. As with {@link Class#getResourceAsStream + * Class.getResourceAsStream}, this method delegates to the module's class + * loader {@link ClassLoader#findResource(String,String) + * findResource(String,String)} method, invoking it with the module name + * (or {@code null} when the module is unnamed) and the name of the + * resource. If the resource name has a leading slash then it is dropped + * before delegation. + * + * <p> A resource in a named module may be <em>encapsulated</em> so that + * it cannot be located by code in other modules. Whether a resource can be + * located or not is determined as follows: </p> + * + * <ul> + * <li> If the resource name ends with "{@code .class}" then it is not + * encapsulated. </li> + * + * <li> A <em>package name</em> is derived from the resource name. If + * the package name is a {@link #getPackages() package} in the module + * then the resource can only be located by the caller of this method + * when the package is {@link #isOpen(String,Module) open} to at least + * the caller's module. If the resource is not in a package in the module + * then the resource is not encapsulated. </li> + * </ul> + * + * <p> In the above, the <em>package name</em> for a resource is derived + * from the subsequence of characters that precedes the last {@code '/'} in + * the name and then replacing each {@code '/'} character in the subsequence + * with {@code '.'}. A leading slash is ignored when deriving the package + * name. As an example, the package name derived for a resource named + * "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name + * with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated + * because "{@code META-INF}" is not a legal package name. </p> + * + * <p> 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. </p> + * + * @param name + * The resource name + * + * @return An input stream for reading the resource or {@code null} + * + * @throws IOException + * If an I/O error occurs + * + * @see Class#getResourceAsStream(String) + */ + @CallerSensitive + public InputStream getResourceAsStream(String name) throws IOException { + if (name.startsWith("/")) { + name = name.substring(1); + } + + if (isNamed() && Resources.canEncapsulate(name)) { + Module caller = getCallerModule(Reflection.getCallerClass()); + if (caller != this && caller != Object.class.getModule()) { + String pn = Resources.toPackageName(name); + if (getPackages().contains(pn)) { + if (caller == null && !isOpen(pn)) { + // no caller, package not open + return null; + } + if (!isOpen(pn, caller)) { + // package not open to caller + return null; + } + } + } + } + + 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(); + } catch (SecurityException e) { } + } + + return null; + } + + /** + * Returns the string representation of this module. For a named module, + * the representation is the string {@code "module"}, followed by a space, + * and then the module name. For an unnamed module, the representation is + * the string {@code "unnamed module"}, followed by a space, and then an + * implementation specific string that identifies the unnamed module. + * + * @return The string representation of this module + */ + @Override + public String toString() { + if (isNamed()) { + return "module " + name; + } else { + String id = Integer.toHexString(System.identityHashCode(this)); + return "unnamed module @" + id; + } + } + + /** + * Returns the module that a given caller class is a member of. Returns + * {@code null} if the caller is {@code null}. + */ + private Module getCallerModule(Class<?> caller) { + return (caller != null) ? caller.getModule() : null; + } + + + // -- native methods -- + + // JVM_DefineModule + private static native void defineModule0(Module module, + boolean isOpen, + String version, + String location, + String[] pns); + + // JVM_AddReadsModule + private static native void addReads0(Module from, Module to); + + // JVM_AddModuleExports + private static native void addExports0(Module from, String pn, Module to); + + // JVM_AddModuleExportsToAll + private static native void addExportsToAll0(Module from, String pn); + + // JVM_AddModuleExportsToAllUnnamed + private static native void addExportsToAllUnnamed0(Module from, String pn); + + // JVM_AddModulePackage + private static native void addPackage0(Module m, String pn); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/lang/ModuleLayer.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,944 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +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.module.ServicesCatalog; +import sun.security.util.SecurityConstants; + + +/** + * A layer of modules in the Java virtual machine. + * + * <p> A layer is created from a graph of modules in a {@link Configuration} + * and a function that maps each module to a {@link ClassLoader}. + * Creating a layer informs the Java virtual machine about the classes that + * may be loaded from the modules so that the Java virtual machine knows which + * module that each class is a member of. </p> + * + * <p> Creating a layer creates a {@link Module} object for each {@link + * ResolvedModule} in the configuration. For each resolved module that is + * {@link ResolvedModule#reads() read}, the {@code Module} {@link + * Module#canRead reads} the corresponding run-time {@code Module}, which may + * be in the same layer or a {@link #parents() parent} layer. </p> + * + * <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and + * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods + * provide convenient ways to create a module layer where all modules are + * 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. 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 where a {@link + * ModuleLayer.Controller Controller} is needed to control modules in the layer + * </p> + * + * <p> 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 + * started. The boot layer contains module {@code java.base} and is the only + * layer in the Java virtual machine with a module named "{@code java.base}". + * The modules in the boot layer are mapped to the bootstrap class loader and + * other class loaders that are <a href="../ClassLoader.html#builtinLoaders"> + * built-in</a> into the Java virtual machine. The boot layer will often be + * the {@link #parents() parent} when creating additional layers. </p> + * + * <p> Each {@code Module} in a layer is created so that it {@link + * Module#isExported(String) exports} and {@link Module#isOpen(String) opens} + * the packages described by its {@link ModuleDescriptor}. Qualified exports + * (where a package is exported to a set of target modules rather than all + * modules) are reified when creating the layer as follows: </p> + * <ul> + * <li> If module {@code X} exports a package to {@code Y}, and if the + * runtime {@code Module} {@code X} reads {@code Module} {@code Y}, then + * the package is exported to {@code Module} {@code Y} (which may be in + * the same layer as {@code X} or a parent layer). </li> + * + * <li> If module {@code X} exports a package to {@code Y}, and if the + * runtime {@code Module} {@code X} does not read {@code Y} then target + * {@code Y} is located as if by invoking {@link #findModule(String) + * findModule} to find the module in the layer or its parent layers. If + * {@code Y} is found then the package is exported to the instance of + * {@code Y} that was found. If {@code Y} is not found then the qualified + * export is ignored. </li> + * </ul> + * + * <p> Qualified opens are handled in same way as qualified exports. </p> + * + * <p> As when creating a {@code Configuration}, + * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special + * treatment when creating a layer. An automatic module is created in the + * Java virtual machine as a {@code Module} that reads every unnamed {@code + * Module} in the Java virtual machine. </p> + * + * <p> Unless otherwise specified, passing a {@code null} argument to a method + * in this class causes a {@link NullPointerException NullPointerException} to + * be thrown. </p> + * + * <h3> Example usage: </h3> + * + * <p> This example creates a configuration by resolving a module named + * "{@code myapp}" with the configuration for the boot layer as the parent. It + * then creates a new layer with the modules in this configuration. All modules + * are defined to the same class loader. </p> + * + * <pre>{@code + * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); + * + * ModuleLayer parent = ModuleLayer.boot(); + * + * Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp")); + * + * ClassLoader scl = ClassLoader.getSystemClassLoader(); + * + * ModuleLayer layer = parent.defineModulesWithOneLoader(cf, scl); + * + * Class<?> c = layer.findLoader("myapp").loadClass("app.Main"); + * }</pre> + * + * @since 9 + * @spec JPMS + * @see Module#getLayer() + */ + +public final class ModuleLayer { + + // the empty layer + private static final ModuleLayer EMPTY_LAYER + = new ModuleLayer(Configuration.empty(), List.of(), null); + + // the configuration from which this ;ayer was created + private final Configuration cf; + + // parent layers, empty in the case of the empty layer + private final List<ModuleLayer> parents; + + // maps module name to jlr.Module + private final Map<String, Module> nameToModule; + + /** + * Creates a new module layer from the modules in the given configuration. + */ + private ModuleLayer(Configuration cf, + List<ModuleLayer> parents, + Function<String, ClassLoader> clf) + { + this.cf = cf; + this.parents = parents; // no need to do defensive copy + + Map<String, Module> map; + if (parents.isEmpty()) { + map = Collections.emptyMap(); + } else { + map = Module.defineModules(cf, clf, this); + } + this.nameToModule = map; // no need to do defensive copy + } + + /** + * Controls a module layer. The static methods defined by {@link ModuleLayer} + * to create module layers return a {@code Controller} that can be used to + * control modules in the layer. + * + * <p> Unless otherwise specified, passing a {@code null} argument to a + * method in this class causes a {@link NullPointerException + * NullPointerException} to be thrown. </p> + * + * @apiNote Care should be taken with {@code Controller} objects, they + * should never be shared with untrusted code. + * + * @since 9 + * @spec JPMS + */ + public static final class Controller { + private final ModuleLayer layer; + + Controller(ModuleLayer layer) { + this.layer = layer; + } + + /** + * Returns the layer that this object controls. + * + * @return the module layer + */ + public ModuleLayer layer() { + return layer; + } + + private void ensureInLayer(Module source) { + if (source.getLayer() != layer) + 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 <em>Read edges</em> added by this method are <em>weak</em> + * 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 module layer + * + * @see Module#addReads + */ + public Controller addReads(Module source, Module target) { + ensureInLayer(source); + source.implAddReads(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 module layer or the package + * is not in the source module + * + * @see Module#addOpens + */ + public Controller addOpens(Module source, String pn, Module target) { + ensureInLayer(source); + source.implAddOpens(pn, target); + return this; + } + } + + + /** + * Creates a new module 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. 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: + * <pre> {@code + * ModuleLayer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer(); + * }</pre> + * + * @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 the layer cannot be created for any of the reasons specified + * by the static {@code defineModulesWithOneLoader} method + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public ModuleLayer defineModulesWithOneLoader(Configuration cf, + ClassLoader parentLoader) { + return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer(); + } + + + /** + * Creates a new module 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: + * <pre> {@code + * ModuleLayer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer(); + * }</pre> + * + * @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 for any of the reasons specified + * by the static {@code defineModulesWithManyLoaders} method + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public ModuleLayer defineModulesWithManyLoaders(Configuration cf, + ClassLoader parentLoader) { + return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer(); + } + + + /** + * Creates a new module 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: + * <pre> {@code + * ModuleLayer.defineModules(cf, List.of(thisLayer), clf).layer(); + * }</pre> + * + * @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 the layer cannot be created for any of the reasons specified + * by the static {@code defineModules} method + * @throws SecurityException + * If {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + */ + public ModuleLayer defineModules(Configuration cf, + Function<String, ClassLoader> clf) { + return defineModules(cf, List.of(this), clf).layer(); + } + + /** + * Creates a new module 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. + * + * <p> The class loader created by this method implements <em>direct + * delegation</em> when loading types from modules. When its {@link + * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to + * load a class then it uses the package name of the class to map it to a + * module. This may be a module in this layer and hence defined to the same + * class loader. It may be a package in a module in a parent layer that is + * exported to one or more of the modules in this layer. The class + * loader delegates to the class loader of the module, throwing {@code + * ClassNotFoundException} if not found by that class loader. + * When {@code loadClass} is invoked to load classes that do not map to a + * module then it delegates to the parent class loader. </p> + * + * <p> Attempting to create a layer with all modules defined to the same + * class loader can fail for the following reasons: + * + * <ul> + * + * <li><p> <em>Overlapping packages</em>: Two or more modules in the + * configuration have the same package. </p></li> + * + * <li><p> <em>Split delegation</em>: The resulting class loader would + * need to delegate to more than one class loader in order to load types + * in a specific package. </p></li> + * + * </ul> + * + * <p> In addition, a layer cannot be created if the configuration contains + * a module named "{@code java.base}", or a module contains a package named + * "{@code java}" or a package with a name starting with "{@code java.}". </p> + * + * <p> If there is a security manager then the class loader created by + * this method will load classes and resources with privileges that are + * restricted by the calling context of this method. </p> + * + * @param cf + * The configuration for the layer + * @param parentLayers + * The list of 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 A controller that controls the newly created layer + * + * @throws IllegalArgumentException + * 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 + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public static Controller defineModulesWithOneLoader(Configuration cf, + List<ModuleLayer> parentLayers, + ClassLoader parentLoader) + { + List<ModuleLayer> parents = new ArrayList<>(parentLayers); + checkConfiguration(cf, parents); + + checkCreateClassLoaderPermission(); + checkGetClassLoaderPermission(); + + try { + Loader loader = new Loader(cf.modules(), parentLoader); + loader.initRemotePackageMap(cf, parents); + ModuleLayer layer = new ModuleLayer(cf, parents, mn -> loader); + return new Controller(layer); + } catch (IllegalArgumentException | IllegalStateException e) { + throw new LayerInstantiationException(e.getMessage()); + } + } + + /** + * Creates a new module 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. + * + * <p> The class loaders created by this method implement <em>direct + * delegation</em> when loading types from modules. When {@link + * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to + * load a class then it uses the package name of the class to map it to a + * module. The package may be in the module defined to the class loader. + * The package may be exported by another module in this layer to the + * module defined to the class loader. It may be in a package exported by a + * module in a parent layer. The class loader delegates to the class loader + * of the module, throwing {@code ClassNotFoundException} if not found by + * that class loader. + * When {@code loadClass} is invoked to load classes that do not map to a + * module then it delegates to the parent class loader. </p> + * + * <p> If there is a security manager then the class loaders created by + * this method will load classes and resources with privileges that are + * restricted by the calling context of this method. </p> + * + * @param cf + * The configuration for the layer + * @param parentLayers + * The list of 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 A controller that controls the newly created layer + * + * @throws IllegalArgumentException + * 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}" or a module contains a package + * named "{@code java}" or a package with a name starting with + * "{@code java.}" + * + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public static Controller defineModulesWithManyLoaders(Configuration cf, + List<ModuleLayer> parentLayers, + ClassLoader parentLoader) + { + List<ModuleLayer> parents = new ArrayList<>(parentLayers); + checkConfiguration(cf, parents); + + checkCreateClassLoaderPermission(); + checkGetClassLoaderPermission(); + + LoaderPool pool = new LoaderPool(cf, parents, parentLoader); + try { + ModuleLayer layer = new ModuleLayer(cf, parents, pool::loaderFor); + return new Controller(layer); + } catch (IllegalArgumentException | IllegalStateException e) { + throw new LayerInstantiationException(e.getMessage()); + } + } + + /** + * Creates a new module layer by defining the modules in the given {@code + * Configuration} to the Java virtual machine. The given function maps each + * module in the configuration, by name, to a class loader. Creating the + * layer informs the Java virtual machine about the classes that may be + * loaded so that the Java virtual machine knows which module that each + * class is a member of. + * + * <p> The class loader delegation implemented by the class 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 be + * ready to load from these modules before there are any attempts to load + * classes or resources. </p> + * + * <p> Creating a layer can fail for the following reasons: </p> + * + * <ul> + * + * <li><p> Two or more modules with the same package are mapped to the + * same class loader. </p></li> + * + * <li><p> A module is mapped to a class loader that already has a + * module of the same name defined to it. </p></li> + * + * <li><p> A module is mapped to a class loader that has already + * defined types in any of the packages in the module. </p></li> + * + * </ul> + * + * <p> In addition, a layer cannot be created if the configuration contains + * a module named "{@code java.base}", a configuration contains a module + * with a package named "{@code java}" or a package name starting with + * "{@code java.}" and the module 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}. </p> + * + * <p> If the function to map a module name to class loader throws an error + * or runtime exception then it is propagated to the caller of this method. + * </p> + * + * @apiNote It is implementation specific as to whether creating a layer + * with this method is an atomic operation or not. Consequentially it is + * possible for this method to fail with some modules, but not all, defined + * to the Java virtual machine. + * + * @param cf + * The configuration for the layer + * @param parentLayers + * The list of parent layers in search order + * @param clf + * The function to map a module name to a class loader + * + * @return A controller that controls the newly created layer + * + * @throws IllegalArgumentException + * If the parent configurations do not match the configuration of + * the parent layers, including order + * @throws LayerInstantiationException + * If creating the layer fails for any of the reasons listed above + * @throws SecurityException + * If {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + */ + public static Controller defineModules(Configuration cf, + List<ModuleLayer> parentLayers, + Function<String, ClassLoader> clf) + { + List<ModuleLayer> parents = new ArrayList<>(parentLayers); + checkConfiguration(cf, parents); + Objects.requireNonNull(clf); + + checkGetClassLoaderPermission(); + + // The boot layer is checked during module system initialization + if (boot() != null) { + checkForDuplicatePkgs(cf, clf); + } + + try { + ModuleLayer layer = new ModuleLayer(cf, parents, clf); + return new Controller(layer); + } catch (IllegalArgumentException | IllegalStateException e) { + throw new LayerInstantiationException(e.getMessage()); + } + } + + + /** + * Checks that the parent configurations match the configuration of + * the parent layers. + */ + private static void checkConfiguration(Configuration cf, + List<ModuleLayer> parentLayers) + { + Objects.requireNonNull(cf); + + List<Configuration> parentConfigurations = cf.parents(); + if (parentLayers.size() != parentConfigurations.size()) + throw new IllegalArgumentException("wrong number of parents"); + + int index = 0; + for (ModuleLayer parent : parentLayers) { + if (parent.configuration() != parentConfigurations.get(index)) { + throw new IllegalArgumentException( + "Parent of configuration != configuration of this Layer"); + } + index++; + } + } + + private static void checkCreateClassLoaderPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); + } + + private static void checkGetClassLoaderPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + + /** + * Checks a configuration and the module-to-loader mapping to ensure that + * no two modules mapped to the same class loader have the same package. + * It also checks that no two automatic modules have the same package. + * + * @throws LayerInstantiationException + */ + private static void checkForDuplicatePkgs(Configuration cf, + Function<String, ClassLoader> clf) + { + // HashMap allows null keys + Map<ClassLoader, Set<String>> loaderToPackages = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); + ClassLoader loader = clf.apply(descriptor.name()); + + Set<String> loaderPackages + = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>()); + + for (String pkg : descriptor.packages()) { + boolean added = loaderPackages.add(pkg); + if (!added) { + throw fail("More than one module with package %s mapped" + + " to the same class loader", pkg); + } + } + } + } + + /** + * Creates a LayerInstantiationException with the a message formatted from + * the given format string and arguments. + */ + private static LayerInstantiationException fail(String fmt, Object ... args) { + String msg = String.format(fmt, args); + return new LayerInstantiationException(msg); + } + + + /** + * Returns the configuration for this layer. + * + * @return The configuration for this layer + */ + public Configuration configuration() { + return cf; + } + + + /** + * 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 The list of this layer's parents + */ + public List<ModuleLayer> parents() { + return parents; + } + + + /** + * 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<ModuleLayer> layers() { + List<ModuleLayer> allLayers = this.allLayers; + if (allLayers != null) + return allLayers.stream(); + + allLayers = new ArrayList<>(); + Set<ModuleLayer> visited = new HashSet<>(); + Deque<ModuleLayer> stack = new ArrayDeque<>(); + visited.add(this); + stack.push(this); + + while (!stack.isEmpty()) { + ModuleLayer layer = stack.pop(); + allLayers.add(layer); + + // push in reverse order + for (int i = layer.parents.size() - 1; i >= 0; i--) { + ModuleLayer 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<ModuleLayer> allLayers; + + /** + * Returns the set of the modules in this layer. + * + * @return A possibly-empty unmodifiable set of the modules in this layer + */ + public Set<Module> modules() { + Set<Module> modules = this.modules; + if (modules == null) { + this.modules = modules = + Collections.unmodifiableSet(new HashSet<>(nameToModule.values())); + } + return modules; + } + + private volatile Set<Module> modules; + + + /** + * Returns the module with the given name in this layer, or if not in this + * layer, the {@linkplain #parents parent} 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 <em>tree of layers</em> then this is equivalent to + * a depth-first search. + * + * @param name + * The name of the module to find + * + * @return The module with the given name or an empty {@code Optional} + * if there isn't a module with this name in this layer or any + * parent layer + */ + public Optional<Module> findModule(String name) { + Objects.requireNonNull(name); + if (this == EMPTY_LAYER) + return Optional.empty(); + Module m = nameToModule.get(name); + if (m != null) + return Optional.of(m); + + 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 #parents + * parent} layers are searched in the manner specified by {@link + * #findModule(String) findModule}. + * + * <p> If there is a security manager then its {@code checkPermission} + * method is called with a {@code RuntimePermission("getClassLoader")} + * permission to check that the caller is allowed to get access to the + * class loader. </p> + * + * @apiNote This method does not return an {@code Optional<ClassLoader>} + * because `null` must be used to represent the bootstrap class loader. + * + * @param name + * The name of the module to find + * + * @return The ClassLoader that the module is defined to + * + * @throws IllegalArgumentException if a module of the given name is not + * defined in this layer or any parent of this layer + * + * @throws SecurityException if denied by the security manager + */ + public ClassLoader findLoader(String name) { + Optional<Module> 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 module layer. + * + * @return A possibly empty string describing this module layer + */ + @Override + public String toString() { + return modules().stream() + .map(Module::getName) + .collect(Collectors.joining(", ")); + } + + /** + * Returns the <em>empty</em> layer. There are no modules in the empty + * layer. It has no parents. + * + * @return The empty layer + */ + public static ModuleLayer empty() { + return EMPTY_LAYER; + } + + + /** + * Returns the boot layer. The boot layer contains at least one module, + * {@code java.base}. Its parent is the {@link #empty() empty} layer. + * + * @apiNote This method returns {@code null} during startup and before + * the boot layer is fully initialized. + * + * @return The boot layer + */ + public static ModuleLayer boot() { + return System.bootLayer; + } + + /** + * Returns the ServicesCatalog for this Layer, creating it if not + * already created. + */ + ServicesCatalog getServicesCatalog() { + ServicesCatalog servicesCatalog = this.servicesCatalog; + if (servicesCatalog != null) + return servicesCatalog; + + synchronized (this) { + servicesCatalog = this.servicesCatalog; + if (servicesCatalog == null) { + servicesCatalog = ServicesCatalog.create(); + nameToModule.values().forEach(servicesCatalog::register); + this.servicesCatalog = servicesCatalog; + } + } + + return servicesCatalog; + } + + 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<ModuleLayer> list = CLV.get(loader); + if (list == null) { + list = new CopyOnWriteArrayList<>(); + List<ModuleLayer> 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<ModuleLayer> layers(ClassLoader loader) { + List<ModuleLayer> 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<List<ModuleLayer>> CLV = new ClassLoaderValue<>(); +}
--- a/src/java.base/share/classes/java/lang/NamedPackage.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/NamedPackage.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ import java.lang.module.Configuration; import java.lang.module.ModuleReference; -import java.lang.reflect.Module; import java.net.URI; /**
--- a/src/java.base/share/classes/java/lang/Package.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/Package.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,7 +27,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Module; import java.net.MalformedURLException; import java.net.URI; import java.net.URL;
--- a/src/java.base/share/classes/java/lang/SecurityManager.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/SecurityManager.java Fri Apr 07 08:05:54 2017 +0000 @@ -29,9 +29,7 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Opens; -import java.lang.reflect.Layer; import java.lang.reflect.Member; -import java.lang.reflect.Module; import java.io.FileDescriptor; import java.io.File; import java.io.FilePermission; @@ -1441,7 +1439,7 @@ static { // Get the modules in the boot layer - Stream<Module> bootLayerModules = Layer.boot().modules().stream(); + Stream<Module> bootLayerModules = ModuleLayer.boot().modules().stream(); // Filter out the modules loaded by the boot or platform loader PrivilegedAction<Set<Module>> pa = () ->
--- a/src/java.base/share/classes/java/lang/StackTraceElement.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/StackTraceElement.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,8 +33,6 @@ import java.lang.module.ModuleDescriptor.Version; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.util.HashSet; import java.util.Objects; import java.util.Optional; @@ -191,7 +189,7 @@ * if the module name is not available. * @since 9 * @spec JPMS - * @see java.lang.reflect.Module#getName() + * @see Module#getName() */ public String getModuleName() { return moduleName; @@ -480,7 +478,7 @@ if (!VM.isModuleSystemInited()) return true; - return Layer.boot() == m.getLayer() && HashedModules.contains(m); + return ModuleLayer.boot() == m.getLayer() && HashedModules.contains(m); } /* @@ -492,7 +490,7 @@ static Set<String> hashedModules() { - Optional<ResolvedModule> resolvedModule = Layer.boot() + Optional<ResolvedModule> resolvedModule = ModuleLayer.boot() .configuration() .findModule("java.base"); assert resolvedModule.isPresent();
--- a/src/java.base/share/classes/java/lang/System.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/System.java Fri Apr 07 08:05:54 2017 +0000 @@ -35,33 +35,32 @@ import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; +import java.lang.module.ModuleDescriptor; 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.URI; import java.net.URL; import java.security.AccessControlContext; import java.security.ProtectionDomain; -import java.util.Properties; -import java.util.PropertyPermission; -import java.util.Map; import java.security.AccessController; import java.security.PrivilegedAction; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.PropertyPermission; +import java.util.ResourceBundle; +import java.util.function.Supplier; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; -import java.util.Objects; -import java.util.ResourceBundle; -import java.util.function.Supplier; -import sun.nio.ch.Interruptible; +import jdk.internal.module.ModuleBootstrap; +import jdk.internal.module.ServicesCatalog; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; -import sun.security.util.SecurityConstants; -import sun.reflect.annotation.AnnotationType; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.JavaLangAccess;; import jdk.internal.misc.SharedSecrets;; @@ -69,8 +68,9 @@ import jdk.internal.logger.LoggerFinderLoader; import jdk.internal.logger.LazyLoggers; import jdk.internal.logger.LocalizedLoggerWrapper; - -import jdk.internal.module.ModuleBootstrap; +import sun.reflect.annotation.AnnotationType; +import sun.nio.ch.Interruptible; +import sun.security.util.SecurityConstants; /** * The <code>System</code> class contains several useful class fields @@ -1160,7 +1160,7 @@ * @param msg the string message (or a key in the message catalog, if * this logger is a {@link * LoggerFinder#getLocalizedLogger(java.lang.String, - * java.util.ResourceBundle, java.lang.reflect.Module) localized logger}); + * java.util.ResourceBundle, java.lang.Module) localized logger}); * can be {@code null}. * * @throws NullPointerException if {@code level} is {@code null}. @@ -1228,7 +1228,7 @@ * @param msg the string message (or a key in the message catalog, if * this logger is a {@link * LoggerFinder#getLocalizedLogger(java.lang.String, - * java.util.ResourceBundle, java.lang.reflect.Module) localized logger}); + * java.util.ResourceBundle, java.lang.Module) localized logger}); * can be {@code null}. * @param thrown a {@code Throwable} associated with the log message; * can be {@code null}. @@ -1277,7 +1277,7 @@ * java.text.MessageFormat} format, (or a key in the message * catalog, if this logger is a {@link * LoggerFinder#getLocalizedLogger(java.lang.String, - * java.util.ResourceBundle, java.lang.reflect.Module) localized logger}); + * java.util.ResourceBundle, java.lang.Module) localized logger}); * can be {@code null}. * @param params an optional list of parameters to the message (may be * none). @@ -1482,7 +1482,7 @@ * message localization. * * @implSpec By default, this method calls {@link - * #getLogger(java.lang.String, java.lang.reflect.Module) + * #getLogger(java.lang.String, java.lang.Module) * this.getLogger(name, module)} to obtain a logger, then wraps that * logger in a {@link Logger} instance where all methods that do not * take a {@link ResourceBundle} as parameter are redirected to one @@ -1566,7 +1566,7 @@ * @implSpec * Instances returned by this method route messages to loggers * obtained by calling {@link LoggerFinder#getLogger(java.lang.String, - * java.lang.reflect.Module) LoggerFinder.getLogger(name, module)}, where + * java.lang.Module) LoggerFinder.getLogger(name, module)}, where * {@code module} is the caller's module. * In cases where {@code System.getLogger} is called from a context where * there is no caller frame on the stack (e.g when called directly @@ -1579,7 +1579,7 @@ * * @apiNote * This method may defer calling the {@link - * LoggerFinder#getLogger(java.lang.String, java.lang.reflect.Module) + * LoggerFinder#getLogger(java.lang.String, java.lang.Module) * LoggerFinder.getLogger} method to create an actual logger supplied by * the logging backend, for instance, to allow loggers to be obtained during * the system initialization time. @@ -1612,7 +1612,7 @@ * @implSpec * The returned logger will perform message localization as specified * by {@link LoggerFinder#getLocalizedLogger(java.lang.String, - * java.util.ResourceBundle, java.lang.reflect.Module) + * java.util.ResourceBundle, java.lang.Module) * LoggerFinder.getLocalizedLogger(name, bundle, module)}, where * {@code module} is the caller's module. * In cases where {@code System.getLogger} is called from a context where @@ -1977,7 +1977,7 @@ } // @see #initPhase2() - private static Layer bootLayer; + static ModuleLayer bootLayer; /* * Invoked by VM. Phase 2 module system initialization. @@ -2100,9 +2100,6 @@ public void invokeFinalize(Object o) throws Throwable { o.finalize(); } - public Layer getBootLayer() { - return bootLayer; - } public ConcurrentHashMap<?, ?> createOrGetClassLoaderValueMap(ClassLoader cl) { return cl.createOrGetClassLoaderValueMap(); } @@ -2127,6 +2124,44 @@ public void invalidatePackageAccessCache() { SecurityManager.invalidatePackageAccessCache(); } + public Module defineModule(ClassLoader loader, + ModuleDescriptor descriptor, + URI uri) { + return new Module(null, loader, descriptor, uri); + } + public Module defineUnnamedModule(ClassLoader loader) { + return new Module(loader); + } + public void addReads(Module m1, Module m2) { + m1.implAddReads(m2); + } + public void addReadsAllUnnamed(Module m) { + m.implAddReadsAllUnnamed(); + } + public void addExports(Module m, String pn, Module other) { + m.implAddExports(pn, other); + } + public void addExportsToAllUnnamed(Module m, String pn) { + m.implAddExportsToAllUnnamed(pn); + } + public void addOpens(Module m, String pn, Module other) { + m.implAddOpens(pn, other); + } + public void addOpensToAllUnnamed(Module m, String pn) { + m.implAddOpensToAllUnnamed(pn); + } + public void addUses(Module m, Class<?> service) { + m.implAddUses(service); + } + public ServicesCatalog getServicesCatalog(ModuleLayer layer) { + return layer.getServicesCatalog(); + } + public Stream<ModuleLayer> layers(ModuleLayer layer) { + return layer.layers(); + } + public Stream<ModuleLayer> layers(ClassLoader loader) { + return ModuleLayer.layers(loader); + } }); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/lang/WeakPairMap.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,354 @@ +/* + * 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 java.lang; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; + +/** + * A WeakHashMap-like data structure that uses a pair of weakly-referenced keys + * with identity equality semantics to associate a strongly-referenced value. + * Unlike WeakHashMap, this data structure is thread-safe. + * + * @param <K1> the type of 1st key in key pair + * @param <K2> the type of 2nd key in key pair + * @param <V> the type of value + * @author Peter Levart + */ +final class WeakPairMap<K1, K2, V> { + + private final ConcurrentHashMap<Pair<K1, K2>, V> map = new ConcurrentHashMap<>(); + private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); + + /** + * Tests if the specified pair of keys are associated with a value + * in the WeakPairMap. + * + * @param k1 the 1st of the pair of keys + * @param k2 the 2nd of the pair of keys + * @return true if and only if the specified key pair is in this WeakPairMap, + * as determined by the identity comparison; false otherwise + * @throws NullPointerException if any of the specified keys is null + */ + public boolean containsKeyPair(K1 k1, K2 k2) { + expungeStaleAssociations(); + return map.containsKey(Pair.lookup(k1, k2)); + } + + /** + * Returns the value to which the specified pair of keys is mapped, or null + * if this WeakPairMap contains no mapping for the key pair. + * <p>More formally, if this WeakPairMap contains a mapping from a key pair + * {@code (_k1, _k2)} to a value {@code v} such that + * {@code k1 == _k1 && k2 == _k2}, then this method returns {@code v}; + * otherwise it returns {@code null}. + * (There can be at most one such mapping.) + * + * @param k1 the 1st of the pair of keys for which the mapped value is to + * be returned + * @param k2 the 2nd of the pair of keys for which the mapped value is to + * be returned + * @return the value to which the specified key pair is mapped, or null if + * this map contains no mapping for the key pair + * @throws NullPointerException if any of the specified keys is null + */ + public V get(K1 k1, K2 k2) { + expungeStaleAssociations(); + return map.get(Pair.lookup(k1, k2)); + } + + /** + * Maps the specified key pair to the specified value in this WeakPairMap. + * Neither the keys nor the value can be null. + * <p>The value can be retrieved by calling the {@link #get} method + * with the the same keys (compared by identity). + * + * @param k1 the 1st of the pair of keys with which the specified value is to + * be associated + * @param k2 the 2nd of the pair of keys with which the specified value is to + * be associated + * @param v value to be associated with the specified key pair + * @return the previous value associated with key pair, or {@code null} if + * there was no mapping for key pair + * @throws NullPointerException if any of the specified keys or value is null + */ + public V put(K1 k1, K2 k2, V v) { + expungeStaleAssociations(); + return map.put(Pair.weak(k1, k2, queue), v); + } + + /** + * If the specified key pair is not already associated with a value, + * associates it with the given value and returns {@code null}, else does + * nothing and returns the currently associated value. + * + * @param k1 the 1st of the pair of keys with which the specified value is to + * be associated + * @param k2 the 2nd of the pair of keys with which the specified value is to + * be associated + * @param v value to be associated with the specified key pair + * @return the previous value associated with key pair, or {@code null} if + * there was no mapping for key pair + * @throws NullPointerException if any of the specified keys or value is null + */ + public V putIfAbsent(K1 k1, K2 k2, V v) { + expungeStaleAssociations(); + return map.putIfAbsent(Pair.weak(k1, k2, queue), v); + } + + /** + * If the specified key pair is not already associated with a value, + * attempts to compute its value using the given mapping function + * and enters it into this WeakPairMap unless {@code null}. The entire + * method invocation is performed atomically, so the function is + * applied at most once per key pair. Some attempted update operations + * on this WeakPairMap by other threads may be blocked while computation + * is in progress, so the computation should be short and simple, + * and must not attempt to update any other mappings of this WeakPairMap. + * + * @param k1 the 1st of the pair of keys with which the + * computed value is to be associated + * @param k2 the 2nd of the pair of keys with which the + * computed value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with + * the specified key pair, or null if the computed value is null + * @throws NullPointerException if any of the specified keys or + * mappingFunction is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map + * that would otherwise never complete + * @throws RuntimeException or Error if the mappingFunction does so, in + * which case the mapping is left unestablished + */ + public V computeIfAbsent(K1 k1, K2 k2, + BiFunction<? super K1, ? super K2, ? extends V> + mappingFunction) { + expungeStaleAssociations(); + try { + return map.computeIfAbsent( + Pair.weak(k1, k2, queue), + pair -> mappingFunction.apply(pair.first(), pair.second())); + } finally { + Reference.reachabilityFence(k1); + Reference.reachabilityFence(k2); + } + } + + /** + * Returns a {@link Collection} view of the values contained in this + * WeakPairMap. The collection is backed by the WeakPairMap, so changes to + * the map are reflected in the collection, and vice-versa. The collection + * supports element removal, which removes the corresponding + * mapping from this map, via the {@code Iterator.remove}, + * {@code Collection.remove}, {@code removeAll}, + * {@code retainAll}, and {@code clear} operations. It does not + * support the {@code add} or {@code addAll} operations. + * + * @return the collection view + */ + public Collection<V> values() { + expungeStaleAssociations(); + return map.values(); + } + + /** + * Removes associations from this WeakPairMap for which at least one of the + * keys in key pair has been found weakly-reachable and corresponding + * WeakRefPeer(s) enqueued. Called as part of each public operation. + */ + private void expungeStaleAssociations() { + WeakRefPeer<?> peer; + while ((peer = (WeakRefPeer<?>) queue.poll()) != null) { + map.remove(peer.weakPair()); + } + } + + /** + * Common interface of both {@link Weak} and {@link Lookup} key pairs. + */ + private interface Pair<K1, K2> { + + static <K1, K2> Pair<K1, K2> weak(K1 k1, K2 k2, + ReferenceQueue<Object> queue) { + return new Weak<>(k1, k2, queue); + } + + static <K1, K2> Pair<K1, K2> lookup(K1 k1, K2 k2) { + return new Lookup<>(k1, k2); + } + + /** + * @return The 1st of the pair of keys (may be null for {@link Weak} + * when it gets cleared) + */ + K1 first(); + + /** + * @return The 2nd of the pair of keys (may be null for {@link Weak} + * when it gets cleared) + */ + K2 second(); + + static int hashCode(Object first, Object second) { + // assert first != null && second != null; + return System.identityHashCode(first) ^ + System.identityHashCode(second); + } + + static boolean equals(Object first, Object second, Pair<?, ?> p) { + return first != null && second != null && + first == p.first() && second == p.second(); + } + + /** + * A Pair where both keys are weakly-referenced. + * It is composed of two instances of {@link WeakRefPeer}s: + * <pre>{@code + * + * +-referent-> [K1] +-referent-> [K2] + * | | + * +----------------+ +----------------+ + * | Pair.Weak <: |-----peer----->| (anonymous) <: | + * | WeakRefPeer, | | WeakRefPeer | + * | Pair |<--weakPair()--| | + * +----------------+ +----------------+ + * | ^ + * | | + * +-weakPair()-+ + * + * }</pre> + * <p> + * Pair.Weak is used for CHM keys. Both peers are associated with the + * same {@link ReferenceQueue} so when either of their referents + * becomes weakly-reachable, the corresponding entries can be + * {@link #expungeStaleAssociations() expunged} from the map. + */ + final class Weak<K1, K2> extends WeakRefPeer<K1> implements Pair<K1, K2> { + + // saved hash so it can be retrieved after the reference is cleared + private final int hash; + // link to <K2> peer + private final WeakRefPeer<K2> peer; + + Weak(K1 k1, K2 k2, ReferenceQueue<Object> queue) { + super(k1, queue); + hash = Pair.hashCode(k1, k2); + peer = new WeakRefPeer<>(k2, queue) { + // link back to <K1> peer + @Override + Weak<?, ?> weakPair() { return Weak.this; } + }; + } + + @Override + Weak<?, ?> weakPair() { + return this; + } + + @Override + public K1 first() { + return get(); + } + + @Override + public K2 second() { + return peer.get(); + } + + @Override + public int hashCode() { + return hash; + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof Pair && + Pair.equals(first(), second(), (Pair<?, ?>) obj)); + } + } + + /** + * Optimized lookup Pair, used as lookup key in methods like + * {@link java.util.Map#get(Object)} or + * {@link java.util.Map#containsKey(Object)}) where + * there is a great chance its allocation is eliminated + * by escape analysis when such lookups are inlined by JIT. + * All its methods are purposely designed so that 'this' is never + * passed to any other method or used as identity. + */ + final class Lookup<K1, K2> implements Pair<K1, K2> { + private final K1 k1; + private final K2 k2; + + Lookup(K1 k1, K2 k2) { + this.k1 = Objects.requireNonNull(k1); + this.k2 = Objects.requireNonNull(k2); + } + + @Override + public K1 first() { + return k1; + } + + @Override + public K2 second() { + return k2; + } + + @Override + public int hashCode() { + return Pair.hashCode(k1, k2); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Pair && + Pair.equals(k1, k2, (Pair<?, ?>) obj); + } + } + } + + /** + * Common abstract supertype of a pair of WeakReference peers. + */ + private static abstract class WeakRefPeer<K> extends WeakReference<K> { + + WeakRefPeer(K k, ReferenceQueue<Object> queue) { + super(Objects.requireNonNull(k), queue); + } + + /** + * @return the {@link Pair.Weak} side of the pair of peers. + */ + abstract Pair.Weak<?, ?> weakPair(); + } +}
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,7 +33,6 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.Module; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator;
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Fri Apr 07 08:05:54 2017 +0000 @@ -43,7 +43,6 @@ 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.security.AccessController; @@ -668,11 +667,11 @@ * The value is {@code 0x20}, which does not correspond meaningfully to * any particular {@linkplain java.lang.reflect.Modifier modifier bit}. * A {@code Lookup} with this lookup mode assumes {@linkplain - * java.lang.reflect.Module#canRead(java.lang.reflect.Module) readability}. + * java.lang.Module#canRead(java.lang.Module) readability}. * In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup} * with this lookup mode can access all public members of public types * of all modules where the type is in a package that is {@link - * java.lang.reflect.Module#isExported(String) exported unconditionally}. + * java.lang.Module#isExported(String) exported unconditionally}. * @since 9 * @spec JPMS * @see #publicLookup()
--- a/src/java.base/share/classes/java/lang/module/Configuration.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/module/Configuration.java Fri Apr 07 08:05:54 2017 +0000 @@ -64,11 +64,11 @@ * with the receiver as the parent configuration. The static methods are for * more advanced cases where there can be more than one parent configuration. </p> * - * <p> Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual + * <p> Each {@link java.lang.ModuleLayer layer} of modules in the Java virtual * machine is created from a configuration. The configuration for the {@link - * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code - * Layer.boot().configuration()}. The configuration for the boot layer will - * often be the parent when creating new configurations. </p> + * java.lang.ModuleLayer#boot() boot} layer is obtained by invoking {@code + * ModuleLayer.boot().configuration()}. The configuration for the boot layer + * will often be the parent when creating new configurations. </p> * * <h3> Example </h3> * @@ -81,7 +81,7 @@ * <pre>{@code * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); * - * Configuration parent = Layer.boot().configuration(); + * Configuration parent = ModuleLayer.boot().configuration(); * * Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp")); * cf.modules().forEach(m -> { @@ -95,7 +95,7 @@ * * @since 9 * @spec JPMS - * @see java.lang.reflect.Layer + * @see java.lang.ModuleLayer */ public final class Configuration {
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java Fri Apr 07 08:05:54 2017 +0000 @@ -60,7 +60,7 @@ * <p> A module descriptor describes a named module and defines methods to * obtain each of its components. The module descriptor for a named module * in the Java virtual machine is obtained by invoking the {@link - * java.lang.reflect.Module Module}'s {@link java.lang.reflect.Module#getDescriptor + * java.lang.Module Module}'s {@link java.lang.Module#getDescriptor * getDescriptor} method. Module descriptors can also be created using the * {@link ModuleDescriptor.Builder} class or by reading the binary form of a * module declaration ({@code module-info.class}) using the {@link @@ -85,7 +85,7 @@ * <p> {@code ModuleDescriptor} objects are immutable and safe for use by * multiple concurrent threads.</p> * - * @see java.lang.reflect.Module + * @see java.lang.Module * @since 9 * @spec JPMS */ @@ -2110,7 +2110,9 @@ /** * Sets the module main class. The package for the main class is added - * to the module if not already added. + * to the module if not already added. In other words, this method is + * equivalent to first invoking this builder's {@link #packages(Set) + * packages} method to add the package name of the main class. * * @param mc * The module main class @@ -2134,8 +2136,8 @@ throw new IllegalArgumentException(mc + ": unnamed package"); } } + packages.add(pn); mainClass = mc; - packages.add(pn); return this; }
--- a/src/java.base/share/classes/java/lang/module/ModuleFinder.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/module/ModuleFinder.java Fri Apr 07 08:05:54 2017 +0000 @@ -228,14 +228,14 @@ * directory is treated as an exploded module rather than a directory of * modules. </p> * - * <p> The module finder returned by this method supports modules that are - * packaged as JAR files. A JAR file with a {@code module-info.class} in - * the top-level directory of the JAR file (or overridden by a versioned - * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release} - * JAR file) is a modular JAR and is an <em>explicit module</em>. - * A JAR file that does not have a {@code module-info.class} in the - * top-level directory is created as an automatic module. The components - * for the automatic module are derived as follows: + * <p id="automatic-modules"> The module finder returned by this method + * supports modules packaged as JAR files. A JAR file with a {@code + * module-info.class} in its top-level directory, or in a versioned entry + * in a {@linkplain java.util.jar.JarFile#isMultiRelease() multi-release} + * JAR file, is a modular JAR file and thus defines an <em>explicit</em> + * module. A JAR file that does not have a {@code module-info.class} in its + * top-level directory defines an <em>automatic module</em>, as follows: + * </p> * * <ul> * @@ -254,16 +254,16 @@ * ModuleDescriptor.Version} and ignored if it cannot be parsed as * a {@code Version}. </p></li> * - * <li><p> 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. </p></li> + * <li><p> All non-alphanumeric characters ({@code [^A-Za-z0-9]}) + * in the module name are replaced with a dot ({@code "."}), all + * repeating dots are replaced with one dot, and all leading and + * trailing dots are removed. </p></li> * * <li><p> 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 - * named {@code foo-1.2.3-SNAPSHOT.jar} will derive a module name - * {@code foo} and {@code 1.2.3-SNAPSHOT} as the version. </p></li> + * named {@code foo-bar-1.2.3-SNAPSHOT.jar} will derive a module + * name {@code foo.bar} and {@code 1.2.3-SNAPSHOT} as the version. + * </p></li> * * </ul></li> * @@ -312,7 +312,9 @@ * * <p> As with automatic modules, the contents of a packaged or exploded * module may need to be <em>scanned</em> in order to determine the packages - * in the module. If a {@code .class} file (other than {@code + * in the module. Whether {@linkplain java.nio.file.Files#isHidden(Path) + * hidden files} are ignored or not is implementation specific and therefore + * not specified. If a {@code .class} file (other than {@code * module-info.class}) is found in the top-level directory then it is * assumed to be a class in the unnamed package and so {@code FindException} * is thrown. </p>
--- a/src/java.base/share/classes/java/lang/module/Resolver.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/module/Resolver.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ 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; @@ -67,6 +66,9 @@ // maps module name to module reference private final Map<String, ModuleReference> nameToReference = new HashMap<>(); + // true if all automatic modules have been found + private boolean haveAllAutomaticModules; + // module constraints on target platform private String osName; private String osArch; @@ -171,6 +173,21 @@ ModuleDescriptor descriptor = q.poll(); assert nameToReference.containsKey(descriptor.name()); + // if the module is an automatic module then all automatic + // modules need to be resolved + if (descriptor.isAutomatic() && !haveAllAutomaticModules) { + addFoundAutomaticModules().forEach(mref -> { + ModuleDescriptor other = mref.descriptor(); + q.offer(other); + if (isTracing()) { + trace("Automatic module %s located, required by %s", + other.name(), descriptor.name()); + mref.location().ifPresent(uri -> trace(" (%s)", uri)); + } + }); + haveAllAutomaticModules = true; + } + // process dependences for (ModuleDescriptor.Requires requires : descriptor.requires()) { @@ -199,10 +216,15 @@ if (!nameToReference.containsKey(dn)) { addFoundModule(mref); q.offer(mref.descriptor()); - resolved.add(mref.descriptor()); if (isTracing()) { - trace("Module %s located, required by %s", + String prefix; + if (mref.descriptor().isAutomatic()) { + prefix = "Automatic module"; + } else { + prefix = "Module"; + } + trace(prefix + " %s located, required by %s", dn, descriptor.name()); mref.location().ifPresent(uri -> trace(" (%s)", uri)); } @@ -250,7 +272,7 @@ // the initial set of modules that may use services Set<ModuleDescriptor> initialConsumers; - if (Layer.boot() == null) { + if (ModuleLayer.boot() == null) { initialConsumers = new HashSet<>(); } else { initialConsumers = parents.stream() @@ -301,6 +323,21 @@ return this; } + /** + * Add all automatic modules that have not already been found to the + * nameToReference map. + */ + private Set<ModuleReference> addFoundAutomaticModules() { + Set<ModuleReference> result = new HashSet<>(); + findAll().forEach(mref -> { + String mn = mref.descriptor().name(); + if (mref.descriptor().isAutomatic() && !nameToReference.containsKey(mn)) { + addFoundModule(mref); + result.add(mref); + } + }); + return result; + } /** * Add the module to the nameToReference map. Also check any constraints on @@ -534,7 +571,7 @@ // need "requires transitive" from the modules in parent configurations // as there may be selected modules that have a dependency on modules in // the parent configuration. - if (Layer.boot() == null) { + if (ModuleLayer.boot() == null) { g2 = new HashMap<>(capacity); } else { g2 = parents.stream()
--- a/src/java.base/share/classes/java/lang/module/package-info.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/module/package-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -70,7 +70,7 @@ * } </pre> * * <p> If module {@code m1} is resolved with the configuration for the {@link - * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting + * java.lang.ModuleLayer#boot() boot} layer as the parent then the resulting * configuration contains two modules ({@code m1}, {@code m2}). The edges in * its readability graph are: * <pre> {@code @@ -92,10 +92,10 @@ * * <p> {@link java.lang.module.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 transitive}" all other automatic modules in the configuration - * (and all automatic modules in parent configurations). </p> + * as if it "{@code requires transitive}" all observable automatic modules and + * all automatic modules in the parent configurations. Each automatic module is + * resolved so that it reads all other modules in the resulting configuration and + * all modules in parent configurations. </p> * * <h2><a name="servicebinding">Service binding</a></h2> *
--- a/src/java.base/share/classes/java/lang/reflect/Layer.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,949 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.reflect; - -import java.lang.module.Configuration; -import java.lang.module.ModuleDescriptor; -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 sun.security.util.SecurityConstants; - - -/** - * A layer of modules in the Java virtual machine. - * - * <p> A layer is created from a graph of modules in a {@link Configuration} - * and a function that maps each module to a {@link ClassLoader}. - * Creating a layer informs the Java virtual machine about the classes that - * may be loaded from the modules so that the Java virtual machine knows which - * module that each class is a member of. </p> - * - * <p> Creating a layer creates a {@link Module} object for each {@link - * ResolvedModule} in the configuration. For each resolved module that is - * {@link ResolvedModule#reads() read}, the {@code Module} {@link - * Module#canRead reads} the corresponding run-time {@code Module}, which may - * be in the same layer or a {@link #parents() parent} layer. </p> - * - * <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and - * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods - * provide convenient ways to create a {@code Layer} where all modules are - * 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. 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 where a {@link Layer.Controller - * Controller} is needed to control modules in the layer. </p> - * - * <p> 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 - * started. The boot layer contains module {@code java.base} and is the only - * layer in the Java virtual machine with a module named "{@code java.base}". - * The modules in the boot layer are mapped to the bootstrap class loader and - * other class loaders that are <a href="../ClassLoader.html#builtinLoaders"> - * built-in</a> into the Java virtual machine. The boot layer will often be - * the {@link #parents() parent} when creating additional layers. </p> - * - * <p> Each {@code Module} in a layer is created so that it {@link - * Module#isExported(String) exports} and {@link Module#isOpen(String) opens} - * the packages described by its {@link ModuleDescriptor}. Qualified exports - * (where a package is exported to a set of target modules rather than all - * modules) are reified when creating the layer as follows: </p> - * <ul> - * <li> If module {@code X} exports a package to {@code Y}, and if the - * runtime {@code Module} {@code X} reads {@code Module} {@code Y}, then - * the package is exported to {@code Module} {@code Y} (which may be in - * the same layer as {@code X} or a parent layer). </li> - * - * <li> If module {@code X} exports a package to {@code Y}, and if the - * runtime {@code Module} {@code X} does not read {@code Y} then target - * {@code Y} is located as if by invoking {@link #findModule(String) - * findModule} to find the module in the layer or its parent layers. If - * {@code Y} is found then the package is exported to the instance of - * {@code Y} that was found. If {@code Y} is not found then the qualified - * export is ignored. </li> - * </ul> - * - * <p> Qualified opens are handled in same way as qualified exports. </p> - * - * <p> As when creating a {@code Configuration}, - * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special - * treatment when creating a layer. An automatic module is created in the - * Java virtual machine as a {@code Module} that reads every unnamed {@code - * Module} in the Java virtual machine. </p> - * - * <p> Unless otherwise specified, passing a {@code null} argument to a method - * in this class causes a {@link NullPointerException NullPointerException} to - * be thrown. </p> - * - * <h3> Example usage: </h3> - * - * <p> This example creates a configuration by resolving a module named - * "{@code myapp}" with the configuration for the boot layer as the parent. It - * then creates a new layer with the modules in this configuration. All modules - * are defined to the same class loader. </p> - * - * <pre>{@code - * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); - * - * Layer parent = Layer.boot(); - * - * Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp")); - * - * ClassLoader scl = ClassLoader.getSystemClassLoader(); - * - * Layer layer = parent.defineModulesWithOneLoader(cf, scl); - * - * Class<?> c = layer.findLoader("myapp").loadClass("app.Main"); - * }</pre> - * - * @since 9 - * @spec JPMS - * @see Module#getLayer() - */ - -public final class Layer { - - // the empty Layer - private static final Layer EMPTY_LAYER - = new Layer(Configuration.empty(), List.of(), null); - - // the configuration from which this Layer was created - private final Configuration cf; - - // parent layers, empty in the case of the empty layer - private final List<Layer> parents; - - // maps module name to jlr.Module - private final Map<String, Module> nameToModule; - - /** - * Creates a new Layer from the modules in the given configuration. - */ - private Layer(Configuration cf, - List<Layer> parents, - Function<String, ClassLoader> clf) - { - this.cf = cf; - this.parents = parents; // no need to do defensive copy - - Map<String, Module> map; - if (parents.isEmpty()) { - map = Collections.emptyMap(); - } else { - map = Module.defineModules(cf, clf, this); - } - 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. - * - * <p> Unless otherwise specified, passing a {@code null} argument to a - * method in this class causes a {@link NullPointerException - * NullPointerException} to be thrown. </p> - * - * @apiNote Care should be taken with {@code Controller} objects, they - * should never be shared with untrusted code. - * - * @since 9 - * @spec JPMS - */ - 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 (source.getLayer() != layer) - 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 <em>Read edges</em> added by this method are <em>weak</em> - * 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) { - ensureInLayer(source); - Objects.requireNonNull(target); - 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) { - ensureInLayer(source); - Objects.requireNonNull(pn); - Objects.requireNonNull(target); - 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. 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: - * <pre> {@code - * Layer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer(); - * }</pre> - * - * @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 the layer cannot be created for any of the reasons specified - * by the static {@code defineModulesWithOneLoader} method - * @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: - * <pre> {@code - * Layer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer(); - * }</pre> - * - * @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 for any of the reasons specified - * by the static {@code defineModulesWithManyLoaders} method - * @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: - * <pre> {@code - * Layer.defineModules(cf, List.of(thisLayer), clf).layer(); - * }</pre> - * - * @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 the layer cannot be created for any of the reasons specified - * by the static {@code defineModules} method - * @throws SecurityException - * If {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - */ - public Layer defineModules(Configuration cf, - Function<String, ClassLoader> 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. - * - * <p> The class loader created by this method implements <em>direct - * delegation</em> when loading types from modules. When its {@link - * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to - * load a class then it uses the package name of the class to map it to a - * module. This may be a module in this layer and hence defined to the same - * class loader. It may be a package in a module in a parent layer that is - * exported to one or more of the modules in this layer. The class - * loader delegates to the class loader of the module, throwing {@code - * ClassNotFoundException} if not found by that class loader. - * When {@code loadClass} is invoked to load classes that do not map to a - * module then it delegates to the parent class loader. </p> - * - * <p> Attempting to create a layer with all modules defined to the same - * class loader can fail for the following reasons: - * - * <ul> - * - * <li><p> <em>Overlapping packages</em>: Two or more modules in the - * configuration have the same package. </p></li> - * - * <li><p> <em>Split delegation</em>: The resulting class loader would - * need to delegate to more than one class loader in order to load types - * in a specific package. </p></li> - * - * </ul> - * - * <p> In addition, a layer cannot be created if the configuration contains - * a module named "{@code java.base}", or a module contains a package named - * "{@code java}" or a package with a name starting with "{@code java.}". </p> - * - * <p> If there is a security manager then the class loader created by - * this method will load classes and resources with privileges that are - * restricted by the calling context of this method. </p> - * - * @param cf - * The configuration for the layer - * @param parentLayers - * The list of 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 A controller that controls the newly created layer - * - * @throws IllegalArgumentException - * 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 - * @throws SecurityException - * If {@code RuntimePermission("createClassLoader")} or - * {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - * - * @see #findLoader - */ - public static Controller defineModulesWithOneLoader(Configuration cf, - List<Layer> parentLayers, - ClassLoader parentLoader) - { - List<Layer> parents = new ArrayList<>(parentLayers); - checkConfiguration(cf, parents); - - checkCreateClassLoaderPermission(); - checkGetClassLoaderPermission(); - - try { - Loader loader = new Loader(cf.modules(), parentLoader); - loader.initRemotePackageMap(cf, parents); - Layer layer = new Layer(cf, parents, mn -> loader); - return new Controller(layer); - } catch (IllegalArgumentException | IllegalStateException e) { - throw new LayerInstantiationException(e.getMessage()); - } - } - - /** - * 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. - * - * <p> The class loaders created by this method implement <em>direct - * delegation</em> when loading types from modules. When {@link - * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to - * load a class then it uses the package name of the class to map it to a - * module. The package may be in the module defined to the class loader. - * The package may be exported by another module in this layer to the - * module defined to the class loader. It may be in a package exported by a - * module in a parent layer. The class loader delegates to the class loader - * of the module, throwing {@code ClassNotFoundException} if not found by - * that class loader. - * When {@code loadClass} is invoked to load classes that do not map to a - * module then it delegates to the parent class loader. </p> - * - * <p> If there is a security manager then the class loaders created by - * this method will load classes and resources with privileges that are - * restricted by the calling context of this method. </p> - * - * @param cf - * The configuration for the layer - * @param parentLayers - * The list of 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 A controller that controls the newly created layer - * - * @throws IllegalArgumentException - * 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}" or a module contains a package - * named "{@code java}" or a package with a name starting with - * "{@code java.}" - * - * @throws SecurityException - * If {@code RuntimePermission("createClassLoader")} or - * {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - * - * @see #findLoader - */ - public static Controller defineModulesWithManyLoaders(Configuration cf, - List<Layer> parentLayers, - ClassLoader parentLoader) - { - List<Layer> parents = new ArrayList<>(parentLayers); - checkConfiguration(cf, parents); - - checkCreateClassLoaderPermission(); - checkGetClassLoaderPermission(); - - LoaderPool pool = new LoaderPool(cf, parents, parentLoader); - try { - Layer layer = new Layer(cf, parents, pool::loaderFor); - return new Controller(layer); - } catch (IllegalArgumentException | IllegalStateException e) { - throw new LayerInstantiationException(e.getMessage()); - } - } - - /** - * Creates a new layer by defining the modules in the given {@code - * Configuration} to the Java virtual machine. The given function maps each - * module in the configuration, by name, to a class loader. Creating the - * layer informs the Java virtual machine about the classes that may be - * loaded so that the Java virtual machine knows which module that each - * class is a member of. - * - * <p> The class loader delegation implemented by the class 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 be - * ready to load from these modules before there are any attempts to load - * classes or resources. </p> - * - * <p> Creating a {@code Layer} can fail for the following reasons: </p> - * - * <ul> - * - * <li><p> Two or more modules with the same package are mapped to the - * same class loader. </p></li> - * - * <li><p> A module is mapped to a class loader that already has a - * module of the same name defined to it. </p></li> - * - * <li><p> A module is mapped to a class loader that has already - * defined types in any of the packages in the module. </p></li> - * - * </ul> - * - * <p> In addition, a layer cannot be created if the configuration contains - * a module named "{@code java.base}", a configuration contains a module - * with a package named "{@code java}" or a package name starting with - * "{@code java.}" and the module 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}. </p> - * - * <p> If the function to map a module name to class loader throws an error - * or runtime exception then it is propagated to the caller of this method. - * </p> - * - * @apiNote It is implementation specific as to whether creating a Layer - * with this method is an atomic operation or not. Consequentially it is - * possible for this method to fail with some modules, but not all, defined - * to the Java virtual machine. - * - * @param cf - * The configuration for the layer - * @param parentLayers - * The list of parent layers in search order - * @param clf - * The function to map a module name to a class loader - * - * @return A controller that controls the newly created layer - * - * @throws IllegalArgumentException - * If the parent configurations do not match the configuration of - * the parent layers, including order - * @throws LayerInstantiationException - * If creating the layer fails for any of the reasons listed above - * @throws SecurityException - * If {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - */ - public static Controller defineModules(Configuration cf, - List<Layer> parentLayers, - Function<String, ClassLoader> clf) - { - List<Layer> parents = new ArrayList<>(parentLayers); - checkConfiguration(cf, parents); - Objects.requireNonNull(clf); - - checkGetClassLoaderPermission(); - - // The boot layer is checked during module system initialization - if (boot() != null) { - checkForDuplicatePkgs(cf, clf); - } - - try { - Layer layer = new Layer(cf, parents, clf); - return new Controller(layer); - } catch (IllegalArgumentException | IllegalStateException e) { - throw new LayerInstantiationException(e.getMessage()); - } - } - - - /** - * Checks that the parent configurations match the configuration of - * the parent layers. - */ - private static void checkConfiguration(Configuration cf, - List<Layer> parentLayers) - { - Objects.requireNonNull(cf); - - List<Configuration> 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++; - } - } - - private static void checkCreateClassLoaderPermission() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); - } - - private static void checkGetClassLoaderPermission() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - - /** - * Checks a configuration and the module-to-loader mapping to ensure that - * no two modules mapped to the same class loader have the same package. - * It also checks that no two automatic modules have the same package. - * - * @throws LayerInstantiationException - */ - private static void checkForDuplicatePkgs(Configuration cf, - Function<String, ClassLoader> clf) - { - // HashMap allows null keys - Map<ClassLoader, Set<String>> loaderToPackages = new HashMap<>(); - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); - ClassLoader loader = clf.apply(descriptor.name()); - - Set<String> loaderPackages - = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>()); - - for (String pkg : descriptor.packages()) { - boolean added = loaderPackages.add(pkg); - if (!added) { - throw fail("More than one module with package %s mapped" + - " to the same class loader", pkg); - } - } - } - } - - /** - * Creates a LayerInstantiationException with the a message formatted from - * the given format string and arguments. - */ - private static LayerInstantiationException fail(String fmt, Object ... args) { - String msg = String.format(fmt, args); - return new LayerInstantiationException(msg); - } - - - /** - * Returns the configuration for this layer. - * - * @return The configuration for this layer - */ - public Configuration configuration() { - return cf; - } - - - /** - * 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 The list of this layer's parents - */ - public List<Layer> parents() { - return parents; - } - - - /** - * 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<Layer> layers() { - List<Layer> allLayers = this.allLayers; - if (allLayers != null) - return allLayers.stream(); - - allLayers = new ArrayList<>(); - Set<Layer> visited = new HashSet<>(); - Deque<Layer> 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<Layer> allLayers; - - /** - * Returns the set of the modules in this layer. - * - * @return A possibly-empty unmodifiable set of the modules in this layer - */ - public Set<Module> modules() { - Set<Module> modules = this.modules; - if (modules == null) { - this.modules = modules = - Collections.unmodifiableSet(new HashSet<>(nameToModule.values())); - } - return modules; - } - - private volatile Set<Module> modules; - - - /** - * Returns the module with the given name in this layer, or if not in this - * layer, the {@linkplain #parents parent} 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 <em>tree of layers</em> then this is equivalent to - * a depth-first search. - * - * @param name - * The name of the module to find - * - * @return The module with the given name or an empty {@code Optional} - * if there isn't a module with this name in this layer or any - * parent layer - */ - public Optional<Module> findModule(String name) { - Objects.requireNonNull(name); - if (this == EMPTY_LAYER) - return Optional.empty(); - Module m = nameToModule.get(name); - if (m != null) - return Optional.of(m); - - 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 #parents - * parent} layers are searched in the manner specified by {@link - * #findModule(String) findModule}. - * - * <p> If there is a security manager then its {@code checkPermission} - * method is called with a {@code RuntimePermission("getClassLoader")} - * permission to check that the caller is allowed to get access to the - * class loader. </p> - * - * @apiNote This method does not return an {@code Optional<ClassLoader>} - * because `null` must be used to represent the bootstrap class loader. - * - * @param name - * The name of the module to find - * - * @return The ClassLoader that the module is defined to - * - * @throws IllegalArgumentException if a module of the given name is not - * defined in this layer or any parent of this layer - * - * @throws SecurityException if denied by the security manager - */ - public ClassLoader findLoader(String name) { - Optional<Module> 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 <em>empty</em> layer. There are no modules in the empty - * layer. It has no parents. - * - * @return The empty layer - */ - public static Layer empty() { - return EMPTY_LAYER; - } - - - /** - * Returns the boot layer. The boot layer contains at least one module, - * {@code java.base}. Its parent is the {@link #empty() empty} layer. - * - * @apiNote This method returns {@code null} during startup and before - * the boot layer is fully initialized. - * - * @return The boot layer - */ - public static Layer boot() { - return SharedSecrets.getJavaLangAccess().getBootLayer(); - } - - - /** - * Returns the ServicesCatalog for this Layer, creating it if not - * already created. - */ - ServicesCatalog getServicesCatalog() { - ServicesCatalog servicesCatalog = this.servicesCatalog; - if (servicesCatalog != null) - return servicesCatalog; - - synchronized (this) { - servicesCatalog = this.servicesCatalog; - if (servicesCatalog == null) { - servicesCatalog = ServicesCatalog.create(); - nameToModule.values().forEach(servicesCatalog::register); - this.servicesCatalog = servicesCatalog; - } - } - - return servicesCatalog; - } - - 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<Layer> list = CLV.get(loader); - if (list == null) { - list = new CopyOnWriteArrayList<>(); - List<Layer> 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<Layer> layers(ClassLoader loader) { - List<Layer> 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<List<Layer>> CLV = new ClassLoaderValue<>(); -}
--- a/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +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 java.lang.reflect; - -/** - * Thrown when creating a Layer fails. - * - * @see Layer - * - * @since 9 - * @spec JPMS - */ -public class LayerInstantiationException extends RuntimeException { - private static final long serialVersionUID = -906239691613568347L; - - /** - * Constructs a {@code LayerInstantiationException} with no detail message. - */ - public LayerInstantiationException() { - } - - /** - * Constructs a {@code LayerInstantiationException} with the given detail - * message. - * - * @param msg - * The detail message; can be {@code null} - */ - public LayerInstantiationException(String msg) { - super(msg); - } - - /** - * Constructs a {@code LayerInstantiationException} with the given cause. - * - * @param cause - * The cause; can be {@code null} - */ - public LayerInstantiationException(Throwable cause) { - super(cause); - } - - /** - * Constructs a {@code FindException} with the given detail message - * and cause. - * - * @param msg - * The detail message; can be {@code null} - * @param cause - * The cause; can be {@code null} - */ - public LayerInstantiationException(String msg, Throwable cause) { - super(msg, cause); - } - -} -
--- a/src/java.base/share/classes/java/lang/reflect/Module.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1591 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.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.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; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Stream; - -import jdk.internal.loader.BuiltinClassLoader; -import jdk.internal.loader.BootLoader; -import jdk.internal.misc.JavaLangAccess; -import jdk.internal.misc.JavaLangReflectModuleAccess; -import jdk.internal.misc.SharedSecrets; -import jdk.internal.module.ServicesCatalog; -import jdk.internal.module.Resources; -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; - -/** - * Represents a run-time module, either {@link #isNamed() named} or unnamed. - * - * <p> Named modules have a {@link #getName() name} and are constructed by the - * Java Virtual Machine when a graph of modules is defined to the Java virtual - * machine to create a module {@link Layer Layer}. </p> - * - * <p> An unnamed module does not have a name. There is an unnamed module for - * each {@link ClassLoader ClassLoader}, obtained by invoking its {@link - * ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are - * not in a named module are members of their defining class loader's unnamed - * module. </p> - * - * <p> The package names that are parameters or returned by methods defined in - * this class are the fully-qualified names of the packages as defined in - * section 6.5.3 of <cite>The Java™ Language Specification</cite>, for - * example, {@code "java.lang"}. </p> - * - * <p> Unless otherwise specified, passing a {@code null} argument to a method - * in this class causes a {@link NullPointerException NullPointerException} to - * be thrown. </p> - * - * @since 9 - * @spec JPMS - * @see java.lang.Class#getModule - */ - -public final class Module implements AnnotatedElement { - - // the layer that contains this module, can be null - private final Layer layer; - - // module name and loader, these fields are read by VM - private final String name; - private final ClassLoader loader; - - // the module descriptor - private final ModuleDescriptor descriptor; - - - /** - * Creates a new named Module. The resulting Module will be defined to the - * VM but will not read any other modules, will not have any exports setup - * and will not be registered in the service catalog. - */ - private Module(Layer layer, - ClassLoader loader, - ModuleDescriptor descriptor, - URI uri) - { - this.layer = layer; - this.name = descriptor.name(); - this.loader = loader; - this.descriptor = descriptor; - - // 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); - String[] packages = descriptor.packages().toArray(new String[0]); - defineModule0(this, isOpen, vs, loc, packages); - } - - - /** - * Create the unnamed Module for the given ClassLoader. - * - * @see ClassLoader#getUnnamedModule - */ - private Module(ClassLoader loader) { - this.layer = null; - this.name = null; - this.loader = loader; - this.descriptor = null; - } - - - /** - * Creates a named module but without defining the module to the VM. - * - * @apiNote This constructor is for VM white-box testing. - */ - Module(ClassLoader loader, ModuleDescriptor descriptor) { - this.layer = null; - this.name = descriptor.name(); - this.loader = loader; - this.descriptor = descriptor; - } - - - - /** - * Returns {@code true} if this module is a named module. - * - * @return {@code true} if this is a named module - * - * @see ClassLoader#getUnnamedModule() - */ - public boolean isNamed() { - return name != null; - } - - /** - * Returns the module name or {@code null} if this module is an unnamed - * module. - * - * @return The module name - */ - public String getName() { - return name; - } - - /** - * Returns the {@code ClassLoader} for this module. - * - * <p> If there is a security manager then its {@code checkPermission} - * method if first called with a {@code RuntimePermission("getClassLoader")} - * permission to check that the caller is allowed to get access to the - * class loader. </p> - * - * @return The class loader for this module - * - * @throws SecurityException - * If denied by the security manager - */ - public ClassLoader getClassLoader() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - return loader; - } - - /** - * Returns the module descriptor for this module or {@code null} if this - * module is an unnamed module. - * - * @return The module descriptor for this module - */ - public ModuleDescriptor getDescriptor() { - return descriptor; - } - - /** - * Returns the layer that contains this module or {@code null} if this - * module is not in a layer. - * - * A module {@code Layer} contains named modules and therefore this - * method always returns {@code null} when invoked on an unnamed module. - * - * <p> <a href="Proxy.html#dynamicmodule">Dynamic modules</a> are named - * modules that are generated at runtime. A dynamic module may or may - * not be in a module Layer. </p> - * - * @return The layer that contains this module - * - * @see Proxy - */ - public Layer getLayer() { - if (isNamed()) { - Layer layer = this.layer; - if (layer != null) - return layer; - - // special-case java.base as it is created before the boot Layer - if (loader == null && name.equals("java.base")) { - return SharedSecrets.getJavaLangAccess().getBootLayer(); - } - } - - return null; - } - - - // -- - - // special Module to mean "all unnamed modules" - private static final Module ALL_UNNAMED_MODULE = new Module(null); - - // special Module to mean "everyone" - private static final Module EVERYONE_MODULE = new Module(null); - - // set contains EVERYONE_MODULE, used when a package is opened or - // exported unconditionally - private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE); - - - // -- readability -- - - // the modules that this module reads - private volatile Set<Module> reads; - - // additional module (2nd key) that some module (1st key) reflectively reads - private static final WeakPairMap<Module, Module, Boolean> reflectivelyReads - = new WeakPairMap<>(); - - - /** - * Indicates if this module reads the given module. This method returns - * {@code true} if invoked to test if this module reads itself. It also - * returns {@code true} if invoked on an unnamed module (as unnamed - * modules read all modules). - * - * @param other - * The other module - * - * @return {@code true} if this module reads {@code other} - * - * @see #addReads(Module) - */ - public boolean canRead(Module other) { - Objects.requireNonNull(other); - - // an unnamed module reads all modules - if (!this.isNamed()) - return true; - - // all modules read themselves - if (other == this) - return true; - - // check if this module reads other - if (other.isNamed()) { - Set<Module> reads = this.reads; // volatile read - if (reads != null && reads.contains(other)) - return true; - } - - // check if this module reads the other module reflectively - 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() - && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE)) - return true; - - return false; - } - - /** - * 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 read - * themselves), this module is an unnamed module (as unnamed modules read - * all modules), or this module already reads {@code other}. - * - * @implNote <em>Read edges</em> added by this method are <em>weak</em> and - * do not prevent {@code other} from being GC'ed when this module is - * strongly reachable. - * - * @param other - * The other module - * - * @return this module - * - * @throws IllegalCallerException - * If this is a named module and the caller's module is not this - * module - * - * @see #canRead - */ - @CallerSensitive - public Module addReads(Module other) { - Objects.requireNonNull(other); - if (this.isNamed()) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != this) { - throw new IllegalCallerException(caller + " != " + this); - } - implAddReads(other, true); - } - return this; - } - - /** - * Updates this module to read another module. - * - * @apiNote This method is for Proxy use and white-box testing. - */ - void implAddReads(Module other) { - implAddReads(other, true); - } - - /** - * Updates this module to read another module without notifying the VM. - * - * @apiNote This method is for VM white-box testing. - */ - void implAddReadsNoSync(Module other) { - implAddReads(other, false); - } - - /** - * Makes the given {@code Module} readable to this module. - * - * If {@code syncVM} is {@code true} then the VM is notified. - */ - private void implAddReads(Module other, boolean syncVM) { - if (!canRead(other)) { - // update VM first, just in case it fails - if (syncVM) { - if (other == ALL_UNNAMED_MODULE) { - addReads0(this, null); - } else { - addReads0(this, other); - } - } - - // add reflective read - reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE); - } - } - - - // -- exported and open packages -- - - // the packages are open to other modules, can be null - // if the value contains EVERYONE_MODULE then the package is open to all - private volatile Map<String, Set<Module>> openPackages; - - // the packages that are exported, can be null - // if the value contains EVERYONE_MODULE then the package is exported to all - private volatile Map<String, Set<Module>> 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<Module, Module, Map<String, Boolean>> - reflectivelyExports = new WeakPairMap<>(); - - - /** - * Returns {@code true} if this module exports the given package to at - * least the given module. - * - * <p> 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. </p> - * - * <p> This method does not check if the given module reads this module. </p> - * - * @param pn - * The package name - * @param other - * The other 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 implIsExportedOrOpen(pn, other, /*open*/false); - } - - /** - * Returns {@code true} if this module has <em>opened</em> a package to at - * least the given module. - * - * <p> 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. </p> - * - * <p> This method does not check if the given module reads this module. </p> - * - * @param pn - * The package name - * @param other - * The other module - * - * @return {@code true} if this module has <em>opened</em> 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. - * - * <p> 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. </p> - * - * <p> This method does not check if the given module reads this module. </p> - * - * @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 implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/false); - } - - /** - * Returns {@code true} if this module has <em>opened</em> a package - * unconditionally. - * - * <p> 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. </p> - * - * <p> This method does not check if the given module reads this module. </p> - * - * @param pn - * The package name - * - * @return {@code true} if this module has <em>opened</em> the package - * unconditionally - * - * @see ModuleDescriptor#opens() - */ - public boolean isOpen(String pn) { - Objects.requireNonNull(pn); - return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/true); - } - - - /** - * 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; - - // all packages are exported/open to self - if (other == this && containsPackage(pn)) - return true; - - // all packages in open and automatic modules are open - if (descriptor.isOpen() || descriptor.isAutomatic()) - return containsPackage(pn); - - // exported/opened via module declaration/descriptor - if (isStaticallyExportedOrOpen(pn, other, open)) - return true; - - // 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 exports or opens a package to - * the given module via its module declaration. - */ - private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) { - // package is open to everyone or <other> - Map<String, Set<Module>> openPackages = this.openPackages; - if (openPackages != null) { - Set<Module> 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 <other> - Map<String, Set<Module>> exportedPackages = this.exportedPackages; - if (exportedPackages != null) { - Set<Module> 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 or opens given - * package package to the given module. - */ - private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) { - // exported or open to all modules - Map<String, Boolean> 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 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 or open to all unnamed - if (!other.isNamed()) { - 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; - } - } - } - - } - - return false; - } - - - /** - * If the caller's module is this module then update this module to export - * the given package to the given module. - * - * <p> This method has no effect if the package is already exported (or - * <em>open</em>) to the given module. </p> - * - * @apiNote As specified in section 5.4.3 of the <cite>The Java™ - * Virtual Machine Specification </cite>, if an attempt to resolve a - * symbolic reference fails because of a linkage error, then subsequent - * attempts to resolve the reference always fail with the same error that - * was thrown as a result of the initial resolution attempt. - * - * @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 IllegalCallerException - * If this is a named module and the caller's module is not this - * module - * - * @jvms 5.4.3 Resolution - * @see #isExported(String,Module) - */ - @CallerSensitive - public Module addExports(String pn, Module other) { - if (pn == null) - throw new IllegalArgumentException("package is null"); - Objects.requireNonNull(other); - - if (isNamed()) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != this) { - throw new IllegalCallerException(caller + " != " + this); - } - implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true); - } - - return this; - } - - /** - * If this module has <em>opened</em> a package to at least the caller - * module then update this module to open the 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. - * - * <p> This method has no effect if the package is already <em>open</em> - * to the given module. </p> - * - * @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 IllegalCallerException - * If this is a named module and this module has not opened the - * package to at least the caller's 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()) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != this && !isOpen(pn, caller)) - throw new IllegalCallerException(pn + " is not open to " + caller); - 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. - * - * @apiNote This method is for VM white-box testing. - */ - void implAddExportsNoSync(String pn, Module other) { - if (other == null) - other = EVERYONE_MODULE; - implAddExportsOrOpens(pn.replace('/', '.'), other, false, false); - } - - /** - * Updates the exports so that package {@code pn} is exported to module - * {@code other}. - * - * @apiNote This method is for white-box testing. - */ - void implAddExports(String pn, Module other) { - implAddExportsOrOpens(pn, other, false, true); - } - - /** - * 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 implAddExportsOrOpens(String pn, - Module other, - boolean open, - boolean syncVM) { - Objects.requireNonNull(other); - Objects.requireNonNull(pn); - - // all packages are open in unnamed, open, and automatic modules - if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic()) - return; - - // nothing to do if already exported/open to other - if (implIsExportedOrOpen(pn, other, open)) - return; - - // can only export a package in the module - if (!containsPackage(pn)) { - throw new IllegalArgumentException("package " + pn - + " not in contents"); - } - - // update VM first, just in case it fails - if (syncVM) { - if (other == EVERYONE_MODULE) { - addExportsToAll0(this, pn); - } else if (other == ALL_UNNAMED_MODULE) { - addExportsToAllUnnamed0(this, pn); - } else { - addExports0(this, pn, other); - } - } - - // add package name to reflectivelyExports if absent - Map<String, Boolean> map = reflectivelyExports - .computeIfAbsent(this, other, - (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<Module, Class<?>, Boolean> reflectivelyUses - = new WeakPairMap<>(); - - /** - * If the caller's module is this module then update this module to add a - * service dependence on the given service type. This method is intended - * 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 or an automatic module. - * - * <p> This method does not cause {@link Configuration#resolveAndBind - * resolveAndBind} to be re-run. </p> - * - * @param service - * The service type - * - * @return this module - * - * @throws IllegalCallerException - * If this is a named module and the caller's module is not this - * module - * - * @see #canUse(Class) - * @see ModuleDescriptor#uses() - */ - @CallerSensitive - public Module addUses(Class<?> service) { - Objects.requireNonNull(service); - - if (isNamed() && !descriptor.isAutomatic()) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != this) { - throw new IllegalCallerException(caller + " != " + this); - } - 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 or an automatic module. - * - * @param service - * The service type - * - * @return {@code true} if this module uses service type {@code st} - * - * @see #addUses(Class) - */ - public boolean canUse(Class<?> service) { - Objects.requireNonNull(service); - - if (!isNamed()) - return true; - - if (descriptor.isAutomatic()) - return true; - - // uses was declared - if (descriptor.uses().contains(service.getName())) - return true; - - // uses added via addUses - return reflectivelyUses.containsKeyPair(this, service); - } - - - - // -- packages -- - - // Additional packages that are added to the module at run-time. - private volatile Map<String, Boolean> extraPackages; - - private boolean containsPackage(String pn) { - if (descriptor.packages().contains(pn)) - return true; - Map<String, Boolean> extraPackages = this.extraPackages; - if (extraPackages != null && extraPackages.containsKey(pn)) - return true; - return false; - } - - - /** - * Returns an array of the package names of the packages in this module. - * - * <p> For named modules, the returned array contains an element for each - * package in the module. </p> - * - * <p> For unnamed modules, this method is the equivalent to invoking the - * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of - * this module's class loader and returning the array of package names. </p> - * - * <p> A package name appears at most once in the returned array. </p> - * - * @apiNote This method returns an array rather than a {@code Set} for - * consistency with other {@code java.lang.reflect} types. - * - * @return an array of the package names of the packages in this module - */ - public String[] getPackages() { - if (isNamed()) { - - Set<String> packages = descriptor.packages(); - Map<String, Boolean> extraPackages = this.extraPackages; - if (extraPackages == null) { - return packages.toArray(new String[0]); - } else { - return Stream.concat(packages.stream(), - extraPackages.keySet().stream()) - .toArray(String[]::new); - } - - } else { - // unnamed module - Stream<Package> packages; - if (loader == null) { - packages = BootLoader.packages(); - } else { - packages = SharedSecrets.getJavaLangAccess().packages(loader); - } - return packages.map(Package::getName).toArray(String[]::new); - } - } - - /** - * Add a package to this module without notifying the VM. - * - * @apiNote This method is VM white-box testing. - */ - void implAddPackageNoSync(String pn) { - implAddPackage(pn.replace('/', '.'), false); - } - - /** - * Add a package to this module. - * - * If {@code syncVM} is {@code true} then the VM is notified. This method is - * a no-op if this is an unnamed module or the module already contains the - * package. - * - * @throws IllegalArgumentException if the package name is not legal - * @throws IllegalStateException if the package is defined to another module - */ - private void implAddPackage(String pn, boolean syncVM) { - // no-op if unnamed module - if (!isNamed()) - return; - - // no-op if module contains the package - if (containsPackage(pn)) - return; - - // check package name is legal for named modules - if (pn.isEmpty()) - throw new IllegalArgumentException("Cannot add <unnamed> package"); - for (int i=0; i<pn.length(); i++) { - char c = pn.charAt(i); - if (c == '/' || c == ';' || c == '[') { - throw new IllegalArgumentException("Illegal character: " + c); - } - } - - // create extraPackages if needed - Map<String, Boolean> extraPackages = this.extraPackages; - if (extraPackages == null) { - synchronized (this) { - extraPackages = this.extraPackages; - if (extraPackages == null) - this.extraPackages = extraPackages = new ConcurrentHashMap<>(); - } - } - - // update VM first in case it fails. This is a no-op if another thread - // beats us to add the package first - if (syncVM) { - // throws IllegalStateException if defined to another module - addPackage0(this, pn); - if (descriptor.isOpen() || descriptor.isAutomatic()) { - addExportsToAll0(this, pn); - } - } - extraPackages.putIfAbsent(pn, Boolean.TRUE); - } - - - // -- creating Module objects -- - - /** - * Defines all module in a configuration to the runtime. - * - * @return a map of module name to runtime {@code Module} - * - * @throws IllegalArgumentException - * If defining any of the modules to the VM fails - */ - static Map<String, Module> defineModules(Configuration cf, - Function<String, ClassLoader> clf, - Layer layer) - { - Map<String, Module> nameToModule = new HashMap<>(); - Map<String, ClassLoader> moduleToLoader = new HashMap<>(); - - boolean isBootLayer = (Layer.boot() == null); - Set<ClassLoader> 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(); - URI uri = mref.location().orElse(null); - ClassLoader loader = moduleToLoader.get(resolvedModule.name()); - Module m; - 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); - } - nameToModule.put(name, m); - moduleToLoader.put(name, loader); - } - - // setup readability and exports - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleReference mref = resolvedModule.reference(); - ModuleDescriptor descriptor = mref.descriptor(); - - String mn = descriptor.name(); - Module m = nameToModule.get(mn); - assert m != null; - - // reads - Set<Module> reads = new HashSet<>(); - - // name -> source Module when in parent layer - Map<String, Module> nameToSource = Collections.emptyMap(); - - for (ResolvedModule other : resolvedModule.reads()) { - Module m2 = null; - if (other.configuration() == cf) { - // this configuration - m2 = nameToModule.get(other.name()); - assert m2 != null; - } else { - // parent layer - for (Layer parent: layer.parents()) { - m2 = findModule(parent, other); - if (m2 != null) - break; - } - assert m2 != null; - if (nameToSource.isEmpty()) - nameToSource = new HashMap<>(); - nameToSource.put(other.name(), m2); - } - reads.add(m2); - - // update VM view - addReads0(m, m2); - } - m.reads = reads; - - // automatic modules read all unnamed modules - if (descriptor.isAutomatic()) { - m.implAddReads(ALL_UNNAMED_MODULE, true); - } - - // exports and opens - initExportsAndOpens(m, nameToSource, nameToModule, layer.parents()); - } - - // 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<Module> 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(Module m, - Map<String, Module> nameToSource, - Map<String, Module> nameToModule, - List<Layer> parents) { - // The VM doesn't special case open or automatic modules so need to - // export all packages - ModuleDescriptor descriptor = m.getDescriptor(); - if (descriptor.isOpen() || descriptor.isAutomatic()) { - assert descriptor.opens().isEmpty(); - for (String source : descriptor.packages()) { - addExportsToAll0(m, source); - } - return; - } - - Map<String, Set<Module>> openPackages = new HashMap<>(); - Map<String, Set<Module>> exportedPackages = new HashMap<>(); - - // process the open packages first - for (Opens opens : descriptor.opens()) { - String source = opens.source(); - - if (opens.isQualified()) { - // qualified opens - Set<Module> targets = new HashSet<>(); - for (String target : opens.targets()) { - Module m2 = findModule(target, nameToSource, nameToModule, parents); - if (m2 != null) { - addExports0(m, source, m2); - targets.add(m2); - } - } - if (!targets.isEmpty()) { - openPackages.put(source, targets); - } - } else { - // unqualified opens - addExportsToAll0(m, source); - openPackages.put(source, EVERYONE_SET); - } - } - - // next the exports, skipping exports when the package is open - for (Exports exports : descriptor.exports()) { - String source = exports.source(); - - // skip export if package is already open to everyone - Set<Module> openToTargets = openPackages.get(source); - if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE)) - continue; - - if (exports.isQualified()) { - // qualified exports - Set<Module> targets = new HashSet<>(); - for (String target : exports.targets()) { - Module m2 = findModule(target, nameToSource, nameToModule, parents); - if (m2 != null) { - // skip qualified export if already open to m2 - if (openToTargets == null || !openToTargets.contains(m2)) { - addExports0(m, source, m2); - targets.add(m2); - } - } - } - if (!targets.isEmpty()) { - exportedPackages.put(source, targets); - } - - } else { - // unqualified exports - addExportsToAll0(m, source); - exportedPackages.put(source, EVERYONE_SET); - } - } - - if (!openPackages.isEmpty()) - m.openPackages = openPackages; - if (!exportedPackages.isEmpty()) - m.exportedPackages = exportedPackages; - } - - /** - * Find the runtime Module with the given name. The module name is the - * name of a target module in a qualified exports or opens directive. - * - * @param target The target module to find - * @param nameToSource The modules in parent layers that are read - * @param nameToModule The modules in the layer under construction - * @param parents The parent layers - */ - private static Module findModule(String target, - Map<String, Module> nameToSource, - Map<String, Module> nameToModule, - List<Layer> parents) { - Module m = nameToSource.get(target); - if (m == null) { - m = nameToModule.get(target); - if (m == null) { - for (Layer parent : parents) { - m = parent.findModule(target).orElse(null); - if (m != null) break; - } - } - } - return m; - } - - - // -- annotations -- - - /** - * {@inheritDoc} - * This method returns {@code null} when invoked on an unnamed module. - */ - @Override - public <T extends Annotation> T getAnnotation(Class<T> 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<Class<?>> 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); - } - } - - - // -- misc -- - - - /** - * 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. As with {@link Class#getResourceAsStream - * Class.getResourceAsStream}, this method delegates to the module's class - * loader {@link ClassLoader#findResource(String,String) - * findResource(String,String)} method, invoking it with the module name - * (or {@code null} when the module is unnamed) and the name of the - * resource. If the resource name has a leading slash then it is dropped - * before delegation. - * - * <p> A resource in a named module may be <em>encapsulated</em> so that - * it cannot be located by code in other modules. Whether a resource can be - * located or not is determined as follows: </p> - * - * <ul> - * <li> If the resource name ends with "{@code .class}" then it is not - * encapsulated. </li> - * - * <li> A <em>package name</em> is derived from the resource name. If - * the package name is a {@link #getPackages() package} in the module - * then the resource can only be located by the caller of this method - * when the package is {@link #isOpen(String,Module) open} to at least - * the caller's module. If the resource is not in a package in the module - * then the resource is not encapsulated. </li> - * </ul> - * - * <p> In the above, the <em>package name</em> for a resource is derived - * from the subsequence of characters that precedes the last {@code '/'} in - * the name and then replacing each {@code '/'} character in the subsequence - * with {@code '.'}. A leading slash is ignored when deriving the package - * name. As an example, the package name derived for a resource named - * "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name - * with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated - * because "{@code META-INF}" is not a legal package name. </p> - * - * <p> 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. </p> - * - * @param name - * The resource name - * - * @return An input stream for reading the resource or {@code null} - * - * @throws IOException - * If an I/O error occurs - * - * @see Class#getResourceAsStream(String) - */ - @CallerSensitive - public InputStream getResourceAsStream(String name) throws IOException { - if (name.startsWith("/")) { - name = name.substring(1); - } - - if (isNamed() && Resources.canEncapsulate(name)) { - Module caller = Reflection.getCallerClass().getModule(); - if (caller != this && caller != Object.class.getModule()) { - // ignore packages added for proxies via addPackage - Set<String> packages = getDescriptor().packages(); - String pn = Resources.toPackageName(name); - if (packages.contains(pn) && !isOpen(pn, caller)) { - // resource is in package not open to caller - return null; - } - } - } - - 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(); - } catch (SecurityException e) { } - } - - return null; - } - - /** - * Returns the string representation of this module. For a named module, - * the representation is the string {@code "module"}, followed by a space, - * and then the module name. For an unnamed module, the representation is - * the string {@code "unnamed module"}, followed by a space, and then an - * implementation specific string that identifies the unnamed module. - * - * @return The string representation of this module - */ - @Override - public String toString() { - if (isNamed()) { - return "module " + name; - } else { - String id = Integer.toHexString(System.identityHashCode(this)); - return "unnamed module @" + id; - } - } - - - // -- native methods -- - - // JVM_DefineModule - private static native void defineModule0(Module module, - boolean isOpen, - String version, - String location, - String[] pns); - - // JVM_AddReadsModule - private static native void addReads0(Module from, Module to); - - // JVM_AddModuleExports - private static native void addExports0(Module from, String pn, Module to); - - // JVM_AddModuleExportsToAll - private static native void addExportsToAll0(Module from, String pn); - - // JVM_AddModuleExportsToAllUnnamed - private static native void addExportsToAllUnnamed0(Module from, String pn); - - // JVM_AddModulePackage - private static native void addPackage0(Module m, String pn); - - /** - * Register shared secret to provide access to package-private methods - */ - static { - SharedSecrets.setJavaLangReflectModuleAccess( - new JavaLangReflectModuleAccess() { - @Override - public Module defineUnnamedModule(ClassLoader loader) { - return new Module(loader); - } - @Override - public Module defineModule(ClassLoader loader, - ModuleDescriptor descriptor, - URI uri) { - return new Module(null, loader, descriptor, uri); - } - @Override - public void addReads(Module m1, Module m2) { - m1.implAddReads(m2, true); - } - @Override - public void addReadsAllUnnamed(Module m) { - m.implAddReads(Module.ALL_UNNAMED_MODULE); - } - @Override - public void addExports(Module m, String pn) { - m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true); - } - @Override - public void addExports(Module m, String pn, Module other) { - m.implAddExportsOrOpens(pn, other, false, true); - } - @Override - public void addExportsToAllUnnamed(Module m, String pn) { - m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true); - } - @Override - public void addOpens(Module m, String pn) { - m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true); - } - @Override - public void addOpens(Module m, String pn, Module other) { - m.implAddExportsOrOpens(pn, other, true, 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 ServicesCatalog getServicesCatalog(Layer layer) { - return layer.getServicesCatalog(); - } - @Override - public Stream<Layer> layers(Layer layer) { - return layer.layers(); - } - @Override - public Stream<Layer> layers(ClassLoader loader) { - return Layer.layers(loader); - } - }); - } -}
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java Fri Apr 07 08:05:54 2017 +0000 @@ -227,11 +227,11 @@ * {@code Proxy.newProxyInstance} method should be used instead. * * <p> - * A dynamic module can read the modules of all of the superinterfaces of a proxy class - * and the modules of the types referenced by all public method signatures + * A dynamic module can read the modules of all of the superinterfaces of a proxy + * class and the modules of the types referenced by all public method signatures * of a proxy class. If a superinterface or a referenced type, say {@code T}, - * is in a non-exported package, the {@linkplain java.lang.reflect.Module module} - * of {@code T} is updated to export the package of {@code T} to the dynamic module. + * is in a non-exported package, the {@linkplain Module module} of {@code T} is + * updated to export the package of {@code T} to the dynamic module. * * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3> *
--- a/src/java.base/share/classes/java/lang/reflect/WeakPairMap.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -/* - * 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 java.lang.reflect; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.Collection; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.BiFunction; - -/** - * A WeakHashMap-like data structure that uses a pair of weakly-referenced keys - * with identity equality semantics to associate a strongly-referenced value. - * Unlike WeakHashMap, this data structure is thread-safe. - * - * @param <K1> the type of 1st key in key pair - * @param <K2> the type of 2nd key in key pair - * @param <V> the type of value - * @author Peter Levart - */ -final class WeakPairMap<K1, K2, V> { - - private final ConcurrentHashMap<Pair<K1, K2>, V> map = new ConcurrentHashMap<>(); - private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); - - /** - * Tests if the specified pair of keys are associated with a value - * in the WeakPairMap. - * - * @param k1 the 1st of the pair of keys - * @param k2 the 2nd of the pair of keys - * @return true if and only if the specified key pair is in this WeakPairMap, - * as determined by the identity comparison; false otherwise - * @throws NullPointerException if any of the specified keys is null - */ - public boolean containsKeyPair(K1 k1, K2 k2) { - expungeStaleAssociations(); - return map.containsKey(Pair.lookup(k1, k2)); - } - - /** - * Returns the value to which the specified pair of keys is mapped, or null - * if this WeakPairMap contains no mapping for the key pair. - * <p>More formally, if this WeakPairMap contains a mapping from a key pair - * {@code (_k1, _k2)} to a value {@code v} such that - * {@code k1 == _k1 && k2 == _k2}, then this method returns {@code v}; - * otherwise it returns {@code null}. - * (There can be at most one such mapping.) - * - * @param k1 the 1st of the pair of keys for which the mapped value is to - * be returned - * @param k2 the 2nd of the pair of keys for which the mapped value is to - * be returned - * @return the value to which the specified key pair is mapped, or null if - * this map contains no mapping for the key pair - * @throws NullPointerException if any of the specified keys is null - */ - public V get(K1 k1, K2 k2) { - expungeStaleAssociations(); - return map.get(Pair.lookup(k1, k2)); - } - - /** - * Maps the specified key pair to the specified value in this WeakPairMap. - * Neither the keys nor the value can be null. - * <p>The value can be retrieved by calling the {@link #get} method - * with the the same keys (compared by identity). - * - * @param k1 the 1st of the pair of keys with which the specified value is to - * be associated - * @param k2 the 2nd of the pair of keys with which the specified value is to - * be associated - * @param v value to be associated with the specified key pair - * @return the previous value associated with key pair, or {@code null} if - * there was no mapping for key pair - * @throws NullPointerException if any of the specified keys or value is null - */ - public V put(K1 k1, K2 k2, V v) { - expungeStaleAssociations(); - return map.put(Pair.weak(k1, k2, queue), v); - } - - /** - * If the specified key pair is not already associated with a value, - * associates it with the given value and returns {@code null}, else does - * nothing and returns the currently associated value. - * - * @param k1 the 1st of the pair of keys with which the specified value is to - * be associated - * @param k2 the 2nd of the pair of keys with which the specified value is to - * be associated - * @param v value to be associated with the specified key pair - * @return the previous value associated with key pair, or {@code null} if - * there was no mapping for key pair - * @throws NullPointerException if any of the specified keys or value is null - */ - public V putIfAbsent(K1 k1, K2 k2, V v) { - expungeStaleAssociations(); - return map.putIfAbsent(Pair.weak(k1, k2, queue), v); - } - - /** - * If the specified key pair is not already associated with a value, - * attempts to compute its value using the given mapping function - * and enters it into this WeakPairMap unless {@code null}. The entire - * method invocation is performed atomically, so the function is - * applied at most once per key pair. Some attempted update operations - * on this WeakPairMap by other threads may be blocked while computation - * is in progress, so the computation should be short and simple, - * and must not attempt to update any other mappings of this WeakPairMap. - * - * @param k1 the 1st of the pair of keys with which the - * computed value is to be associated - * @param k2 the 2nd of the pair of keys with which the - * computed value is to be associated - * @param mappingFunction the function to compute a value - * @return the current (existing or computed) value associated with - * the specified key pair, or null if the computed value is null - * @throws NullPointerException if any of the specified keys or - * mappingFunction is null - * @throws IllegalStateException if the computation detectably - * attempts a recursive update to this map - * that would otherwise never complete - * @throws RuntimeException or Error if the mappingFunction does so, in - * which case the mapping is left unestablished - */ - public V computeIfAbsent(K1 k1, K2 k2, - BiFunction<? super K1, ? super K2, ? extends V> - mappingFunction) { - expungeStaleAssociations(); - try { - return map.computeIfAbsent( - Pair.weak(k1, k2, queue), - pair -> mappingFunction.apply(pair.first(), pair.second())); - } finally { - Reference.reachabilityFence(k1); - Reference.reachabilityFence(k2); - } - } - - /** - * Returns a {@link Collection} view of the values contained in this - * WeakPairMap. The collection is backed by the WeakPairMap, so changes to - * the map are reflected in the collection, and vice-versa. The collection - * supports element removal, which removes the corresponding - * mapping from this map, via the {@code Iterator.remove}, - * {@code Collection.remove}, {@code removeAll}, - * {@code retainAll}, and {@code clear} operations. It does not - * support the {@code add} or {@code addAll} operations. - * - * @return the collection view - */ - public Collection<V> values() { - expungeStaleAssociations(); - return map.values(); - } - - /** - * Removes associations from this WeakPairMap for which at least one of the - * keys in key pair has been found weakly-reachable and corresponding - * WeakRefPeer(s) enqueued. Called as part of each public operation. - */ - private void expungeStaleAssociations() { - WeakRefPeer<?> peer; - while ((peer = (WeakRefPeer<?>) queue.poll()) != null) { - map.remove(peer.weakPair()); - } - } - - /** - * Common interface of both {@link Weak} and {@link Lookup} key pairs. - */ - private interface Pair<K1, K2> { - - static <K1, K2> Pair<K1, K2> weak(K1 k1, K2 k2, - ReferenceQueue<Object> queue) { - return new Weak<>(k1, k2, queue); - } - - static <K1, K2> Pair<K1, K2> lookup(K1 k1, K2 k2) { - return new Lookup<>(k1, k2); - } - - /** - * @return The 1st of the pair of keys (may be null for {@link Weak} - * when it gets cleared) - */ - K1 first(); - - /** - * @return The 2nd of the pair of keys (may be null for {@link Weak} - * when it gets cleared) - */ - K2 second(); - - static int hashCode(Object first, Object second) { - // assert first != null && second != null; - return System.identityHashCode(first) ^ - System.identityHashCode(second); - } - - static boolean equals(Object first, Object second, Pair<?, ?> p) { - return first != null && second != null && - first == p.first() && second == p.second(); - } - - /** - * A Pair where both keys are weakly-referenced. - * It is composed of two instances of {@link WeakRefPeer}s: - * <pre>{@code - * - * +-referent-> [K1] +-referent-> [K2] - * | | - * +----------------+ +----------------+ - * | Pair.Weak <: |-----peer----->| (anonymous) <: | - * | WeakRefPeer, | | WeakRefPeer | - * | Pair |<--weakPair()--| | - * +----------------+ +----------------+ - * | ^ - * | | - * +-weakPair()-+ - * - * }</pre> - * <p> - * Pair.Weak is used for CHM keys. Both peers are associated with the - * same {@link ReferenceQueue} so when either of their referents - * becomes weakly-reachable, the corresponding entries can be - * {@link #expungeStaleAssociations() expunged} from the map. - */ - final class Weak<K1, K2> extends WeakRefPeer<K1> implements Pair<K1, K2> { - - // saved hash so it can be retrieved after the reference is cleared - private final int hash; - // link to <K2> peer - private final WeakRefPeer<K2> peer; - - Weak(K1 k1, K2 k2, ReferenceQueue<Object> queue) { - super(k1, queue); - hash = Pair.hashCode(k1, k2); - peer = new WeakRefPeer<>(k2, queue) { - // link back to <K1> peer - @Override - Weak<?, ?> weakPair() { return Weak.this; } - }; - } - - @Override - Weak<?, ?> weakPair() { - return this; - } - - @Override - public K1 first() { - return get(); - } - - @Override - public K2 second() { - return peer.get(); - } - - @Override - public int hashCode() { - return hash; - } - - @Override - public boolean equals(Object obj) { - return this == obj || - (obj instanceof Pair && - Pair.equals(first(), second(), (Pair<?, ?>) obj)); - } - } - - /** - * Optimized lookup Pair, used as lookup key in methods like - * {@link java.util.Map#get(Object)} or - * {@link java.util.Map#containsKey(Object)}) where - * there is a great chance its allocation is eliminated - * by escape analysis when such lookups are inlined by JIT. - * All its methods are purposely designed so that 'this' is never - * passed to any other method or used as identity. - */ - final class Lookup<K1, K2> implements Pair<K1, K2> { - private final K1 k1; - private final K2 k2; - - Lookup(K1 k1, K2 k2) { - this.k1 = Objects.requireNonNull(k1); - this.k2 = Objects.requireNonNull(k2); - } - - @Override - public K1 first() { - return k1; - } - - @Override - public K2 second() { - return k2; - } - - @Override - public int hashCode() { - return Pair.hashCode(k1, k2); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof Pair && - Pair.equals(k1, k2, (Pair<?, ?>) obj); - } - } - } - - /** - * Common abstract supertype of a pair of WeakReference peers. - */ - private static abstract class WeakRefPeer<K> extends WeakReference<K> { - - WeakRefPeer(K k, ReferenceQueue<Object> queue) { - super(Objects.requireNonNull(k), queue); - } - - /** - * @return the {@link Pair.Weak} side of the pair of peers. - */ - abstract Pair.Weak<?, ?> weakPair(); - } -}
--- a/src/java.base/share/classes/java/lang/reflect/package-info.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/lang/reflect/package-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. * 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,11 +25,10 @@ /** * Provides classes and interfaces for obtaining reflective information about - * modules, classes and objects. Reflection allows programmatic access to - * information about modules and to the fields, methods and constructors of - * loaded classes, and the use of reflected fields, methods, and constructors - * to operate on their underlying counterparts, within encapsulation and - * security restrictions. + * classes and objects. Reflection allows programmatic access to information + * about the fields, methods and constructors of loaded classes, and the use + * of reflected fields, methods, and constructors to operate on their underlying + * counterparts, within encapsulation and security restrictions. * * <p>{@code AccessibleObject} allows suppression of access checks if * the necessary {@code ReflectPermission} is available.
--- a/src/java.base/share/classes/java/util/ResourceBundle.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/util/ResourceBundle.java Fri Apr 07 08:05:54 2017 +0000 @@ -50,7 +50,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; -import java.lang.reflect.Module; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection;
--- a/src/java.base/share/classes/java/util/ServiceLoader.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/util/ServiceLoader.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,10 +31,8 @@ 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.AccessControlContext; @@ -50,7 +48,6 @@ import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; 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; @@ -160,7 +157,7 @@ * <h2> Locating providers </h2> * * <p> The {@code load} methods locate providers using a class loader or module - * {@link Layer layer}. When locating providers using a class loader then + * {@link ModuleLayer 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. @@ -168,11 +165,11 @@ * <p> 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 + * other than the {@link ModuleLayer#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 + * ModuleLayer#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. @@ -198,7 +195,7 @@ * 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 + * delegation chain, defines modules in a custom module {@link ModuleLayer} 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. </li> @@ -216,11 +213,11 @@ * method finds the service configuration files. </li> * </ul> * - * <p> 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 + * <p> Service loaders created to locate providers in a {@linkplain ModuleLayer + * module 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 @@ -352,12 +349,12 @@ // The class of the service type private final String serviceName; - // The module Layer used to locate providers; null when locating + // The module layer used to locate providers; null when locating // providers using a class loader - private final Layer layer; + private final ModuleLayer layer; // The class loader used to locate, load, and instantiate providers; - // null when locating provider using a module Layer + // null when locating provider using a module layer private final ClassLoader loader; // The access control context taken when the ServiceLoader is created @@ -376,10 +373,8 @@ private int reloadCount; private static JavaLangAccess LANG_ACCESS; - private static JavaLangReflectModuleAccess JLRM_ACCESS; static { LANG_ACCESS = SharedSecrets.getJavaLangAccess(); - JLRM_ACCESS = SharedSecrets.getJavaLangReflectModuleAccess(); } /** @@ -425,13 +420,13 @@ /** * Initializes a new instance of this class for locating service providers - * in a module Layer. + * in a module layer. * * @throws ServiceConfigurationError * 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<S> svc) { + private ServiceLoader(Class<?> caller, ModuleLayer layer, Class<S> svc) { Objects.requireNonNull(caller); Objects.requireNonNull(layer); Objects.requireNonNull(svc); @@ -512,12 +507,15 @@ /** * 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 declares that it uses the service type. */ private static void checkCaller(Class<?> caller, Class<?> svc) { - Module callerModule = caller.getModule(); + if (caller == null) { + fail(svc, "no caller to check if it declares `uses`"); + } // Check access to the service type + Module callerModule = caller.getModule(); int mods = svc.getModifiers(); if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) { fail(svc, "service type not accessible to " + callerModule); @@ -826,13 +824,13 @@ /** * Implements lazy service provider lookup of service providers that - * are provided by modules in a module Layer (or parent layers) + * are provided by modules in a module layer (or parent layers) */ private final class LayerLookupIterator<T> implements Iterator<Provider<T>> { - Deque<Layer> stack = new ArrayDeque<>(); - Set<Layer> visited = new HashSet<>(); + Deque<ModuleLayer> stack = new ArrayDeque<>(); + Set<ModuleLayer> visited = new HashSet<>(); Iterator<ServiceProvider> iterator; ServiceProvider next; // next provider to load @@ -841,8 +839,8 @@ stack.push(layer); } - private Iterator<ServiceProvider> providers(Layer layer) { - ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer); + private Iterator<ServiceProvider> providers(ModuleLayer layer) { + ServicesCatalog catalog = LANG_ACCESS.getServicesCatalog(layer); return catalog.findServices(serviceName).iterator(); } @@ -864,10 +862,10 @@ if (stack.isEmpty()) return false; - Layer layer = stack.pop(); - List<Layer> parents = layer.parents(); + ModuleLayer layer = stack.pop(); + List<ModuleLayer> parents = layer.parents(); for (int i = parents.size() - 1; i >= 0; i--) { - Layer parent = parents.get(i); + ModuleLayer parent = parents.get(i); if (!visited.contains(parent)) { visited.add(parent); stack.push(parent); @@ -915,8 +913,8 @@ * Returns iterator to iterate over the implementations of {@code * service} in the given layer. */ - private List<ServiceProvider> providers(Layer layer) { - ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer); + private List<ServiceProvider> providers(ModuleLayer layer) { + ServicesCatalog catalog = LANG_ACCESS.getServicesCatalog(layer); return catalog.findServices(serviceName); } @@ -946,10 +944,10 @@ return providers.iterator(); } else { List<ServiceProvider> allProviders = new ArrayList<>(providers); - Layer bootLayer = Layer.boot(); - Iterator<Layer> iterator = JLRM_ACCESS.layers(loader).iterator(); + ModuleLayer bootLayer = ModuleLayer.boot(); + Iterator<ModuleLayer> iterator = LANG_ACCESS.layers(loader).iterator(); while (iterator.hasNext()) { - Layer layer = iterator.next(); + ModuleLayer layer = iterator.next(); if (layer != bootLayer) { allProviders.addAll(providers(layer)); } @@ -1535,7 +1533,7 @@ /** * Creates a new service loader for the given service type that loads - * service providers from modules in the given {@code Layer} and its + * service providers from modules in the given {@code ModuleLayer} and its * ancestors. * * @apiNote Unlike the other load methods defined here, the service type @@ -1545,7 +1543,7 @@ * @param <S> the class of the service type * * @param layer - * The module Layer + * The module layer * * @param service * The interface or abstract class representing the service @@ -1561,7 +1559,7 @@ * @spec JPMS */ @CallerSensitive - public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) { + public static <S> ServiceLoader<S> load(ModuleLayer layer, Class<S> service) { return new ServiceLoader<>(Reflection.getCallerClass(), layer, service); }
--- a/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,7 +31,6 @@ 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;
--- a/src/java.base/share/classes/javax/crypto/JceSecurityManager.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/javax/crypto/JceSecurityManager.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package javax.crypto; -import java.lang.reflect.Module; import java.security.*; import java.net.*; import java.util.*;
--- a/src/java.base/share/classes/jdk/internal/loader/BootLoader.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,8 +27,6 @@ import java.io.IOException; import java.io.InputStream; import java.lang.module.ModuleReference; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -62,8 +60,7 @@ private static final String JAVA_HOME = System.getProperty("java.home"); static { - UNNAMED_MODULE - = SharedSecrets.getJavaLangReflectModuleAccess().defineUnnamedModule(null); + UNNAMED_MODULE = SharedSecrets.getJavaLangAccess().defineUnnamedModule(null); setBootLoaderUnnamedModule0(UNNAMED_MODULE); } @@ -255,7 +252,7 @@ if (mn != null) { // named module from runtime image or exploded module - Optional<Module> om = Layer.boot().findModule(mn); + Optional<Module> om = ModuleLayer.boot().findModule(mn); if (!om.isPresent()) throw new InternalError(mn + " not in boot layer"); return om.get();
--- a/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,7 +27,6 @@ import java.io.File; import java.io.IOException; -import java.lang.reflect.Module; import java.net.URL; import java.nio.file.InvalidPathException; import java.nio.file.Paths;
--- a/src/java.base/share/classes/jdk/internal/loader/Loader.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/loader/Loader.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,7 +33,6 @@ import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -80,8 +79,8 @@ * loader. This allows automatic modules (for example) to link to types in the * unnamed module of the parent class loader. * - * @see Layer#defineModulesWithOneLoader - * @see Layer#defineModulesWithManyLoaders + * @see ModuleModuleLayer#defineModulesWithOneLoader + * @see ModuleModuleLayer#defineModulesWithManyLoaders */ public final class Loader extends SecureClassLoader { @@ -207,10 +206,10 @@ * @param cf the Configuration containing at least modules to be defined to * this class loader * - * @param parentLayers the parent Layers + * @param parentModuleLayers the parent ModuleLayers */ public Loader initRemotePackageMap(Configuration cf, - List<Layer> parentLayers) + List<ModuleLayer> parentModuleLayers) { for (String name : nameToModule.keySet()) { ResolvedModule resolvedModule = cf.findModule(name).get(); @@ -236,8 +235,8 @@ } else { // find the layer for the target module - Layer layer = parentLayers.stream() - .map(parent -> findLayer(parent, other.configuration())) + ModuleLayer layer = parentModuleLayers.stream() + .map(parent -> findModuleLayer(parent, other.configuration())) .flatMap(Optional::stream) .findAny() .orElseThrow(() -> @@ -286,8 +285,8 @@ * Find the layer corresponding to the given configuration in the tree * of layers rooted at the given parent. */ - private Optional<Layer> findLayer(Layer parent, Configuration cf) { - return SharedSecrets.getJavaLangReflectModuleAccess().layers(parent) + private Optional<ModuleLayer> findModuleLayer(ModuleLayer parent, Configuration cf) { + return SharedSecrets.getJavaLangAccess().layers(parent) .filter(l -> l.configuration() == cf) .findAny(); }
--- a/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,7 +27,6 @@ import java.lang.module.Configuration; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -36,7 +35,7 @@ /** * A pool of class loaders. * - * @see Layer#defineModulesWithManyLoaders + * @see ModuleLayer#defineModulesWithManyLoaders */ public final class LoaderPool { @@ -51,7 +50,7 @@ * created with the given parent class loader as its parent. */ public LoaderPool(Configuration cf, - List<Layer> parentLayers, + List<ModuleLayer> parentLayers, ClassLoader parentLoader) { Map<String, Loader> loaders = new HashMap<>();
--- a/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java Fri Apr 07 08:05:54 2017 +0000 @@ -34,7 +34,6 @@ import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.lang.ref.ReferenceQueue; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection;
--- a/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,7 +31,6 @@ import java.lang.System.LoggerFinder; import java.lang.System.Logger; import java.lang.ref.WeakReference; -import java.lang.reflect.Module; import java.util.Objects; import jdk.internal.misc.VM; import sun.util.logging.PlatformLogger; @@ -402,10 +401,10 @@ * @param module The module on behalf of which the logger is created. * If the module is not loaded from the Boot ClassLoader, * the LoggerFinder is accessed and the logger returned - * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.reflect.Module)} + * by {@link LoggerFinder#getLogger(java.lang.String, java.lang.Module)} * is returned to the caller directly. * Otherwise, the logger returned by - * {@link #getLazyLogger(java.lang.String, java.lang.reflect.Module)} + * {@link #getLazyLogger(java.lang.String, java.lang.Module)} * is returned to the caller. * * @return a (possibly lazy) Logger instance.
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java Fri Apr 07 08:05:54 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * 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,10 +27,10 @@ import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.module.ModuleDescriptor; import java.lang.reflect.Executable; -import java.lang.reflect.Layer; import java.lang.reflect.Method; -import java.lang.reflect.Module; +import java.net.URI; import java.net.URL; import java.security.AccessControlContext; import java.security.ProtectionDomain; @@ -38,6 +38,7 @@ 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; @@ -140,11 +141,6 @@ void invokeFinalize(Object o) throws Throwable; /** - * Returns the boot Layer - */ - Layer getBootLayer(); - - /** * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s) * associated with the given class loader, creating it if it doesn't already exist. */ @@ -185,4 +181,74 @@ * Invalidate package access cache */ void invalidatePackageAccessCache(); + + /** + * Defines a new module to the Java virtual machine. The module + * is defined to the given class loader. + * + * The URI is for information purposes only, it can be {@code null}. + */ + Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri); + + /** + * Defines the unnamed module for the given class loader. + */ + Module defineUnnamedModule(ClassLoader loader); + + /** + * Updates the readability so that module m1 reads m2. The new read edge + * does not result in a strong reference to m2 (m2 can be GC'ed). + * + * This method is the same as m1.addReads(m2) but without a permission check. + */ + void addReads(Module m1, Module m2); + + /** + * Updates module m to read all unnamed modules. + */ + void addReadsAllUnnamed(Module m); + + /** + * Updates module m1 to export a package to module m2. The export does + * not result in a strong reference to m2 (m2 can be GC'ed). + */ + void addExports(Module m1, String pkg, Module m2); + + /** + * Updates a module m to export a package to all unnamed modules. + */ + void addExportsToAllUnnamed(Module m, String pkg); + + /** + * 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 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); + + /** + * Returns the ServicesCatalog for the given Layer. + */ + ServicesCatalog getServicesCatalog(ModuleLayer 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<ModuleLayer> layers(ModuleLayer layer); + + /** + * Returns a stream of the layers that have modules defined to the + * given class loader. + */ + Stream<ModuleLayer> layers(ClassLoader loader); }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * 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 - * 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.misc; - -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; - -/** - * Provides access to non-public methods in java.lang.reflect.Module - */ - -public interface JavaLangReflectModuleAccess { - - /** - * Defines the unnamed module for the given class loader. - */ - Module defineUnnamedModule(ClassLoader loader); - - /** - * Defines a new module to the Java virtual machine. The module - * is defined to the given class loader. - * - * The URI is for information purposes only, it can be {@code null}. - */ - Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri); - - /** - * Updates the readability so that module m1 reads m2. The new read edge - * does not result in a strong reference to m2 (m2 can be GC'ed). - * - * This method is the same as m1.addReads(m2) but without a permission check. - */ - void addReads(Module m1, Module m2); - - /** - * Updates module m to read all unnamed modules. - */ - void addReadsAllUnnamed(Module m); - - /** - * Update module m to export a package to all modules. - */ - void addExports(Module m, String pn); - - /** - * Updates module m1 to export a package to module m2. The export does - * not result in a strong reference to m2 (m2 can be GC'ed). - */ - void addExports(Module m1, String pkg, Module m2); - - /** - * 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 modules. - */ - void addOpens(Module m, String pkg); - - /** - * 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 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); - - /** - * Returns the ServicesCatalog for the given Layer. - */ - 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<Layer> layers(Layer layer); - - /** - * Returns a stream of the layers that have modules defined to the - * given class loader. - */ - Stream<Layer> layers(ClassLoader loader); -} \ No newline at end of file
--- a/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package jdk.internal.misc; -import java.lang.reflect.Module; import java.util.Locale; import java.util.ResourceBundle;
--- a/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Fri Apr 07 08:05:54 2017 +0000 @@ -50,7 +50,6 @@ private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; private static JavaLangModuleAccess javaLangModuleAccess; - private static JavaLangReflectModuleAccess javaLangReflectModuleAccess; private static JavaLangInvokeAccess javaLangInvokeAccess; private static JavaLangRefAccess javaLangRefAccess; private static JavaIOAccess javaIOAccess; @@ -119,16 +118,6 @@ return javaLangModuleAccess; } - public static void setJavaLangReflectModuleAccess(JavaLangReflectModuleAccess jlrma) { - javaLangReflectModuleAccess = jlrma; - } - - public static JavaLangReflectModuleAccess getJavaLangReflectModuleAccess() { - if (javaLangReflectModuleAccess == null) - unsafe.ensureClassInitialized(java.lang.reflect.Module.class); - return javaLangReflectModuleAccess; - } - public static void setJavaLangRefAccess(JavaLangRefAccess jlra) { javaLangRefAccess = jlra; }
--- a/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,7 +27,6 @@ import java.io.PrintStream; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Module; import java.net.URL; import java.security.AccessController; import java.security.CodeSource;
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Fri Apr 07 08:05:54 2017 +0000 @@ -32,9 +32,6 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; -import java.lang.reflect.LayerInstantiationException; -import java.lang.reflect.Module; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; @@ -61,7 +58,7 @@ * resolving a set of module names specified via the launcher (or equivalent) * -m and --add-modules options. The modules are located on a module path that * is constructed from the upgrade module path, system modules, and application - * module path. The Configuration is instantiated as the boot Layer with each + * module path. The Configuration is instantiated as the boot layer with each * module in the the configuration defined to one of the built-in class loaders. */ @@ -106,11 +103,11 @@ } /** - * Initialize the module system, returning the boot Layer. + * Initialize the module system, returning the boot layer. * * @see java.lang.System#initPhase2() */ - public static Layer boot() { + public static ModuleLayer boot() { long t0 = System.nanoTime(); @@ -237,7 +234,6 @@ ModuleFinder f = finder; // observable modules systemModules.findAll() .stream() - .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref)) .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .filter(mn -> f.find(mn).isPresent()) // observable @@ -321,8 +317,7 @@ if (SystemModules.hasSplitPackages() || needPostResolutionChecks) { Map<String, String> packageToModule = new HashMap<>(); for (ResolvedModule resolvedModule : cf.modules()) { - ModuleDescriptor descriptor = - resolvedModule.reference().descriptor(); + ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); String name = descriptor.name(); for (String p : descriptor.packages()) { String other = packageToModule.putIfAbsent(p, name); @@ -338,7 +333,7 @@ long t4 = System.nanoTime(); // define modules to VM/runtime - Layer bootLayer = Layer.empty().defineModules(cf, clf); + ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf); PerfCounters.layerCreateTime.addElapsedTimeFrom(t4); @@ -476,7 +471,7 @@ * Process the --add-reads options to add any additional read edges that * are specified on the command-line. */ - private static void addExtraReads(Layer bootLayer) { + private static void addExtraReads(ModuleLayer bootLayer) { // decode the command line options Map<String, List<String>> map = decode("jdk.module.addreads."); @@ -514,7 +509,7 @@ * Process the --add-exports and --add-opens options to export/open * additional packages specified on the command-line. */ - private static void addExtraExportsAndOpens(Layer bootLayer) { + private static void addExtraExportsAndOpens(ModuleLayer bootLayer) { // --add-exports String prefix = "jdk.module.addexports."; Map<String, List<String>> extraExports = decode(prefix); @@ -548,7 +543,7 @@ } } - private static void addExtraExportsOrOpens(Layer bootLayer, + private static void addExtraExportsOrOpens(ModuleLayer bootLayer, Map<String, List<String>> map, boolean opens) {
--- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Fri Apr 07 08:05:54 2017 +0000 @@ -135,8 +135,9 @@ Path top = file; Files.find(top, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile())) - .filter(path -> !isAutomatic + .filter(path -> (!isAutomatic || path.toString().endsWith(".class")) + && !isHidden(path)) .map(path -> toPackageName(top, path)) .filter(Checks::isPackageName) .forEach(packages::add); @@ -177,11 +178,13 @@ ModuleTarget target = null; ModuleHashes recordedHashes = null; + ModuleHashes.HashSupplier hasher = null; ModuleResolution mres = null; if (mref instanceof ModuleReferenceImpl) { ModuleReferenceImpl impl = (ModuleReferenceImpl)mref; target = impl.moduleTarget(); recordedHashes = impl.recordedHashes(); + hasher = impl.hasher(); mres = impl.moduleResolution(); } @@ -191,7 +194,7 @@ this, target, recordedHashes, - null, + hasher, mres); } @@ -556,7 +559,7 @@ /** - * Derives a package name from a file path to a .class file. + * Derives a package name from the file path of an entry in an exploded patch */ private static String toPackageName(Path top, Path file) { Path entry = top.relativize(file); @@ -569,6 +572,17 @@ } /** + * Returns true if the given file exists and is a hidden file + */ + private boolean isHidden(Path file) { + try { + return Files.isHidden(file); + } catch (IOException ioe) { + return false; + } + } + + /** * Derives a package name from the name of an entry in a JAR file. */ private static String toPackageName(Path file, JarEntry entry) {
--- a/src/java.base/share/classes/jdk/internal/module/ModulePath.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/module/ModulePath.java Fri Apr 07 08:05:54 2017 +0000 @@ -547,7 +547,6 @@ */ 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("^\\."); @@ -558,9 +557,6 @@ * 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("."); @@ -630,7 +626,7 @@ private Set<String> explodedPackages(Path dir) { try { return Files.find(dir, Integer.MAX_VALUE, - ((path, attrs) -> attrs.isRegularFile())) + ((path, attrs) -> attrs.isRegularFile() && !isHidden(path))) .map(path -> dir.relativize(path)) .map(this::toPackageName) .flatMap(Optional::stream) @@ -726,6 +722,17 @@ } } + /** + * Returns true if the given file exists and is a hidden file + */ + private boolean isHidden(Path file) { + try { + return Files.isHidden(file); + } catch (IOException ioe) { + return false; + } + } + private static final PerfCounter scanTime = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime"); private static final PerfCounter moduleCount
--- a/src/java.base/share/classes/jdk/internal/module/Modules.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/module/Modules.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,15 +26,13 @@ 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 jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; -import jdk.internal.misc.JavaLangReflectModuleAccess; +import jdk.internal.misc.JavaLangAccess; import jdk.internal.misc.SharedSecrets; /** @@ -51,8 +49,7 @@ public class Modules { private Modules() { } - private static final JavaLangReflectModuleAccess JLRMA - = SharedSecrets.getJavaLangReflectModuleAccess(); + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); /** * Creates a new Module. The module has the given ModuleDescriptor and @@ -67,7 +64,7 @@ ModuleDescriptor descriptor, URI uri) { - return JLRMA.defineModule(loader, descriptor, uri); + return JLA.defineModule(loader, descriptor, uri); } /** @@ -75,23 +72,14 @@ * Same as m1.addReads(m2) but without a caller check. */ public static void addReads(Module m1, Module m2) { - JLRMA.addReads(m1, m2); + JLA.addReads(m1, m2); } /** * Update module m to read all unnamed modules. */ public static void addReadsAllUnnamed(Module m) { - JLRMA.addReadsAllUnnamed(m); - } - - /** - * Update module m to export a package to all modules. - * - * This method is for intended for use by tests only. - */ - public static void addExports(Module m, String pn) { - JLRMA.addExports(m, pn); + JLA.addReadsAllUnnamed(m); } /** @@ -99,23 +87,14 @@ * 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); + JLA.addExports(m1, pn, m2); } /** * Updates module m to export a package to all unnamed modules. */ public static void addExportsToAllUnnamed(Module m, String pn) { - JLRMA.addExportsToAllUnnamed(m, pn); - } - - /** - * Update module m to open a package to all modules. - * - * This method is for intended for use by tests only. - */ - public static void addOpens(Module m, String pn) { - JLRMA.addOpens(m, pn); + JLA.addExportsToAllUnnamed(m, pn); } /** @@ -123,14 +102,14 @@ * 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); + JLA.addOpens(m1, pn, m2); } /** * Updates module m to open a package to all unnamed modules. */ public static void addOpensToAllUnnamed(Module m, String pn) { - JLRMA.addOpensToAllUnnamed(m, pn); + JLA.addOpensToAllUnnamed(m, pn); } /** @@ -138,16 +117,16 @@ * Same as m2.addUses(service) but without a caller check. */ public static void addUses(Module m, Class<?> service) { - JLRMA.addUses(m, service); + JLA.addUses(m, service); } /** * Updates module m to provide a service */ public static void addProvides(Module m, Class<?> service, Class<?> impl) { - Layer layer = m.getLayer(); + ModuleLayer layer = m.getLayer(); - if (layer == null || layer == Layer.boot()) { + if (layer == null || layer == ModuleLayer.boot()) { // update ClassLoader catalog PrivilegedAction<ClassLoader> pa = m::getClassLoader; ClassLoader loader = AccessController.doPrivileged(pa); @@ -162,9 +141,7 @@ if (layer != null) { // update Layer catalog - SharedSecrets.getJavaLangReflectModuleAccess() - .getServicesCatalog(layer) - .addProvider(m, service, impl); + JLA.getServicesCatalog(layer).addProvider(m, service, impl); } }
--- a/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package jdk.internal.module; -import java.lang.reflect.Module; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Provides; import java.util.ArrayList;
--- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,7 +27,6 @@ import java.lang.reflect.Modifier; import static java.lang.reflect.Modifier.*; -import java.lang.reflect.Module; import java.util.Objects; import jdk.internal.reflect.Reflection;
--- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java Fri Apr 07 08:05:54 2017 +0000 @@ -50,10 +50,8 @@ 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; import java.lang.reflect.Modifier; -import java.lang.reflect.Module; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URI; @@ -467,7 +465,7 @@ String mn = s[0]; String pn = s[1]; - Layer.boot().findModule(mn).ifPresent(m -> { + ModuleLayer.boot().findModule(mn).ifPresent(m -> { if (m.getDescriptor().packages().contains(pn)) { if (open) { Modules.addOpensToAllUnnamed(m, pn); @@ -564,7 +562,7 @@ } // main module is in the boot layer - Layer layer = Layer.boot(); + ModuleLayer layer = ModuleLayer.boot(); Optional<Module> om = layer.findModule(mainModule); if (!om.isPresent()) { // should not happen @@ -854,7 +852,7 @@ private static void setFXLaunchParameters(String what, int mode) { // find the module with the FX launcher - Optional<Module> om = Layer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME); + Optional<Module> om = ModuleLayer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME); if (!om.isPresent()) { abort(null, "java.launcher.cls.error5"); } @@ -938,8 +936,7 @@ * Called by the launcher to list the observable modules. * If called without any sub-options then the output is a simple list of * the modules. If called with sub-options then the sub-options are the - * names of the modules to list (-listmods:java.base,java.desktop for - * example). + * names of the modules to list (e.g. --list-modules java.base,java.desktop) */ static void listModules(boolean printToStderr, String optionFlag) throws IOException, ClassNotFoundException @@ -947,89 +944,97 @@ initOutput(printToStderr); ModuleFinder finder = jdk.internal.module.ModuleBootstrap.finder(); - int colon = optionFlag.indexOf('='); if (colon == -1) { finder.findAll().stream() - .sorted(Comparator.comparing(ModuleReference::descriptor)) - .forEach(md -> { - ostream.println(midAndLocation(md.descriptor(), - md.location())); - }); + .sorted(Comparator.comparing(ModuleReference::descriptor)) + .forEach(mref -> describeModule(finder, mref, false)); } else { String[] names = optionFlag.substring(colon+1).split(","); for (String name: names) { ModuleReference mref = finder.find(name).orElse(null); if (mref == null) { - System.err.format("%s not observable!%n", name); + System.err.format("%s not found%n", name); continue; } - - ModuleDescriptor md = mref.descriptor(); - if (md.isOpen()) - ostream.print("open "); - if (md.isAutomatic()) - ostream.print("automatic "); - if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) - ostream.print("synthetic "); - if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) - ostream.print("mandated "); - ostream.println("module " + midAndLocation(md, mref.location())); - - // unqualified exports (sorted by package) - Set<Exports> 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); - } - for (String s : md.uses()) { - ostream.format(" uses %s%n", s); - } - - 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()); - } - } - - // 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<String> 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)); + describeModule(finder, mref, true); } } } + /** + * Describes the given module. + */ + static void describeModule(ModuleFinder finder, + ModuleReference mref, + boolean verbose) + { + ModuleDescriptor md = mref.descriptor(); + ostream.print("module " + midAndLocation(md, mref.location())); + if (md.isAutomatic()) + ostream.print(" automatic"); + ostream.println(); + + if (!verbose) + return; + + // unqualified exports (sorted by package) + Set<Exports> 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", d); + String suffix = finder.find(d.name()) + .map(ModuleReference::descriptor) + .map(any -> any.isAutomatic() ? " automatic" : "") + .orElse(" not found"); + ostream.println(suffix); + } + for (String s : md.uses()) { + ostream.format(" uses %s%n", s); + } + + 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()); + } + } + + // 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<String> 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 <T> String toString(Set<T> s) { return toStringStream(s).collect(Collectors.joining(" ")); }
--- a/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package sun.reflect.misc; -import java.lang.reflect.Module; import java.io.EOFException; import java.security.AllPermission; import java.security.AccessController;
--- a/src/java.base/share/native/libjava/Module.c Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.base/share/native/libjava/Module.c Fri Apr 07 08:05:54 2017 +0000 @@ -29,12 +29,12 @@ #include "jni_util.h" #include "jvm.h" -#include "java_lang_reflect_Module.h" +#include "java_lang_Module.h" /* * Gets the UTF-8 chars for the string and translates '.' to '/'. Does no * further validation, assumption being that both calling code in - * java.lang.reflect.Module and VM will do deeper validation. + * java.lang.Module and VM will do deeper validation. */ static char* GetInternalPackageName(JNIEnv *env, jstring pkg, char* buf, jsize buf_size) @@ -68,7 +68,7 @@ } JNIEXPORT void JNICALL -Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module, +Java_java_lang_Module_defineModule0(JNIEnv *env, jclass cls, jobject module, jboolean is_open, jstring version, jstring location, jobjectArray packages) { @@ -109,14 +109,14 @@ } JNIEXPORT void JNICALL -Java_java_lang_reflect_Module_addReads0(JNIEnv *env, jclass cls, jobject from, jobject to) +Java_java_lang_Module_addReads0(JNIEnv *env, jclass cls, jobject from, jobject to) { JVM_AddReadsModule(env, from, to); } JNIEXPORT void JNICALL -Java_java_lang_reflect_Module_addExports0(JNIEnv *env, jclass cls, jobject from, - jstring pkg, jobject to) +Java_java_lang_Module_addExports0(JNIEnv *env, jclass cls, jobject from, + jstring pkg, jobject to) { char buf[128]; char* pkg_name; @@ -136,8 +136,8 @@ } JNIEXPORT void JNICALL -Java_java_lang_reflect_Module_addExportsToAll0(JNIEnv *env, jclass cls, jobject from, - jstring pkg) +Java_java_lang_Module_addExportsToAll0(JNIEnv *env, jclass cls, jobject from, + jstring pkg) { char buf[128]; char* pkg_name; @@ -157,8 +157,8 @@ } JNIEXPORT void JNICALL -Java_java_lang_reflect_Module_addExportsToAllUnnamed0(JNIEnv *env, jclass cls, - jobject from, jstring pkg) +Java_java_lang_Module_addExportsToAllUnnamed0(JNIEnv *env, jclass cls, + jobject from, jstring pkg) { char buf[128]; char* pkg_name; @@ -178,7 +178,7 @@ } JNIEXPORT void JNICALL -Java_java_lang_reflect_Module_addPackage0(JNIEnv *env, jclass cls, jobject m, jstring pkg) +Java_java_lang_Module_addPackage0(JNIEnv *env, jclass cls, jobject m, jstring pkg) { char buf[128]; char* pkg_name;
--- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import org.w3c.dom.Node; import java.lang.reflect.Method; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction;
--- a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays;
--- a/src/java.desktop/share/classes/javax/swing/text/PlainView.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.desktop/share/classes/javax/swing/text/PlainView.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,7 +31,6 @@ import java.security.PrivilegedAction; import java.util.Objects; import javax.swing.event.*; -import java.lang.reflect.Module; import java.lang.ref.SoftReference; import java.util.HashMap;
--- a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package java.lang.instrument; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.ProtectionDomain;
--- a/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package java.lang.instrument; -import java.lang.reflect.Module; import java.security.ProtectionDomain; import java.util.List; import java.util.Map; @@ -346,7 +345,7 @@ /** - * Determines whether a class is modifiable by + * Tests whether a class is modifiable by * {@linkplain #retransformClasses retransformation} * or {@linkplain #redefineClasses redefinition}. * If a class is modifiable then this method returns <code>true</code>. @@ -711,8 +710,11 @@ * {@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 UnmodifiableModuleException if the module cannot be modified * @throws NullPointerException if any of the arguments are {@code null} or * any of the Sets or Maps contains a {@code null} key or value + * + * @see #isModifiableModule(Module) * @since 9 * @spec JPMS */ @@ -722,4 +724,19 @@ Map<String, Set<Module>> extraOpens, Set<Class<?>> extraUses, Map<Class<?>, List<Class<?>>> extraProvides); + + /** + * Tests whether a module can be modified with {@link #redefineModule + * redefineModule}. If a module is modifiable then this method returns + * {@code true}. If a module is not modifiable then this method returns + * {@code false}. + * + * @param module the module to test if it can be modified + * @return {@code true} if the module is modifiable, otherwise {@code false} + * @throws NullPointerException if the module is {@code null} + * + * @since 9 + * @spec JPMS + */ + boolean isModifiableModule(Module module); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.instrument/share/classes/java/lang/instrument/UnmodifiableModuleException.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.instrument; + +/** + * Thrown to indicate that a module cannot be modified. + * + * @see Instrumentation#redefineModule + * @since 9 + * @spec JPMS + */ + +public class UnmodifiableModuleException extends RuntimeException { + private static final long serialVersionUID = 6912511912351080644L; + + /** + * Constructs an {@code UnmodifiableModuleException} with no + * detail message. + */ + public UnmodifiableModuleException() { + super(); + } + + /** + * Constructs an {@code UnmodifiableModuleException} with the + * specified detail message. + * + * @param msg the detail message. + */ + public UnmodifiableModuleException(String msg) { + super(msg); + } +}
--- a/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,11 +23,10 @@ * questions. */ - package sun.instrument; +import java.lang.instrument.UnmodifiableModuleException; 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; @@ -132,6 +131,13 @@ return isModifiableClass0(mNativeAgent, theClass); } + public boolean isModifiableModule(Module module) { + if (module == null) { + throw new NullPointerException("'module' is null"); + } + return true; + } + public boolean isRetransformClassesSupported() { // ask lazily since there is some overhead @@ -243,6 +249,9 @@ if (!module.isNamed()) return; + if (!isModifiableModule(module)) + throw new UnmodifiableModuleException(module.getName()); + // copy and check reads extraReads = new HashSet<>(extraReads); if (extraReads.contains(null)) @@ -312,7 +321,7 @@ return Collections.emptyMap(); Map<String, Set<Module>> result = new HashMap<>(); - Set<String> packages = Set.of(module.getPackages()); + Set<String> packages = module.getPackages(); for (Map.Entry<String, Set<Module>> e : map.entrySet()) { String pkg = e.getKey(); if (pkg == null)
--- a/src/java.instrument/share/classes/sun/instrument/TransformerManager.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.instrument/share/classes/sun/instrument/TransformerManager.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,10 +25,8 @@ package sun.instrument; - import java.lang.instrument.Instrumentation; import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.Module; import java.security.ProtectionDomain; /*
--- a/src/java.instrument/share/native/libinstrument/JPLISAgent.h Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.h Fri Apr 07 08:05:54 2017 +0000 @@ -66,7 +66,7 @@ #define JPLIS_INSTRUMENTIMPL_AGENTMAININVOKER_METHODSIGNATURE "(Ljava/lang/String;Ljava/lang/String;)V" #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODNAME "transform" #define JPLIS_INSTRUMENTIMPL_TRANSFORM_METHODSIGNATURE \ - "(Ljava/lang/reflect/Module;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B" + "(Ljava/lang/Module;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/Class;Ljava/security/ProtectionDomain;[BZ)[B" /*
--- a/src/java.logging/share/classes/java/util/logging/Level.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.logging/share/classes/java/util/logging/Level.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,10 +24,10 @@ */ package java.util.logging; + import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList;
--- a/src/java.logging/share/classes/java/util/logging/LogManager.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.logging/share/classes/java/util/logging/LogManager.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ * questions. */ - package java.util.logging; import java.io.*; @@ -43,7 +42,6 @@ import jdk.internal.misc.JavaAWTAccess; import jdk.internal.misc.SharedSecrets; import sun.util.logging.internal.LoggingProviderImpl; -import java.lang.reflect.Module; import static jdk.internal.logger.DefaultLoggerFinder.isSystem; /**
--- a/src/java.logging/share/classes/java/util/logging/Logger.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.logging/share/classes/java/util/logging/Logger.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,11 +23,9 @@ * questions. */ - package java.util.logging; import java.lang.ref.WeakReference; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList;
--- a/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.logging/share/classes/sun/util/logging/internal/LoggingProviderImpl.java Fri Apr 07 08:05:54 2017 +0000 @@ -32,7 +32,6 @@ import java.util.function.Supplier; import java.lang.System.LoggerFinder; import java.lang.System.Logger; -import java.lang.reflect.Module; import java.util.Objects; import java.util.logging.LogManager; import jdk.internal.logger.DefaultLoggerFinder;
--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java Fri Apr 07 08:05:54 2017 +0000 @@ -43,7 +43,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Module; import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.rmi.MarshalledObject;
--- a/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import com.sun.jmx.mbeanserver.Util; import java.io.IOException; import java.io.UncheckedIOException; -import java.lang.reflect.Module; import java.net.MalformedURLException; import java.util.Collections; import java.util.HashMap;
--- a/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.management/share/classes/sun/management/ManagementFactoryHelper.java Fri Apr 07 08:05:54 2017 +0000 @@ -45,7 +45,6 @@ import java.util.ArrayList; import java.util.List; -import java.lang.reflect.Module; import java.lang.reflect.UndeclaredThrowableException; import java.security.PrivilegedAction; import java.util.Collections; @@ -181,8 +180,7 @@ return AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Class<?> run() { - Optional<Module> logging = java.lang.reflect.Layer.boot() - .findModule("java.logging"); + Optional<Module> logging = ModuleLayer.boot().findModule("java.logging"); if (logging.isPresent()) { return Class.forName(logging.get(), className); }
--- a/src/java.naming/share/classes/com/sun/naming/internal/VersionHelper.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.naming/share/classes/com/sun/naming/internal/VersionHelper.java Fri Apr 07 08:05:54 2017 +0000 @@ -176,7 +176,7 @@ InputStream getResourceAsStream(Class<?> c, String name) { PrivilegedAction<InputStream> act = () -> { try { - java.lang.reflect.Module m = c.getModule(); + Module m = c.getModule(); return c.getModule().getResourceAsStream(resolveName(c,name)); } catch (IOException x) { return null;
--- a/src/java.rmi/share/classes/java/rmi/activation/ActivationInstantiator.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.rmi/share/classes/java/rmi/activation/ActivationInstantiator.java Fri Apr 07 08:05:54 2017 +0000 @@ -67,11 +67,11 @@ * * <ul><li>The class to be activated and the special activation constructor are both public, * and the class resides in a package that is - * {@linkplain java.lang.reflect.Module#isExported(String,java.lang.reflect.Module) exported} + * {@linkplain Module#isExported(String,Module) exported} * to at least the {@code java.rmi} module; or * * <li>The class to be activated resides in a package that is - * {@linkplain java.lang.reflect.Module#isOpen(String,java.lang.reflect.Module) open} + * {@linkplain Module#isOpen(String,Module) open} * to at least the {@code java.rmi} module. * </ul> *
--- a/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java Fri Apr 07 08:05:54 2017 +0000 @@ -135,9 +135,9 @@ * remote object's class. * * <li>Each remote interface must either be public and reside in a package that is - * {@linkplain java.lang.reflect.Module#isExported(String,java.lang.reflect.Module) exported} + * {@linkplain Module#isExported(String,Module) exported} * to at least the {@code java.rmi} module, or it must reside in a package that is - * {@linkplain java.lang.reflect.Module#isOpen(String,java.lang.reflect.Module) open} + * {@linkplain Module#isOpen(String,Module) open} * to at least the {@code java.rmi} module. * * <li>The proxy's invocation handler is a {@link
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyStore.java Fri Apr 07 08:05:54 2017 +0000 @@ -1022,7 +1022,7 @@ ("trusted certificates may only be set by " + "token initialization application")); } - Module module = token.provider.nssModule; + Secmod.Module module = token.provider.nssModule; if ((module.type != ModuleType.KEYSTORE) && (module.type != ModuleType.FIPS)) { // XXX allow TRUSTANCHOR module throw new KeyStoreException("Trusted certificates can only be "
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java Fri Apr 07 08:05:54 2017 +0000 @@ -77,7 +77,7 @@ final boolean removable; - final Module nssModule; + final Secmod.Module nssModule; final boolean nssUseSecmodTrust; @@ -148,7 +148,7 @@ boolean useSecmod = config.getNssUseSecmod(); boolean nssUseSecmodTrust = config.getNssUseSecmodTrust(); - Module nssModule = null; + Secmod.Module nssModule = null; // // Initialization via Secmod. The way this works is as follows: @@ -217,7 +217,7 @@ // XXX which exception to throw throw new ProviderException("Could not initialize NSS", e); } - List<Module> modules = secmod.getModules(); + List<Secmod.Module> modules = secmod.getModules(); if (config.getShowInfo()) { System.out.println("NSS modules: " + modules); } @@ -258,7 +258,7 @@ ("Invalid external module: " + moduleName); } int k = 0; - for (Module module : modules) { + for (Secmod.Module module : modules) { if (module.getType() == ModuleType.EXTERNAL) { if (++k == moduleIndex) { nssModule = module;
--- a/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ package sun.tools.common; -import java.lang.reflect.Module; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection;
--- a/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c Fri Apr 07 08:05:54 2017 +0000 @@ -29,8 +29,8 @@ #include "ModuleReferenceImpl.h" -static jclass jlrM(JNIEnv *env) { - return findClass(env, "Ljava/lang/reflect/Module;"); +static jclass jlM(JNIEnv *env) { + return findClass(env, "Ljava/lang/Module;"); } static jboolean @@ -43,7 +43,7 @@ jobject module; if (method == NULL) { - method = getMethod(env, jlrM(env), "getName", "()Ljava/lang/String;"); + method = getMethod(env, jlM(env), "getName", "()Ljava/lang/String;"); } module = inStream_readModuleRef(getEnv(), in); if (inStream_error(in)) { @@ -71,7 +71,7 @@ jobject module; if (method == NULL) { - method = getMethod(env, jlrM(env), "getClassLoader", "()Ljava/lang/ClassLoader;"); + method = getMethod(env, jlM(env), "getClassLoader", "()Ljava/lang/ClassLoader;"); } module = inStream_readModuleRef(env, in); if (inStream_error(in)) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ import java.lang.module.Configuration; import java.lang.module.ModuleFinder; -import java.lang.reflect.Layer; import java.nio.ByteOrder; import java.nio.file.Path; import java.util.ArrayList; @@ -55,10 +54,10 @@ * @return A new plugin or null if plugin is unknown. */ public static Plugin newPlugin(String name, - Map<String, String> configuration, Layer pluginsLayer) { + Map<String, String> configuration, ModuleLayer pluginsLayer) { Objects.requireNonNull(name); Objects.requireNonNull(configuration); - pluginsLayer = pluginsLayer == null ? Layer.boot() : pluginsLayer; + pluginsLayer = pluginsLayer == null ? ModuleLayer.boot() : pluginsLayer; return PluginRepository.newPlugin(configuration, name, pluginsLayer); } @@ -330,7 +329,7 @@ private PluginsConfiguration addAutoEnabledPlugins(PluginsConfiguration pluginsConfig) { List<Plugin> plugins = new ArrayList<>(pluginsConfig.getPlugins()); - List<Plugin> bootPlugins = PluginRepository.getPlugins(Layer.boot()); + List<Plugin> bootPlugins = PluginRepository.getPlugins(ModuleLayer.boot()); for (Plugin bp : bootPlugins) { if (Utils.isAutoEnabled(bp)) { try {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ */ package jdk.tools.jlink.internal; -import java.lang.reflect.Layer; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -56,7 +55,7 @@ * @return A provider or null if not found. */ public static Plugin getPlugin(String name, - Layer pluginsLayer) { + ModuleLayer pluginsLayer) { return getPlugin(Plugin.class, name, pluginsLayer); } @@ -69,7 +68,7 @@ * @return A plugin or null if no plugin found. */ public static Plugin newPlugin(Map<String, String> config, String name, - Layer pluginsLayer) { + ModuleLayer pluginsLayer) { Objects.requireNonNull(name); Objects.requireNonNull(pluginsLayer); Plugin plugin = getPlugin(name, pluginsLayer); @@ -107,12 +106,12 @@ registeredPlugins.remove(name); } - public static List<Plugin> getPlugins(Layer pluginsLayer) { + public static List<Plugin> getPlugins(ModuleLayer pluginsLayer) { return getPlugins(Plugin.class, pluginsLayer); } private static <T extends Plugin> T getPlugin(Class<T> clazz, String name, - Layer pluginsLayer) { + ModuleLayer pluginsLayer) { Objects.requireNonNull(name); Objects.requireNonNull(pluginsLayer); @SuppressWarnings("unchecked") @@ -136,7 +135,7 @@ * @param pluginsLayer * @return The list of plugins. */ - private static <T extends Plugin> List<T> getPlugins(Class<T> clazz, Layer pluginsLayer) { + private static <T extends Plugin> List<T> getPlugins(Class<T> clazz, ModuleLayer pluginsLayer) { Objects.requireNonNull(pluginsLayer); List<T> factories = new ArrayList<>(); try {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Fri Apr 07 08:05:54 2017 +0000 @@ -29,7 +29,6 @@ import java.io.PrintWriter; 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; @@ -211,7 +210,7 @@ private final class PluginsHelper { - private Layer pluginsLayer = Layer.boot(); + private ModuleLayer pluginsLayer = ModuleLayer.boot(); private final List<Plugin> plugins; private String lastSorter; private boolean listPlugins; @@ -655,7 +654,7 @@ return defaults; } - public Layer getPluginsLayer() { + public ModuleLayer getPluginsLayer() { return pluginOptions.pluginsLayer; } } @@ -725,18 +724,18 @@ return System.getProperty("java.version"); } - static Layer createPluginsLayer(List<Path> paths) { + static ModuleLayer createPluginsLayer(List<Path> paths) { Path[] dirs = paths.toArray(new Path[0]); ModuleFinder finder = ModulePath.of(Runtime.version(), true, dirs); - Configuration bootConfiguration = Layer.boot().configuration(); + Configuration bootConfiguration = ModuleLayer.boot().configuration(); try { Configuration cf = bootConfiguration .resolveAndBind(ModuleFinder.of(), finder, Collections.emptySet()); ClassLoader scl = ClassLoader.getSystemClassLoader(); - return Layer.boot().defineModulesWithOneLoader(cf, scl); + return ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); } catch (Exception ex) { // Malformed plugin modules (e.g.: same package in multiple modules). throw new PluginException("Invalid modules in the plugins path: " + ex);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Utils.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ */ package jdk.tools.jlink.internal; -import java.lang.reflect.Module; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems;
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java Thu Apr 06 17:01:03 2017 +0000 +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,6 +27,7 @@ import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; +import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor; import java.util.EnumSet; @@ -43,8 +44,6 @@ import jdk.tools.jlink.plugin.ResourcePoolBuilder; import jdk.tools.jlink.plugin.ResourcePoolEntry; import jdk.tools.jlink.plugin.ResourcePoolModule; -import jdk.tools.jlink.plugin.Plugin.Category; -import jdk.tools.jlink.plugin.Plugin.State; import jdk.tools.jlink.plugin.Plugin; /** @@ -101,9 +100,9 @@ // --release-info add:build_type=fastdebug,source=openjdk,java_version=9 // and put whatever value that was passed in command line. - config.keySet().stream(). - filter(s -> !NAME.equals(s)). - forEach(s -> release.put(s, config.get(s))); + config.keySet().stream() + .filter(s -> !NAME.equals(s)) + .forEach(s -> release.put(s, config.get(s))); } break; @@ -148,8 +147,8 @@ // put topological sorted module names separated by space release.put("MODULES", new ModuleSorter(in.moduleView()) - .sorted().map(ResourcePoolModule::name) - .collect(Collectors.joining(" ", "\"", "\""))); + .sorted().map(ResourcePoolModule::name) + .collect(Collectors.joining(" ", "\"", "\""))); // create a TOP level ResourcePoolEntry for "release" file. out.add(ResourcePoolEntry.create("/java.base/release", @@ -160,11 +159,11 @@ // Parse version string and return a string that includes only version part // leaving "pre", "build" information. See also: java.lang.Runtime.Version. private static String parseVersion(String str) { - return Runtime.Version.parse(str). - version(). - stream(). - map(Object::toString). - collect(Collectors.joining(".")); + return Runtime.Version.parse(str) + .version() + .stream() + .map(Object::toString) + .collect(Collectors.joining(".")); } private static String quote(String str) { @@ -172,14 +171,12 @@ } private byte[] releaseFileContent() { - Properties props = new Properties(); - props.putAll(release); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { - props.store(baos, ""); - return baos.toByteArray(); - } catch (IOException ex) { - throw new UncheckedIOException(ex); + try (PrintWriter pw = new PrintWriter(baos)) { + release.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> pw.format("%s=%s%n", e.getKey(), e.getValue())); } + return baos.toByteArray(); } }
--- a/test/TEST.ROOT Thu Apr 06 17:01:03 2017 +0000 +++ b/test/TEST.ROOT Fri Apr 07 08:05:54 2017 +0000 @@ -26,8 +26,8 @@ # Allow querying of various System properties in @requires clauses requires.properties=sun.arch.data.model java.runtime.name -# Tests using jtreg 4.2 b05 features -requiredVersion=4.2 b05 +# Tests using jtreg 4.2 b07 features +requiredVersion=4.2 b07 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them
--- a/test/java/awt/TrayIcon/SystemTrayIconHelper.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/awt/TrayIcon/SystemTrayIconHelper.java Fri Apr 07 08:05:54 2017 +0000 @@ -81,7 +81,7 @@ try { // sun.lwawt.macosx.CTrayIcon Field f_peer = getField( java.awt.TrayIcon.class, "peer"); - Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class); + Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.Module.class); m_addExports.invoke(null, "sun.lwawt.macosx", robot.getClass().getModule()); @@ -105,7 +105,7 @@ } else { try { // sun.awt.X11.XTrayIconPeer - Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class); + Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.Module.class); m_addExports.invoke(null, "sun.awt.X11", robot.getClass().getModule()); Field f_peer = getField(java.awt.TrayIcon.class, "peer");
--- a/test/java/awt/patchlib/java.desktop/java/awt/Helper.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/awt/patchlib/java.desktop/java/awt/Helper.java Fri Apr 07 08:05:54 2017 +0000 @@ -22,7 +22,6 @@ */ package java.awt; -import java.lang.reflect.Module; public class Helper { private Helper() { } public static void addExports(String pn, Module target) {
--- a/test/java/awt/regtesthelpers/Util.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/awt/regtesthelpers/Util.java Fri Apr 07 08:05:54 2017 +0000 @@ -445,7 +445,7 @@ try { final Class _clazz = clazz; - Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class); + Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.Module.class); // No MToolkit anymore: nothing to do about it. // We may be called from non-X11 system, and this permission cannot be delegated to a test. m_addExports.invoke(null, "sun.awt.X11", Util.class.getModule());
--- a/test/java/lang/Class/GetModuleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/GetModuleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,7 +31,6 @@ */ import java.awt.Component; -import java.lang.reflect.Module; import jdk.internal.org.objectweb.asm.ClassWriter; import static jdk.internal.org.objectweb.asm.Opcodes.*;
--- a/test/java/lang/Class/forName/modules/TestLayer.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/forName/modules/TestLayer.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,9 +23,7 @@ import java.lang.module.Configuration; import java.lang.module.ModuleFinder; -import java.lang.reflect.Layer; import java.lang.reflect.Method; -import java.lang.reflect.Module; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; @@ -45,13 +43,13 @@ ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); Configuration cf = parent.resolveAndBind(ModuleFinder.of(), finder, modules); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); Module m1 = layer.findModule("m1").get(); Module m2 = layer.findModule("m2").get();
--- a/test/java/lang/Class/forName/modules/TestMain.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/forName/modules/TestMain.java Fri Apr 07 08:05:54 2017 +0000 @@ -21,13 +21,11 @@ * questions. */ -import java.lang.reflect.Layer; import java.lang.reflect.Method; -import java.lang.reflect.Module; public class TestMain { public static void main(String[] args) throws Exception { - Layer boot = Layer.boot(); + ModuleLayer boot = ModuleLayer.boot(); Module m1 = boot.findModule("m1").get(); Module m2 = boot.findModule("m2").get();
--- a/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,12 +23,9 @@ package p2.test; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; - public class Main { public static void main(String... args) throws Exception { - Layer boot = Layer.boot(); + ModuleLayer boot = ModuleLayer.boot(); Module m1 = boot.findModule("m1").get(); Module m2 = Main.class.getModule();
--- a/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,8 +26,6 @@ import java.io.FilePermission; import java.lang.module.Configuration; import java.lang.module.ModuleFinder; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.nio.file.Path; import java.nio.file.Paths; import java.security.AccessControlException; @@ -47,7 +45,7 @@ ModuleFinder finder = ModuleFinder.of(Paths.get("mods1"), Paths.get("mods2")); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration parent = bootLayer.configuration(); Configuration cf = parent.resolveAndBind(finder, @@ -55,7 +53,7 @@ Set.of("m1", "m2")); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl); + ModuleLayer layer = bootLayer.defineModulesWithManyLoaders(cf, scl); if (sm != null) { System.setSecurityManager(sm);
--- a/test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,8 +23,6 @@ package p3; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.security.AccessControlException; import java.security.Permission; @@ -37,7 +35,7 @@ private static final Permission GET_CLASSLOADER_PERMISSION = new RuntimePermission("getClassLoader"); public static void main(String[] args) throws Exception { - Layer boot = Layer.boot(); + ModuleLayer boot = ModuleLayer.boot(); System.setSecurityManager(new SecurityManager()); Module m1 = boot.findModule("m1").get();
--- a/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,10 +26,8 @@ import java.io.UncheckedIOException; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; -import java.lang.reflect.Module; import java.lang.reflect.Modifier; import java.lang.reflect.InaccessibleObjectException; -import java.lang.reflect.Layer; import java.lang.reflect.ReflectPermission; import java.net.URI; import java.nio.file.FileSystem; @@ -269,7 +267,7 @@ try { return Files.walk(root) .filter(p -> p.getNameCount() > 2) - .filter(p -> Layer.boot().findModule(p.getName(1).toString()).isPresent()) + .filter(p -> ModuleLayer.boot().findModule(p.getName(1).toString()).isPresent()) .map(p -> p.subpath(2, p.getNameCount())) .map(p -> p.toString()) .filter(s -> s.endsWith(".class") && !s.endsWith("module-info.class"))
--- a/test/java/lang/Class/getResource/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/Class/getResource/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ import java.lang.module.Configuration; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -256,7 +255,7 @@ * Returns the directory for the given module (by name). */ static Path directoryFor(String name) { - Configuration cf = Layer.boot().configuration(); + Configuration cf = ModuleLayer.boot().configuration(); ResolvedModule resolvedModule = cf.findModule(name).orElse(null); if (resolvedModule == null) throw new RuntimeException("not found: " + name);
--- a/test/java/lang/ClassLoader/getResource/automaticmodules/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/ClassLoader/getResource/automaticmodules/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; import java.net.URL; import java.util.Enumeration; @@ -74,7 +73,7 @@ public static void main(String[] args) throws Exception { String mn = args[0]; - ModuleReference mref = Layer.boot() + ModuleReference mref = ModuleLayer.boot() .configuration() .findModule(mn) .map(ResolvedModule::reference)
--- a/test/java/lang/ClassLoader/getResource/modules/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/ClassLoader/getResource/modules/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ 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; @@ -309,7 +308,7 @@ * Returns the directory for the given module (by name). */ static Path directoryFor(String mn) { - Configuration cf = Layer.boot().configuration(); + Configuration cf = ModuleLayer.boot().configuration(); ResolvedModule resolvedModule = cf.findModule(mn).orElse(null); if (resolvedModule == null) throw new RuntimeException("not found: " + mn);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/BasicLayerTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,1213 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 java.base/jdk.internal.misc + * @build BasicLayerTest ModuleUtils + * @compile layertest/Test.java + * @run testng BasicLayerTest + * @summary Basic tests for java.lang.ModuleLayer + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import jdk.internal.misc.SharedSecrets; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class BasicLayerTest { + + /** + * Creates a "non-strict" builder for building a module. This allows the + * test the create ModuleDescriptor objects that do not require java.base. + */ + private static ModuleDescriptor.Builder newBuilder(String mn) { + return SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder(mn, false, Set.of()); + } + + /** + * Exercise ModuleLayer.empty() + */ + public void testEmpty() { + ModuleLayer emptyLayer = ModuleLayer.empty(); + + assertTrue(emptyLayer.parents().isEmpty()); + + assertTrue(emptyLayer.configuration() == Configuration.empty()); + + assertTrue(emptyLayer.modules().isEmpty()); + + assertFalse(emptyLayer.findModule("java.base").isPresent()); + + try { + emptyLayer.findLoader("java.base"); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + + /** + * Exercise ModuleLayer.boot() + */ + public void testBoot() { + ModuleLayer bootLayer = ModuleLayer.boot(); + + // configuration + Configuration cf = bootLayer.configuration(); + assertTrue(cf.findModule("java.base").get() + .reference() + .descriptor() + .exports() + .stream().anyMatch(e -> (e.source().equals("java.lang") + && !e.isQualified()))); + + // modules + Set<Module> modules = bootLayer.modules(); + assertTrue(modules.contains(Object.class.getModule())); + int count = (int) modules.stream().map(Module::getName).count(); + assertEquals(count, modules.size()); // module names are unique + + // findModule + Module base = Object.class.getModule(); + assertTrue(bootLayer.findModule("java.base").get() == base); + assertTrue(base.getLayer() == bootLayer); + + // findLoader + assertTrue(bootLayer.findLoader("java.base") == null); + + // parents + assertTrue(bootLayer.parents().size() == 1); + assertTrue(bootLayer.parents().get(0) == ModuleLayer.empty()); + } + + + /** + * Exercise defineModules, created with empty layer as parent + */ + public void testLayerOnEmpty() { + ModuleDescriptor descriptor1 = newBuilder("m1") + .requires("m2") + .exports("p1") + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires("m3") + .build(); + + ModuleDescriptor descriptor3 = newBuilder("m3") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + Configuration cf = resolve(finder, "m1"); + + // map each module to its own class loader for this test + ClassLoader loader1 = new ClassLoader() { }; + ClassLoader loader2 = new ClassLoader() { }; + ClassLoader loader3 = new ClassLoader() { }; + Map<String, ClassLoader> map = new HashMap<>(); + map.put("m1", loader1); + map.put("m2", loader2); + map.put("m3", loader3); + + ModuleLayer layer = ModuleLayer.empty().defineModules(cf, map::get); + + // configuration + assertTrue(layer.configuration() == cf); + assertTrue(layer.configuration().modules().size() == 3); + + // modules + Set<Module> modules = layer.modules(); + assertTrue(modules.size() == 3); + Set<String> names = modules.stream() + .map(Module::getName) + .collect(Collectors.toSet()); + assertTrue(names.contains("m1")); + assertTrue(names.contains("m2")); + assertTrue(names.contains("m3")); + + // findModule + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + Module m3 = layer.findModule("m3").get(); + assertEquals(m1.getName(), "m1"); + assertEquals(m2.getName(), "m2"); + assertEquals(m3.getName(), "m3"); + assertTrue(m1.getDescriptor() == descriptor1); + assertTrue(m2.getDescriptor() == descriptor2); + assertTrue(m3.getDescriptor() == descriptor3); + assertTrue(m1.getLayer() == layer); + assertTrue(m2.getLayer() == layer); + assertTrue(m3.getLayer() == layer); + assertTrue(modules.contains(m1)); + assertTrue(modules.contains(m2)); + assertTrue(modules.contains(m3)); + assertFalse(layer.findModule("godot").isPresent()); + + // findLoader + assertTrue(layer.findLoader("m1") == loader1); + assertTrue(layer.findLoader("m2") == loader2); + assertTrue(layer.findLoader("m3") == loader3); + try { + ClassLoader loader = layer.findLoader("godot"); + assertTrue(false); + } catch (IllegalArgumentException ignore) { } + + // parents + assertTrue(layer.parents().size() == 1); + assertTrue(layer.parents().get(0) == ModuleLayer.empty()); + } + + + /** + * Exercise defineModules, created with boot layer as parent + */ + public void testLayerOnBoot() { + ModuleDescriptor descriptor1 = newBuilder("m1") + .requires("m2") + .requires("java.base") + .exports("p1") + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires("java.base") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + + ClassLoader loader = new ClassLoader() { }; + + ModuleLayer layer = ModuleLayer.boot().defineModules(cf, mn -> loader); + + // configuration + assertTrue(layer.configuration() == cf); + assertTrue(layer.configuration().modules().size() == 2); + + // modules + Set<Module> modules = layer.modules(); + assertTrue(modules.size() == 2); + Set<String> names = modules.stream() + .map(Module::getName) + .collect(Collectors.toSet()); + assertTrue(names.contains("m1")); + assertTrue(names.contains("m2")); + + // findModule + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + assertEquals(m1.getName(), "m1"); + assertEquals(m2.getName(), "m2"); + assertTrue(m1.getDescriptor() == descriptor1); + assertTrue(m2.getDescriptor() == descriptor2); + assertTrue(m1.getLayer() == layer); + assertTrue(m2.getLayer() == layer); + assertTrue(modules.contains(m1)); + assertTrue(modules.contains(m2)); + assertTrue(layer.findModule("java.base").get() == Object.class.getModule()); + assertFalse(layer.findModule("godot").isPresent()); + + // findLoader + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("m2") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // parents + assertTrue(layer.parents().size() == 1); + assertTrue(layer.parents().get(0) == ModuleLayer.boot()); + } + + + /** + * Exercise defineModules with a configuration of two modules that + * have the same module-private package. + */ + public void testPackageContainedInSelfAndOther() { + ModuleDescriptor descriptor1 = newBuilder("m1") + .requires("m2") + .packages(Set.of("p")) + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .packages(Set.of("p")) + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolve(finder, "m1"); + assertTrue(cf.modules().size() == 2); + + // one loader per module, should be okay + ModuleLayer.empty().defineModules(cf, mn -> new ClassLoader() { }); + + // same class loader + try { + ClassLoader loader = new ClassLoader() { }; + ModuleLayer.empty().defineModules(cf, mn -> loader); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + } + + + /** + * Exercise defineModules with a configuration that is a partitioned + * graph. The same package is exported in both partitions. + */ + public void testSameExportInPartitionedGraph() { + + // m1 reads m2, m2 exports p to m1 + ModuleDescriptor descriptor1 = newBuilder("m1") + .requires("m2") + .build(); + ModuleDescriptor descriptor2 = newBuilder("m2") + .exports("p", Set.of("m1")) + .build(); + + // m3 reads m4, m4 exports p to m3 + ModuleDescriptor descriptor3 = newBuilder("m3") + .requires("m4") + .build(); + ModuleDescriptor descriptor4 = newBuilder("m4") + .exports("p", Set.of("m3")) + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, + descriptor2, + descriptor3, + descriptor4); + + Configuration cf = resolve(finder, "m1", "m3"); + assertTrue(cf.modules().size() == 4); + + // one loader per module + ModuleLayer.empty().defineModules(cf, mn -> new ClassLoader() { }); + + // m1 & m2 in one loader, m3 & m4 in another loader + ClassLoader loader1 = new ClassLoader() { }; + ClassLoader loader2 = new ClassLoader() { }; + Map<String, ClassLoader> map = new HashMap<>(); + map.put("m1", loader1); + map.put("m2", loader1); + map.put("m3", loader2); + map.put("m4", loader2); + ModuleLayer.empty().defineModules(cf, map::get); + + // same loader + try { + ClassLoader loader = new ClassLoader() { }; + ModuleLayer.empty().defineModules(cf, mn -> loader); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + } + + + /** + * Exercise 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 testContainsSamePackageAsBootLayer() { + + // check assumption that java.base contains sun.launcher + ModuleDescriptor base = Object.class.getModule().getDescriptor(); + assertTrue(base.packages().contains("sun.launcher")); + + ModuleDescriptor descriptor = newBuilder("m1") + .requires("java.base") + .packages(Set.of("sun.launcher")) + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); + assertTrue(cf.modules().size() == 1); + + ClassLoader loader = new ClassLoader() { }; + ModuleLayer layer = ModuleLayer.boot().defineModules(cf, mn -> loader); + assertTrue(layer.modules().size() == 1); + } + + + /** + * Test layers with implied readability. + * + * The test consists of three configurations: + * - Configuration/layer1: m1, m2 requires transitive m1 + * - Configuration/layer2: m3 requires m1 + */ + public void testImpliedReadabilityWithLayers1() { + + // cf1: m1 and m2, m2 requires transitive m1 + + ModuleDescriptor descriptor1 = newBuilder("m1") + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolve(finder1, "m2"); + + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m3, m3 requires m2 + + ModuleDescriptor descriptor3 = newBuilder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); + + Configuration cf2 = resolve(cf1, finder2, "m3"); + + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == ModuleLayer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); + + Module m1 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + Module m3 = layer2.findModule("m3").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer1); + assertTrue(m3.getLayer() == layer2); + + assertTrue(m1.getClassLoader() == cl1); + assertTrue(m2.getClassLoader() == cl1); + assertTrue(m3.getClassLoader() == cl2); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m2.canRead(m3)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + } + + + /** + * Test layers with implied readability. + * + * The test consists of three configurations: + * - Configuration/layer1: m1 + * - Configuration/layer2: m2 requires transitive m3, m3 requires m2 + */ + public void testImpliedReadabilityWithLayers2() { + + // cf1: m1 + + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolve(finder1, "m1"); + + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + + ModuleDescriptor descriptor3 = newBuilder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); + + Configuration cf2 = resolve(cf1, finder2, "m3"); + + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == ModuleLayer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); + + Module m1 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + Module m3 = layer2.findModule("m3").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer2); + assertTrue(m3.getLayer() == layer2); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m2.canRead(m3)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + } + + + /** + * Test layers with implied readability. + * + * The test consists of three configurations: + * - Configuration/layer1: m1 + * - Configuration/layer2: m2 requires transitive m1 + * - Configuration/layer3: m3 requires m1 + */ + public void testImpliedReadabilityWithLayers3() { + + // cf1: m1 + + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolve(finder1, "m1"); + + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m2 requires transitive m1 + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + + Configuration cf2 = resolve(cf1, finder2, "m2"); + + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + + + // cf3: m3 requires m2 + + ModuleDescriptor descriptor3 = newBuilder("m3") + .requires("m2") + .build(); + + ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); + + Configuration cf3 = resolve(cf2, finder3, "m3"); + + ClassLoader cl3 = new ClassLoader() { }; + ModuleLayer layer3 = layer2.defineModules(cf3, mn -> cl3); + + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == ModuleLayer.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(); + Module m3 = layer3.findModule("m3").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer2); + assertTrue(m3.getLayer() == layer3); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m2.canRead(m3)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + } + + + /** + * Test layers with implied readability. + * + * The test consists of two configurations: + * - Configuration/layer1: m1, m2 requires transitive m1 + * - Configuration/layer2: m3 requires transitive m2, m4 requires m3 + */ + public void testImpliedReadabilityWithLayers4() { + + // cf1: m1, m2 requires transitive m1 + + ModuleDescriptor descriptor1 = newBuilder("m1") + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolve(finder1, "m2"); + + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m3 requires transitive m2, m4 requires m3 + + ModuleDescriptor descriptor3 = newBuilder("m3") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") + .build(); + + ModuleDescriptor descriptor4 = newBuilder("m4") + .requires("m3") + .build(); + + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); + + Configuration cf2 = resolve(cf1, finder2, "m3", "m4"); + + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + + assertTrue(layer1.parents().size() == 1); + assertTrue(layer1.parents().get(0) == ModuleLayer.empty()); + + assertTrue(layer2.parents().size() == 1); + assertTrue(layer2.parents().get(0) == layer1); + + Module m1 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + Module m3 = layer2.findModule("m3").get(); + Module m4 = layer2.findModule("m4").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer1); + assertTrue(m3.getLayer() == layer2); + assertTrue(m4.getLayer() == layer2); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + assertFalse(m1.canRead(m4)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m1.canRead(m3)); + assertFalse(m1.canRead(m4)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + assertFalse(m3.canRead(m4)); + + assertTrue(m4.canRead(m1)); + assertTrue(m4.canRead(m2)); + assertTrue(m4.canRead(m3)); + assertTrue(m4.canRead(m4)); + } + + + /** + * Test layers with a qualified export. The module exporting the package + * does not read the target module. + * + * m1 { exports p to m2 } + * m2 { } + */ + public void testQualifiedExports1() { + ModuleDescriptor descriptor1 = newBuilder("m1"). + exports("p", Set.of("m2")) + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolve(finder1, "m1", "m2"); + + ClassLoader cl = new ClassLoader() { }; + ModuleLayer layer = ModuleLayer.empty().defineModules(cf, mn -> cl); + assertTrue(layer.modules().size() == 2); + + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + + // check m1 exports p to m2 + assertFalse(m1.isExported("p")); + assertTrue(m1.isExported("p", m2)); + assertFalse(m1.isOpen("p", m2)); + } + + + /** + * Test layers with a qualified export. The module exporting the package + * reads the target module. + * + * m1 { exports p to m2; } + * m2 { requires m1; } + */ + public void testQualifiedExports2() { + ModuleDescriptor descriptor1 = newBuilder("m1") + .exports("p", Set.of("m2")) + .build(); + + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolve(finder1, "m2"); + ClassLoader cl = new ClassLoader() { }; + ModuleLayer layer = ModuleLayer.empty().defineModules(cf, mn -> cl); + assertTrue(layer.modules().size() == 2); + + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + + // check m1 exports p to m2 + assertFalse(m1.isExported("p")); + assertTrue(m1.isExported("p", m2)); + assertFalse(m1.isOpen("p", m2)); + } + + + /** + * Test layers with a qualified export. The module exporting the package + * does not read the target module in the parent layer. + * + * - Configuration/layer1: m1 { } + * - Configuration/layer2: m2 { exports p to m1; } + */ + public void testQualifiedExports3() { + // create layer1 with m1 + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + assertTrue(layer1.modules().size() == 1); + + // create layer2 with m2 + ModuleDescriptor descriptor2 = newBuilder("m2") + .exports("p", Set.of("m1")) + .build(); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(cf1, finder2, "m2"); + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + assertTrue(layer2.modules().size() == 1); + + Module m1 = layer1.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + + // check m2 exports p to layer1/m1 + assertFalse(m2.isExported("p")); + assertTrue(m2.isExported("p", m1)); + assertFalse(m2.isOpen("p", m1)); + } + + + /** + * Test layers with a qualified export. The module exporting the package + * reads the target module in the parent layer. + * + * - Configuration/layer1: m1 { } + * - Configuration/layer2: m2 { requires m1; exports p to m1; } + */ + public void testQualifiedExports4() { + // create layer1 with m1 + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + assertTrue(layer1.modules().size() == 1); + + // create layer2 with m2 + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires("m1") + .exports("p", Set.of("m1")) + .build(); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(cf1, finder2, "m2"); + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + assertTrue(layer2.modules().size() == 1); + + Module m1 = layer1.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + + // check m2 exports p to layer1/m1 + assertFalse(m2.isExported("p")); + assertTrue(m2.isExported("p", m1)); + assertFalse(m2.isOpen("p", m1)); + } + + /** + * Test layers with a qualified export. The module exporting the package + * does not read the target module. + * + * - Configuration/layer1: m1 + * - Configuration/layer2: m1, m2 { exports p to m1; } + */ + public void testQualifiedExports5() { + // create layer1 with m1 + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + assertTrue(layer1.modules().size() == 1); + + // create layer2 with m1 and m2 + ModuleDescriptor descriptor2 = newBuilder("m2").exports("p", Set.of("m1")).build(); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2); + Configuration cf2 = resolve(cf1, finder2, "m1", "m2"); + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + assertTrue(layer2.modules().size() == 2); + + Module m1_v1 = layer1.findModule("m1").get(); + Module m1_v2 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + + // check m2 exports p to layer2/m2 + assertFalse(m2.isExported("p")); + assertTrue(m2.isExported("p", m1_v2)); + assertFalse(m2.isExported("p", m1_v1)); + } + + + /** + * Test layers with a qualified export. The module exporting the package + * reads the target module in the parent layer (due to requires transitive). + * + * - Configuration/layer1: m1, m2 { requires transitive m1; } + * - Configuration/layer2: m1, m3 { requires m2; exports p to m1; } + */ + public void testQualifiedExports6() { + // create layer1 with m1 and m2 + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + ModuleDescriptor descriptor2 = newBuilder("m2") + .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") + .build(); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + Configuration cf1 = resolve(finder1, "m2"); + ClassLoader loader1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> loader1); + assertTrue(layer1.modules().size() == 2); + + // create layer2 with m1 and m3 + ModuleDescriptor descriptor3 = newBuilder("m3") + .requires("m2") + .exports("p", Set.of("m1")) + .build(); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); + Configuration cf2 = resolve(cf1, finder2, "m1", "m3"); + ClassLoader loader2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> loader2); + assertTrue(layer2.modules().size() == 2); + + Module m1_v1 = layer1.findModule("m1").get(); + Module m2 = layer1.findModule("m2").get(); + + Module m1_v2 = layer2.findModule("m1").get(); + Module m3 = layer2.findModule("m3").get(); + + assertTrue(m3.canRead(m1_v1)); + assertFalse(m3.canRead(m1_v2)); + + assertFalse(m3.isExported("p")); + assertTrue(m3.isExported("p", m1_v1)); + assertFalse(m3.isExported("p", m1_v2)); + assertFalse(m3.isExported("p", m2)); + } + + + /** + * Test layers with a qualified export. The target module is not in any layer. + * + * - Configuration/layer1: m1 { } + * - Configuration/layer2: m2 { exports p to m3; } + */ + public void testQualifiedExports7() { + // create layer1 with m1 + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + ClassLoader cl1 = new ClassLoader() { }; + ModuleLayer layer1 = ModuleLayer.empty().defineModules(cf1, mn -> cl1); + assertTrue(layer1.modules().size() == 1); + + // create layer2 with m2 + ModuleDescriptor descriptor2 = newBuilder("m2") + .exports("p", Set.of("m3")) + .build(); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(cf1, finder2, "m2"); + ClassLoader cl2 = new ClassLoader() { }; + ModuleLayer layer2 = layer1.defineModules(cf2, mn -> cl2); + assertTrue(layer2.modules().size() == 1); + + Module m1 = layer1.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + + // check m2 does not export p to anyone + assertFalse(m2.isExported("p")); + assertFalse(m2.isExported("p", m1)); + } + + /** + * Attempt to use defineModules to create a layer with a module defined + * to a class loader that already has a module of the same name defined + * to the class loader. + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testModuleAlreadyDefinedToLoader() { + + ModuleDescriptor md = newBuilder("m") + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(md); + + Configuration parent = ModuleLayer.boot().configuration(); + + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); + + ClassLoader loader = new ClassLoader() { }; + + ModuleLayer.boot().defineModules(cf, mn -> loader); + + // should throw LayerInstantiationException as m1 already defined to loader + ModuleLayer.boot().defineModules(cf, mn -> loader); + + } + + + /** + * Attempt to use defineModules to create a layer with a module containing + * package {@code p} where the class loader already has a module defined + * to it containing package {@code p}. + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testPackageAlreadyInNamedModule() { + + ModuleDescriptor md1 = newBuilder("m1") + .packages(Set.of("p")) + .requires("java.base") + .build(); + + ModuleDescriptor md2 = newBuilder("m2") + .packages(Set.of("p")) + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(md1, md2); + + ClassLoader loader = new ClassLoader() { }; + + // define m1 containing package p to class loader + + Configuration parent = ModuleLayer.boot().configuration(); + + Configuration cf1 = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); + + ModuleLayer layer1 = ModuleLayer.boot().defineModules(cf1, mn -> loader); + + // attempt to define m2 containing package p to class loader + + Configuration cf2 = parent.resolve(finder, ModuleFinder.of(), Set.of("m2")); + + // should throw exception because p already in m1 + ModuleLayer layer2 = ModuleLayer.boot().defineModules(cf2, mn -> loader); + + } + + + /** + * Attempt to use defineModules to create a layer with a module + * containing a package in which a type is already loaded by the class + * loader. + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testPackageAlreadyInUnnamedModule() throws Exception { + + Class<?> c = layertest.Test.class; + assertFalse(c.getModule().isNamed()); // in unnamed module + + ModuleDescriptor md = newBuilder("m") + .packages(Set.of(c.getPackageName())) + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(md); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); + + ModuleLayer.boot().defineModules(cf, mn -> c.getClassLoader()); + } + + + /** + * Attempt to create a layer with a module named "java.base". + */ + public void testLayerWithJavaBase() { + ModuleDescriptor descriptor = newBuilder("java.base") + .exports("java.lang") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of("java.base")); + assertTrue(cf.modules().size() == 1); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + try { + ModuleLayer.boot().defineModules(cf, mn -> new ClassLoader() { }); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + try { + ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + try { + ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); + assertTrue(false); + } catch (LayerInstantiationException e) { } + } + + + @DataProvider(name = "javaPackages") + public Object[][] javaPackages() { + return new Object[][] { { "m1", "java" }, { "m2", "java.x" } }; + } + + /** + * 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(dataProvider = "javaPackages") + public void testLayerWithJavaPackage(String mn, String pn) { + ModuleDescriptor descriptor = newBuilder(mn).packages(Set.of(pn)).build(); + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of(mn)); + assertTrue(cf.modules().size() == 1); + + ClassLoader pcl = ClassLoader.getPlatformClassLoader(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + try { + ModuleLayer.boot().defineModules(cf, _mn -> new ClassLoader() { }); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + try { + ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + try { + ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); + assertTrue(false); + } catch (LayerInstantiationException e) { } + + // create layer with module defined to platform class loader + ModuleLayer layer = ModuleLayer.boot().defineModules(cf, _mn -> pcl); + Optional<Module> om = layer.findModule(mn); + assertTrue(om.isPresent()); + Module foo = om.get(); + assertTrue(foo.getClassLoader() == pcl); + assertTrue(foo.getPackages().size() == 1); + assertTrue(foo.getPackages().iterator().next().equals(pn)); + } + + + /** + * Attempt to create a layer with a module defined to the boot loader + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testLayerWithBootLoader() { + ModuleDescriptor descriptor = newBuilder("m1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of("m1")); + assertTrue(cf.modules().size() == 1); + + ModuleLayer.boot().defineModules(cf, mn -> null ); + } + + + /** + * Parent of configuration != configuration of parent layer + */ + @Test(expectedExceptions = { IllegalArgumentException.class }) + public void testIncorrectParent1() { + ModuleDescriptor descriptor1 = newBuilder("m1") + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); + + ClassLoader loader = new ClassLoader() { }; + ModuleLayer.empty().defineModules(cf, mn -> loader); + } + + + /** + * Parent of configuration != configuration of parent layer + */ + @Test(expectedExceptions = { IllegalArgumentException.class }) + public void testIncorrectParent2() { + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf = resolve(finder, "m1"); + + ClassLoader loader = new ClassLoader() { }; + ModuleLayer.boot().defineModules(cf, mn -> loader); + } + + + // null handling + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull1() { + ClassLoader loader = new ClassLoader() { }; + ModuleLayer.empty().defineModules(null, mn -> loader); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull2() { + Configuration cf = resolve(ModuleLayer.boot().configuration(), ModuleFinder.of()); + ModuleLayer.boot().defineModules(cf, null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull3() { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ModuleLayer.empty().defineModulesWithOneLoader(null, scl); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull4() { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ModuleLayer.empty().defineModulesWithManyLoaders(null, scl); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testFindModuleWithNull() { + ModuleLayer.boot().findModule(null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testFindLoaderWithNull() { + ModuleLayer.boot().findLoader(null); + } + + + // immutable sets + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testImmutableSet() { + Module base = Object.class.getModule(); + ModuleLayer.boot().modules().add(base); + } + + + /** + * Resolve the given modules, by name, and returns the resulting + * Configuration. + */ + private static Configuration resolve(Configuration cf, + ModuleFinder finder, + String... roots) { + return cf.resolve(finder, ModuleFinder.of(), Set.of(roots)); + } + + private static Configuration resolve(ModuleFinder finder, + String... roots) { + return resolve(Configuration.empty(), finder, roots); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/LayerAndLoadersTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,721 @@ +/* + * 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 + * @library /lib/testlibrary + * @modules jdk.compiler + * @build LayerAndLoadersTest CompilerUtils ModuleUtils + * @run testng LayerAndLoadersTest + * @summary Tests for java.lang.ModuleLayer@defineModulesWithXXX methods + */ + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.reflect.Method; +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; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class LayerAndLoadersTest { + + 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 MODS_DIR = Paths.get("mods"); + + @BeforeTest + public void setup() throws Exception { + + // javac -d mods --module-source-path src src/** + assertTrue(CompilerUtils.compile(SRC_DIR, MODS_DIR, + "--module-source-path", SRC_DIR.toString())); + } + + + /** + * Basic test of ModuleLayer.defineModulesWithOneLoader + * + * Test scenario: + * m1 requires m2 and m3 + */ + public void testWithOneLoader() throws Exception { + + Configuration cf = resolve("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); + + checkLayer(layer, "m1", "m2", "m3"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2 == cl1); + assertTrue(cl3 == cl1); + + invoke(layer, "m1", "p.Main"); + + } + + + /** + * Basic test of ModuleLayer.defineModulesWithManyLoaders + * + * Test scenario: + * m1 requires m2 and m3 + */ + public void testWithManyLoaders() throws Exception { + + Configuration cf = resolve("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); + + checkLayer(layer, "m1", "m2", "m3"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2.getParent() == scl); + assertTrue(cl3.getParent() == scl); + assertTrue(cl2 != cl1); + assertTrue(cl3 != cl1); + assertTrue(cl3 != cl2); + + invoke(layer, "m1", "p.Main"); + + } + + + /** + * Basic test of ModuleLayer.defineModulesWithOneLoader where one of the + * modules is a service provider module. + * + * Test scenario: + * m1 requires m2 and m3 + * m1 uses S + * m4 provides S with ... + */ + public void testServicesWithOneLoader() throws Exception { + + Configuration cf = resolveAndBind("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); + + checkLayer(layer, "m1", "m2", "m3", "m4"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + ClassLoader cl4 = layer.findLoader("m4"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2 == cl1); + assertTrue(cl3 == cl1); + assertTrue(cl4 == cl1); + + Class<?> serviceType = cl1.loadClass("p.Service"); + assertTrue(serviceType.getClassLoader() == cl1); + + Iterator<?> iter = ServiceLoader.load(serviceType, cl1).iterator(); + Object provider = iter.next(); + assertTrue(serviceType.isInstance(provider)); + assertTrue(provider.getClass().getClassLoader() == cl1); + assertFalse(iter.hasNext()); + + } + + + /** + * Basic test of ModuleLayer.defineModulesWithManyLoaders where one of the + * modules is a service provider module. + * + * Test scenario: + * m1 requires m2 and m3 + * m1 uses S + * m4 provides S with ... + */ + public void testServicesWithManyLoaders() throws Exception { + + Configuration cf = resolveAndBind("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); + + checkLayer(layer, "m1", "m2", "m3", "m4"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + ClassLoader cl4 = layer.findLoader("m4"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2.getParent() == scl); + assertTrue(cl3.getParent() == scl); + assertTrue(cl4.getParent() == scl); + assertTrue(cl2 != cl1); + assertTrue(cl3 != cl1); + assertTrue(cl3 != cl2); + assertTrue(cl4 != cl1); + assertTrue(cl4 != cl2); + assertTrue(cl4 != cl3); + + Class<?> serviceType = cl1.loadClass("p.Service"); + assertTrue(serviceType.getClassLoader() == cl1); + + // Test that the service provider can be located via any of + // the class loaders in the layer + for (Module m : layer.modules()) { + ClassLoader loader = m.getClassLoader(); + Iterator<?> iter = ServiceLoader.load(serviceType, loader).iterator(); + Object provider = iter.next(); + assertTrue(serviceType.isInstance(provider)); + assertTrue(provider.getClass().getClassLoader() == cl4); + assertFalse(iter.hasNext()); + } + + } + + + /** + * Tests that the class loaders created by defineModulesWithXXX delegate + * to the given parent class loader. + */ + public void testDelegationToParent() throws Exception { + + Configuration cf = resolve("m1"); + + ClassLoader parent = this.getClass().getClassLoader(); + String cn = this.getClass().getName(); + + // one loader + ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, parent); + testLoad(layer, cn); + + // one loader with boot loader as parent + layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, null); + testLoadFail(layer, cn); + + // many loaders + layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, parent); + testLoad(layer, cn); + + // many loader with boot loader as parent + layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, null); + testLoadFail(layer, cn); + + } + + + /** + * Test defineModulesWithXXX when modules that have overlapping packages. + * + * Test scenario: + * m1 exports p + * m2 exports p + */ + public void testOverlappingPackages() { + + ModuleDescriptor descriptor1 + = ModuleDescriptor.newModule("m1").exports("p").build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.newModule("m2").exports("p").build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); + + // cannot define both module m1 and m2 to the same class loader + try { + ModuleLayer.boot().defineModulesWithOneLoader(cf, null); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + + // should be okay to have one module per class loader + ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, null); + checkLayer(layer, "m1", "m2"); + + } + + + /** + * Test ModuleLayer.defineModulesWithXXX with split delegation. + * + * Test scenario: + * layer1: m1 exports p, m2 exports p + * layer2: m3 reads m1, m4 reads m2 + */ + public void testSplitDelegation() { + + ModuleDescriptor descriptor1 + = ModuleDescriptor.newModule("m1").exports("p").build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.newModule("m2").exports("p").build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = ModuleLayer.boot() + .configuration() + .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2")); + + ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null); + checkLayer(layer1, "m1", "m2"); + + ModuleDescriptor descriptor3 + = ModuleDescriptor.newModule("m3").requires("m1").build(); + + ModuleDescriptor descriptor4 + = ModuleDescriptor.newModule("m4").requires("m2").build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); + + Configuration cf2 = cf1.resolve(finder2, ModuleFinder.of(), + Set.of("m3", "m4")); + + // package p cannot be supplied by two class loaders + try { + layer1.defineModulesWithOneLoader(cf2, null); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + + // no split delegation when modules have their own class loader + ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); + checkLayer(layer2, "m3", "m4"); + + } + + + /** + * Test ModuleLayer.defineModulesWithXXX when the modules that override same + * named modules in the parent layer. + * + * Test scenario: + * layer1: m1, m2, m3 => same loader + * layer2: m1, m2, m4 => same loader + */ + public void testOverriding1() throws Exception { + + Configuration cf1 = resolve("m1"); + + ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithOneLoader(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), + Set.of("m1")); + + ModuleLayer layer2 = layer1.defineModulesWithOneLoader(cf2, null); + checkLayer(layer2, "m1", "m2", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer1.findLoader("m2"); + ClassLoader loader3 = layer1.findLoader("m3"); + + ClassLoader loader4 = layer2.findLoader("m1"); + ClassLoader loader5 = layer2.findLoader("m2"); + ClassLoader loader6 = layer2.findLoader("m3"); + + assertTrue(loader1 == loader2); + assertTrue(loader1 == loader3); + + assertTrue(loader4 == loader5); + assertTrue(loader4 == loader6); + assertTrue(loader4 != loader1); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1); + + assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); + assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader4); + assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader4); + + } + + + /** + * Test Layer defineModulesWithXXX when the modules that override same + * named modules in the parent layer. + * + * Test scenario: + * layer1: m1, m2, m3 => loader pool + * layer2: m1, m2, m3 => loader pool + */ + public void testOverriding2() throws Exception { + + Configuration cf1 = resolve("m1"); + + ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), + Set.of("m1")); + + ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); + checkLayer(layer2, "m1", "m2", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer1.findLoader("m2"); + ClassLoader loader3 = layer1.findLoader("m3"); + + ClassLoader loader4 = layer2.findLoader("m1"); + ClassLoader loader5 = layer2.findLoader("m2"); + ClassLoader loader6 = layer2.findLoader("m3"); + + assertTrue(loader4 != loader1); + assertTrue(loader5 != loader2); + assertTrue(loader6 != loader3); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3); + + // p.Main is not visible via loader2 + try { + loader2.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // w.Hello is not visible via loader2 + try { + loader2.loadClass("w.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // p.Main is not visible via loader3 + try { + loader3.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // q.Hello is not visible via loader3 + try { + loader3.loadClass("q.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + + assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); + assertTrue(loader5.loadClass("q.Hello").getClassLoader() == loader5); + assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); + + // p.Main is not visible via loader5 + try { + loader5.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // w.Hello is not visible via loader5 + try { + loader5.loadClass("w.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // p.Main is not visible via loader6 + try { + loader6.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // q.Hello is not visible via loader6 + try { + loader6.loadClass("q.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + } + + + /** + * Test ModuleLayer.defineModulesWithXXX when the modules that override same + * named modules in the parent layer. + * + * layer1: m1, m2, m3 => same loader + * layer2: m1, m3 => same loader + */ + public void testOverriding3() throws Exception { + + Configuration cf1 = resolve("m1"); + + ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithOneLoader(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = finderFor("m1", "m3"); + + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), + Set.of("m1")); + + ModuleLayer layer2 = layer1.defineModulesWithOneLoader(cf2, null); + checkLayer(layer2, "m1", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer2.findLoader("m1"); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1); + + assertTrue(loader2.loadClass("p.Main").getClassLoader() == loader2); + assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader1); + assertTrue(loader2.loadClass("w.Hello").getClassLoader() == loader2); + + } + + + /** + * Test Layer defineModulesWithXXX when the modules that override same + * named modules in the parent layer. + * + * layer1: m1, m2, m3 => loader pool + * layer2: m1, m3 => loader pool + */ + public void testOverriding4() throws Exception { + + Configuration cf1 = resolve("m1"); + + ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = finderFor("m1", "m3"); + + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), + Set.of("m1")); + + ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); + checkLayer(layer2, "m1", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer1.findLoader("m2"); + ClassLoader loader3 = layer1.findLoader("m3"); + + ClassLoader loader4 = layer2.findLoader("m1"); + ClassLoader loader5 = layer2.findLoader("m2"); + ClassLoader loader6 = layer2.findLoader("m3"); + + assertTrue(loader4 != loader1); + assertTrue(loader5 == loader2); // m2 not overridden + assertTrue(loader6 != loader3); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3); + + assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader2); + + assertTrue(loader3.loadClass("w.Hello").getClassLoader() == loader3); + + assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); + assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader2); + assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader6); + + assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); + + } + + + /** + * Basic test of resource loading with a class loader created by + * Layer.defineModulesWithOneLoader. + */ + public void testResourcesOneLoader() throws Exception { + Configuration cf = resolve("m1"); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ModuleLayer layer = ModuleLayer.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 = resolve("m1"); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ModuleLayer layer = ModuleLayer.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<URL> urls = loader.getResources(name); + assertTrue(urls.hasMoreElements()); + } + + + // -- supporting methods -- + + + /** + * Resolve the given modules, by name, and returns the resulting + * Configuration. + */ + private static Configuration resolve(String... roots) { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + return ModuleLayer.boot() + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of(roots)); + } + + /** + * Resolve the given modules, by name, and returns the resulting + * Configuration. + */ + private static Configuration resolveAndBind(String... roots) { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + return ModuleLayer.boot() + .configuration() + .resolveAndBind(finder, ModuleFinder.of(), Set.of(roots)); + } + + + /** + * Invokes the static void main(String[]) method on the given class + * in the given module. + */ + private static void invoke(ModuleLayer layer, String mn, String mc) throws Exception { + ClassLoader loader = layer.findLoader(mn); + Class<?> c = loader.loadClass(mc); + Method mainMethod = c.getMethod("main", String[].class); + mainMethod.invoke(null, (Object)new String[0]); + } + + + /** + * Checks that the given layer contains exactly the expected modules + * (by name). + */ + private void checkLayer(ModuleLayer layer, String ... expected) { + Set<String> names = layer.modules().stream() + .map(Module::getName) + .collect(Collectors.toSet()); + assertTrue(names.size() == expected.length); + for (String name : expected) { + assertTrue(names.contains(name)); + } + } + + + /** + * Test that a class can be loaded via the class loader of all modules + * in the given layer. + */ + static void testLoad(ModuleLayer layer, String cn) throws Exception { + for (Module m : layer.modules()) { + ClassLoader l = m.getClassLoader(); + l.loadClass(cn); + } + } + + + /** + * Test that a class cannot be loaded via any of the class loaders of + * the modules in the given layer. + */ + static void testLoadFail(ModuleLayer layer, String cn) throws Exception { + for (Module m : layer.modules()) { + ClassLoader l = m.getClassLoader(); + try { + l.loadClass(cn); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + } + } + + + /** + * Returns a ModuleFinder that only finds the given test modules + */ + static ModuleFinder finderFor(String... names) { + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + + Map<String, ModuleReference> mrefs = new HashMap<>(); + for (String name : names) { + Optional<ModuleReference> omref = finder.find(name); + assert omref.isPresent(); + mrefs.put(name, omref.get()); + } + + return new ModuleFinder() { + @Override + public Optional<ModuleReference> find(String name) { + ModuleReference mref = mrefs.get(name); + return Optional.ofNullable(mref); + } + @Override + public Set<ModuleReference> findAll() { + return mrefs.values().stream().collect(Collectors.toSet()); + } + }; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/LayerControllerTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,194 @@ +/* + * 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.ModuleLayer.Controller + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +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 ModuleLayer.Controller createTestLayer() { + ModuleDescriptor descriptor1 + = ModuleDescriptor.newModule("m1") + .packages(Set.of("p1")) + .requires("java.base") + .build(); + + ModuleDescriptor descriptor2 + = ModuleDescriptor.newModule("m2") + .requires("java.base") + .packages(Set.of("p2")) + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + ModuleLayer bootLayer = ModuleLayer.boot(); + + Configuration cf = bootLayer.configuration() + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + ModuleLayer.Controller controller + = ModuleLayer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl); + + ModuleLayer layer = controller.layer(); + + assertTrue(layer.modules().size() == 2); + assertTrue(layer.findModule("m1").isPresent()); + assertTrue(layer.findModule("m2").isPresent()); + + return controller; + } + + /** + * Basic test of Controller to update modules m1 and m2 to read and + * open packages to each other. + */ + public void testBasic() { + ModuleLayer.Controller controller = createTestLayer(); + ModuleLayer 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() { + ModuleLayer.Controller controller = createTestLayer(); + ModuleLayer 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() { + ModuleLayer.Controller controller = createTestLayer(); + ModuleLayer 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) { } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/layertest/Test.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Supporting class for tests of java.lang.ModuleLayer. + */ + +package layertest; + +public class Test { } +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m1/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module m1 { + requires m2; + requires m3; + exports p; + uses p.Service; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m1/p/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.net.URL; + +public class Main { + public static void main(String[] args) { + + URL url1 = Main.class.getResource("Main.class"); + if (url1 == null) throw new RuntimeException(); + URL url2 = Main.class.getResource("/p/Main.class"); + if (url2 == null) throw new RuntimeException(); + + q.Hello.hello(); + w.Hello.hello(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m1/p/Service.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public interface Service { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m2/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m2 { + exports q; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m2/q/Hello.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q; + +import java.net.URL; + +public class Hello { + + public static void hello() { + + URL url1 = Hello.class.getResource("Hello.class"); + if (url1 == null) throw new RuntimeException(); + URL url2 = Hello.class.getResource("/q/Hello.class"); + if (url2 == null) throw new RuntimeException(); + + System.out.println("Hello!"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m3/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m3 { + // qualified export + exports w to m1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m3/w/Hello.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package w; + +import java.net.URL; + +public class Hello { + + public static void hello() { + + URL url1 = Hello.class.getResource("Hello.class"); + if (url1 == null) throw new RuntimeException(); + URL url2 = Hello.class.getResource("/w/Hello.class"); + if (url2 == null) throw new RuntimeException(); + + System.out.println("Hello!"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m4/impl/ServiceImpl.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package impl; + +public class ServiceImpl implements p.Service { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleLayer/src/m4/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m4 { + requires m1; + provides p.Service with impl.ServiceImpl; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/AddExportsTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,126 @@ +/* + * 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 + * @modules java.base/jdk.internal.misc + * java.desktop + * @run main/othervm --add-exports=java.desktop/sun.awt=java.base AddExportsTest + * @run main/othervm --add-exports=java.desktop/sun.awt=ALL-UNNAMED AddExportsTest + * @summary Test Module isExported methods with exports changed by -AddExportsTest + */ + +import java.util.Optional; +import java.util.stream.Stream; + +import jdk.internal.misc.VM; + +public class AddExportsTest { + /* + * jtreg sets -Dtest.modules system property to the internal APIs + * specified at @modules tag. The test will exclude --add-exports set + * for @modules. + */ + private static final String TEST_MODULES = System.getProperty("test.modules"); + + public static void main(String[] args) { + + Optional<String> oaddExports = Stream.of(VM.getRuntimeArguments()) + .filter(arg -> arg.startsWith("--add-exports=")) + .filter(arg -> !arg.equals("--add-exports=" + TEST_MODULES + "=ALL-UNNAMED")) + .map(arg -> arg.substring("--add-exports=".length(), arg.length())) + .findFirst(); + + assertTrue(oaddExports.isPresent()); + + ModuleLayer bootLayer = ModuleLayer.boot(); + + Module unnamedModule = AddExportsTest.class.getModule(); + assertFalse(unnamedModule.isNamed()); + + for (String expr : oaddExports.get().split(",")) { + + String[] s = expr.split("="); + assertTrue(s.length == 2); + + // $MODULE/$PACKAGE + String[] moduleAndPackage = s[0].split("/"); + assertTrue(moduleAndPackage.length == 2); + + String mn = moduleAndPackage[0]; + String pn = moduleAndPackage[1]; + + // source module + Module source; + Optional<Module> om = bootLayer.findModule(mn); + assertTrue(om.isPresent(), mn + " not in boot layer"); + source = om.get(); + + // package should not be exported unconditionally + assertFalse(source.isExported(pn), + pn + " should not be exported unconditionally"); + + // $TARGET + String tn = s[1]; + if ("ALL-UNNAMED".equals(tn)) { + + // package is exported to all unnamed modules + assertTrue(source.isExported(pn, unnamedModule), + pn + " should be exported to all unnamed modules"); + + } else { + + om = bootLayer.findModule(tn); + assertTrue(om.isPresent()); + Module target = om.get(); + + // package should be exported to target module + assertTrue(source.isExported(pn, target), + pn + " should be exported to " + target); + + // package should not be exported to unnamed modules + assertFalse(source.isExported(pn, unnamedModule), + pn + " should not be exported to unnamed modules"); + + } + + } + } + + static void assertTrue(boolean cond) { + if (!cond) throw new RuntimeException(); + } + + static void assertTrue(boolean cond, String msg) { + if (!cond) throw new RuntimeException(msg); + } + + static void assertFalse(boolean cond) { + if (cond) throw new RuntimeException(); + } + + static void assertFalse(boolean cond, String msg) { + if (cond) throw new RuntimeException(msg); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/AnnotationsTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,154 @@ +/* + * 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.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 = ModuleLayer.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<Attribute> attrs = new ArrayList<>(); + attrs.add(new ClassFileAttributes.ModuleAttribute()); + attrs.add(new ClassFileAttributes.ModulePackagesAttribute()); + 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); + + ModuleLayer bootLayer = ModuleLayer.boot(); + + Configuration cf = bootLayer.configuration() + .resolve(finder, ModuleFinder.of(), Set.of(name)); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + + Module module = layer.findModule(name).orElse(null); + assertNotNull(module, name + " not loaded"); + return module; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/BasicModuleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ResolvedModule; +import java.nio.file.spi.FileSystemProvider; // service type in java.base +import java.util.function.Predicate; +import java.util.stream.Stream; +import javax.print.PrintServiceLookup; // service type in java.desktop + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/* + * @test + * @summary Basic test of java.lang.Module + * @modules java.desktop java.xml + * @run testng BasicModuleTest + */ + +public class BasicModuleTest { + + /** + * Tests that the given module reads all modules in the boot layer. + */ + private void testReadsAllBootModules(Module m) { + ModuleLayer bootLayer = ModuleLayer.boot(); + bootLayer.configuration() + .modules() + .stream() + .map(ResolvedModule::name) + .map(bootLayer::findModule) + .forEach(target -> assertTrue(m.canRead(target.get()))); + } + + /** + * Returns a {@code Predicate} to test if a package is exported. + */ + private Predicate<Exports> doesExport(String pn) { + return e -> (e.source().equals(pn) && !e.isQualified()); + } + + + + @Test + public void testThisModule() { + Module thisModule = BasicModuleTest.class.getModule(); + Module baseModule = Object.class.getModule(); + + assertFalse(thisModule.isNamed()); + assertTrue(thisModule.getName() == null); + assertTrue(thisModule.getDescriptor() == null); + assertTrue(thisModule.getLayer() == null); + assertTrue(thisModule.toString().startsWith("unnamed module ")); + + ClassLoader thisLoader = BasicModuleTest.class.getClassLoader(); + assertTrue(thisLoader == thisModule.getClassLoader()); + assertTrue(thisLoader.getUnnamedModule() == thisModule); + + // unnamed modules read all other modules + ClassLoader cl; + cl = ClassLoader.getPlatformClassLoader(); + assertTrue(thisModule.canRead(cl.getUnnamedModule())); + cl = ClassLoader.getSystemClassLoader(); + assertTrue(thisModule.canRead(cl.getUnnamedModule())); + testReadsAllBootModules(thisModule); + + // unnamed modules export all packages + assertTrue(thisModule.isExported("")); + assertTrue(thisModule.isExported("", thisModule)); + assertTrue(thisModule.isExported("", baseModule)); + assertTrue(thisModule.isExported("p")); + assertTrue(thisModule.isExported("p", thisModule)); + assertTrue(thisModule.isExported("p", baseModule)); + + // this test is in the unnamed package + assertTrue(thisModule.getPackages().contains("")); + } + + + @Test + public void testUnnamedModules() { + Module thisModule = BasicModuleTest.class.getModule(); + Module baseModule = Object.class.getModule(); + + ClassLoader loader1 = ClassLoader.getSystemClassLoader(); + ClassLoader loader2 = loader1.getParent(); + + Module m1 = loader1.getUnnamedModule(); + Module m2 = loader2.getUnnamedModule(); + + assertTrue(m1 != m2); + + assertFalse(m1.isNamed()); + assertFalse(m2.isNamed()); + + assertTrue(m1.getLayer() == null); + assertTrue(m2.getLayer() == null); + + assertTrue(m1.toString().startsWith("unnamed module ")); + assertTrue(m2.toString().startsWith("unnamed module ")); + + // unnamed module reads all modules + assertTrue(m1.canRead(m2)); + assertTrue(m2.canRead(m1)); + + testReadsAllBootModules(m1); + testReadsAllBootModules(m2); + + assertTrue(m1.isExported("")); + assertTrue(m1.isExported("", thisModule)); + assertTrue(m1.isExported("", baseModule)); + assertTrue(m1.isExported("p")); + assertTrue(m1.isExported("p", thisModule)); + assertTrue(m1.isExported("p", baseModule)); + } + + + + @Test + public void testBaseModule() { + Module base = Object.class.getModule(); + Module thisModule = BasicModuleTest.class.getModule(); + + // getName + assertTrue(base.getName().equals("java.base")); + + // getDescriptor + assertTrue(base.getDescriptor().exports().stream() + .anyMatch(doesExport("java.lang"))); + + // getClassLoader + assertTrue(base.getClassLoader() == null); + + // getLayer + assertTrue(base.getLayer() == ModuleLayer.boot()); + + // toString + assertEquals(base.toString(), "module java.base"); + + // getPackages + assertTrue(base.getPackages().contains("java.lang")); + + // canRead + assertTrue(base.canRead(base)); + assertFalse(base.canRead(thisModule)); + + // addReads + try { + base.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.canRead(thisModule)); + + // 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)); + + // addExports + try { + base.addExports("java.lang", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + base.addExports("jdk.internal.misc", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.isExported("jdk.internal.misc")); + assertFalse(base.isExported("jdk.internal.misc", thisModule)); + + // 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)); + + // addOpens + try { + base.addOpens("jdk.internal.misc", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.isOpen("jdk.internal.misc")); + assertFalse(base.isOpen("jdk.internal.misc", thisModule)); + + // canUse + assertTrue(base.canUse(FileSystemProvider.class)); + assertFalse(base.canUse(Thread.class)); + + // addUses + try { + base.addUses(FileSystemProvider.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + base.addUses(Thread.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.canUse(Thread.class)); + } + + + @Test + public void testDesktopModule() { + Module desktop = java.awt.Component.class.getModule(); + Module base = Object.class.getModule(); + Module xml = javax.xml.XMLConstants.class.getModule(); + Module thisModule = BasicModuleTest.class.getModule(); + + // name + assertTrue(desktop.getName().equals("java.desktop")); + + // descriptor + assertTrue(desktop.getDescriptor().exports().stream() + .anyMatch(doesExport("java.awt"))); + + // getClassLoader + assertTrue(desktop.getClassLoader() == null); + + // getLayer + assertTrue(desktop.getLayer() == ModuleLayer.boot()); + + // toString + assertEquals(desktop.toString(), "module java.desktop"); + + // getPackages + assertTrue(desktop.getPackages().contains("java.awt")); + assertTrue(desktop.getPackages().contains("sun.awt")); + + // canRead + assertTrue(desktop.canRead(base)); + assertTrue(desktop.canRead(xml)); + + // addReads + try { + desktop.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.canRead(thisModule)); + + // isExported + assertTrue(desktop.isExported("java.awt")); + assertTrue(desktop.isExported("java.awt", thisModule)); + assertFalse(desktop.isExported("sun.awt")); + assertFalse(desktop.isExported("sun.awt", thisModule)); + assertTrue(desktop.isExported("sun.awt", desktop)); + assertFalse(desktop.isExported("java.wombat")); + assertFalse(desktop.isExported("java.wombat", thisModule)); + assertFalse(desktop.isExported("java.wombat", base)); + + // addExports + try { + desktop.addExports("java.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + desktop.addExports("sun.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.isExported("sun.awt")); + assertFalse(desktop.isExported("sun.awt", thisModule)); + + // isOpen + assertFalse(desktop.isOpen("java.awt")); + assertFalse(desktop.isOpen("java.awt", thisModule)); + assertTrue(desktop.isOpen("java.awt", desktop)); + assertFalse(desktop.isOpen("sun.awt")); + assertFalse(desktop.isOpen("sun.awt", thisModule)); + assertTrue(desktop.isOpen("sun.awt", desktop)); + assertFalse(desktop.isOpen("java.wombat")); + assertFalse(desktop.isOpen("java.wombat", thisModule)); + assertFalse(desktop.isOpen("java.wombat", desktop)); + + // addOpens + try { + base.addOpens("sun.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.isOpen("sun.awt")); + assertFalse(desktop.isOpen("sun.awt", thisModule)); + + // canUse + assertTrue(base.canUse(FileSystemProvider.class)); + assertFalse(base.canUse(Thread.class)); + + // addUses + try { + desktop.addUses(PrintServiceLookup.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + desktop.addUses(Thread.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.canUse(Thread.class)); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/WithSecurityManager.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,145 @@ +/* + * 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 + * @modules jdk.compiler + * @summary Test java.lang.Module methods that specify permission checks + * @run main/othervm -Djava.security.policy=${test.src}/allow.policy WithSecurityManager allow + * @run main/othervm WithSecurityManager deny + */ + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +/** + * Test java.lang.Module methods that specify permission checks. + */ + +public class WithSecurityManager { + + // a module that will be loaded into a child layer + 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"); + + // base module, in the boot layer + Module base = Object.class.getModule(); + + // another module, in a child layer + Module other = loadModuleInChildLayer(ANOTHER_MODULE); + assertTrue(other.getLayer() != ModuleLayer.boot()); + + System.setSecurityManager(new SecurityManager()); + + test(base, "java/lang/Object.class", allow); + test(other, ANOTHER_MODULE_RESOURCE, allow); + } + + /** + * Test the permission checks by invoking methods on the given module. + * + * If {@code allow} is {@code true} then the permission checks should succeed. + */ + static void test(Module m, String name, boolean allow) throws IOException { + + // test Module::getClassLoader + System.out.format("Test getClassLoader on %s ...%n", m); + try { + ClassLoader cl = m.getClassLoader(); + System.out.println(cl); + if (!allow) + assertTrue("getClassLoader should have failed", false); + } catch (SecurityException e) { + System.out.println(e + " thrown"); + if (allow) + throw e; + } + + // test Module::getResourceAsStream + System.out.format("Test getResourceAsStream(\"%s\") on %s ...%n", name, m); + try (InputStream in = m.getResourceAsStream(name)) { + System.out.println(in); + if (allow && (in == null)) + assertTrue(name + " not found", false); + if (!allow && (in != null)) + assertTrue(name + " should not be found", false); + } + + } + + /** + * Create a module layer that contains the given system module. + */ + static Module loadModuleInChildLayer(String mn) { + Optional<ModuleReference> omref = ModuleFinder.ofSystem().find(mn); + assertTrue("module " + mn + " not a system module", omref.isPresent()); + + // create a ModuleFinder that only finds this module + ModuleReference mref = omref.get(); + ModuleFinder finder = new ModuleFinder() { + @Override + public Optional<ModuleReference> find(String name) { + if (name.equals(mn)) + return Optional.of(mref); + else + return Optional.empty(); + } + + @Override + public Set<ModuleReference> findAll() { + return Collections.singleton(mref); + } + }; + + // create a child configuration and layer with this module + ModuleLayer bootLayer = ModuleLayer.boot(); + Configuration cf = bootLayer + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of(ANOTHER_MODULE)); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, null); + + Optional<Module> om = layer.findModule(mn); + assertTrue("module " + mn + " not in child layer", om.isPresent()); + return om.get(); + } + + static void assertTrue(String msg, boolean e) { + if (!e) + throw new RuntimeException(msg); + } + + static void assertTrue(boolean e) { + if (!e) + throw new RuntimeException(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/AccessTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,86 @@ +/* + * 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.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +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 jdk.compiler + * @build AccessTest CompilerUtils jdk.testlibrary.* + * @run testng AccessTest + * @summary Driver for test that checks access to access to types in + * exported and non-exported packages. + */ + +@Test +public class AccessTest { + + 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 MODS_DIR = Paths.get("mods"); + + + // the names of the modules in this test + private static List<String> modules = Arrays.asList("test", "target"); + + + /** + * Compiles all modules used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + for (String mn : modules) { + Path src = SRC_DIR.resolve(mn); + Path mods = MODS_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(src, mods)); + } + } + + /** + * Run the test + */ + public void runTest() throws Exception { + 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) + .getExitValue(); + + assertTrue(exitValue == 0); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/target/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module target { + exports p1; + exports p2; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/target/p1/Helper.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +/** + * Helper class in target module to allow test invoke addExports[Private] + */ + +public class Helper { + Helper() { } + + public static void addExports(String pn, Module who) { + Helper.class.getModule().addExports(pn, who); + } + + public static void addOpens(String pn, Module who) { + Helper.class.getModule().addOpens(pn, who); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/target/p1/Public.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p1; + +public class Public { + + // public constructor + public Public() { } + + // non-public constructor + private Public(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/target/p2/NonPublic.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p2; + +class NonPublic { + + // public constructor + public NonPublic() { } + + // non-public constructor + private NonPublic(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/target/q1/Public.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q1; + +public class Public { + + // public constructor + public Public() { } + + // non-public constructor + private Public(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/target/q2/NonPublic.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q2; + +class NonPublic { + + // public constructor + public NonPublic() { } + + // non-public constructor + private NonPublic(Void ignore) { } + + // public field + public static Object f1; + + // non-public field + private static Object f2; + + // public method + public static void foo() { } + + // non-public method + private static void bar() { } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/test/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module test { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/access/src/test/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,377 @@ +/* + * 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 test; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * 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(); + Module targetModule = getTargetModule(); + + assertTrue(targetModule.isExported("p1")); + assertTrue(targetModule.isExported("p1", thisModule)); + assertTrue(targetModule.isExported("p1", targetModule)); + + assertFalse(targetModule.isOpen("p1")); + assertFalse(targetModule.isOpen("p1", thisModule)); + assertTrue(targetModule.isOpen("p1", targetModule)); + + Class<?> clazz = Class.forName("p1.Public"); + Constructor<?> ctor1 = clazz.getConstructor(); // public + Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public + + Field f1 = clazz.getField("f1"); // public + Field f2 = clazz.getDeclaredField("f2"); // non-public + + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public + + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, false); + trySetAccessible(m1, true); + trySetAccessible(m2, false); + trySetAccessible(f1, true); + trySetAccessible(f2, false); + + targetAddOpens("p1", thisModule); + + tryAccessConstructor(ctor1, true); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, true); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, true); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, true); + trySetAccessible(ctor2, true); + trySetAccessible(m1, true); + trySetAccessible(m2, true); + trySetAccessible(f1, true); + trySetAccessible(f2, true); + } + + static void testNonPublicClassInExportedPackage() throws Exception { + Module thisModule = Main.class.getModule(); + Module targetModule = getTargetModule(); + + assertTrue(targetModule.isExported("p2")); + assertTrue(targetModule.isExported("p2", thisModule)); + assertTrue(targetModule.isExported("p2", targetModule)); + + assertFalse(targetModule.isOpen("p2")); + assertFalse(targetModule.isOpen("p2", thisModule)); + assertTrue(targetModule.isOpen("p1", targetModule)); + + Class<?> clazz = Class.forName("p2.NonPublic"); + Constructor<?> ctor1 = clazz.getConstructor(); + Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class); + + Field f1 = clazz.getField("f1"); // public + Field f2 = clazz.getDeclaredField("f2"); // non-public + + Method m1 = clazz.getMethod("foo"); // public + Method m2 = clazz.getDeclaredMethod("bar"); // non-public + + tryAccessConstructor(ctor1, false); + tryAccessConstructor(ctor2, false); + tryAccessMethod(m1, false); + tryAccessMethod(m2, false); + tryAccessObjectField(f1, false); + tryAccessObjectField(f2, false); + + trySetAccessible(ctor1, false); + trySetAccessible(ctor2, false); + trySetAccessible(m1, false); + trySetAccessible(m2, false); + trySetAccessible(f1, false); + trySetAccessible(f2, false); + + targetAddExports("p2", thisModule); + + 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); + } + + + static Module getTargetModule() { + return ModuleLayer.boot().findModule("target").get(); + } + + static void tryAccessConstructor(Constructor<?> ctor, boolean shouldSucceed) { + try { + ctor.newInstance(); + assertTrue(shouldSucceed); + } catch (Exception e) { + assertFalse(shouldSucceed); + } + } + + static void tryAccessMethod(Method method, boolean shouldSucceed) { + try { + method.invoke(null); + assertTrue(shouldSucceed); + } catch (Exception e) { + e.printStackTrace(); + assertFalse(shouldSucceed); + } + } + + static void tryAccessObjectField(Field f, boolean shouldSucceed) { + try { + f.get(null); + assertTrue(shouldSucceed); + } catch (Exception e) { + assertFalse(shouldSucceed); + } + try { + f.set(null, new Object()); + assertTrue(shouldSucceed); + } 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("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(); + } + + static void assertFalse(boolean expr) { + assertTrue(!expr); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/Driver.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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/* m4/* + * @run testng/othervm test/test.Main + * @summary Basic test case for Module::addXXX methods + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m1/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module m1 { + exports p1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m1/p1/C.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p1; + +public class C { + public C() { } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m2/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p2; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m2/p2/C.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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; + +public class C { + + public static void export(String pn, Module m) { + C.class.getModule().addExports(pn, m); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m2/p2/internal/C.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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.internal; + +public class C { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m3/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module m3 { + exports p3 to test; + opens p3 to test; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m3/p3/C.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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; + +public class C { +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m4/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 m4 { + exports p4; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/m4/p4/C.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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; + +import java.lang.reflect.Constructor; + +public class C { + public static Object tryNewInstance(Class<?> clazz) throws Exception { + Constructor<?> ctor = clazz.getDeclaredConstructor(); + return ctor.newInstance(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/test/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module test { + exports test to testng; + + requires m2; + requires m3; + requires m4; + requires testng; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/test/test/C.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +public class C { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/test/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Basic test case for Module::addXXXX methods + */ + +@Test +public class Main { + + /** + * Test Module::addReads + * + * module test { } + * + * module m1 { + * exports p1; + * } + */ + public void testAddReads() throws Throwable { + Module thisModule = Main.class.getModule(); + Class<?> clazz = Class.forName("p1.C"); + Module m1 = clazz.getModule(); + + // test does not read m1 + assertFalse(thisModule.canRead(m1)); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class); + try { + lookup.findConstructor(clazz, mt); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // update test to read m1 + Module result = thisModule.addReads(m1); + assertTrue(result== thisModule); + assertTrue(thisModule.canRead(m1)); + MethodHandle mh = lookup.findConstructor(clazz, mt); + Object obj = mh.invoke(); + + // attempt to update m1 to read test + try { + m1.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + + /** + * Test Module::addExports + * + * module test { + * requires m2; + * } + * module m2 { + * exports p2; + * contains package p2.internal; + * } + */ + public void testAddExports() throws Exception { + Module thisModule = Main.class.getModule(); + Module m2 = p2.C.class.getModule(); + Class<?> targetClass = Class.forName("p2.internal.C"); + String p2Internal = targetClass.getPackageName(); + assertTrue(targetClass.getModule() == m2); + + // m2 does not export p2.internal to test + assertFalse(m2.isExported(p2Internal, thisModule)); + Constructor<?> ctor = targetClass.getDeclaredConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // update m2 to export p2.internal to test + p2.C.export(p2Internal, thisModule); + assertTrue(m2.isExported(p2Internal, thisModule)); + ctor.newInstance(); // should succeed + + // attempt to update m2 to export a package to test + try { + m2.addExports("p2.other", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + /** + * Test Module::addOpens + * + * module test { + * requires m3; + * requires m4; + * } + * + * module m3 { + * exports p3 to test; + * opens p3 to test; + * } + * + * module m4 { + * exports p4; + * } + */ + public void testAddOpens() throws Exception { + Module thisModule = Main.class.getModule(); + Module m3 = p3.C.class.getModule(); + Module m4 = p4.C.class.getModule(); + + // test does not open package test to m4 + assertFalse(thisModule.isOpen("test", m4)); + try { + p4.C.tryNewInstance(test.C.class); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // open test to m4 + thisModule.addOpens("test", m4); + p4.C.tryNewInstance(test.C.class); // should succeed + + + // m3 does not open p3 to m4 + assertFalse(m3.isOpen("p3", m4)); + try { + p4.C.tryNewInstance(p3.C.class); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + + // m3 opens p3 to test => test allowed to open m3/p3 to m4 + assertTrue(m3.isOpen("p3", thisModule)); + m3.addOpens("p3", m4); + assertTrue(m3.isOpen("p3", m4)); + p4.C.tryNewInstance(p3.C.class); // should succeed + + + // attempt to update m4 to open package to m3 + try { + m4.addOpens("p4", m3); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + + /** + * Test Module::addUses + */ + public void testAddUses() { + Module thisModule = Main.class.getModule(); + + assertFalse(thisModule.canUse(Service.class)); + try { + ServiceLoader.load(Service.class); + assertTrue(false); + } catch (ServiceConfigurationError expected) { } + + Module result = thisModule.addUses(Service.class); + assertTrue(result== thisModule); + + assertTrue(thisModule.canUse(Service.class)); + ServiceLoader.load(Service.class); // no exception + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/addXXX/test/test/Service.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +/** + * Simple service type + */ +public interface Service { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/allow.policy Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +grant { + permission java.lang.RuntimePermission "getClassLoader"; + permission java.lang.RuntimePermission "accessSystemModules"; + permission java.io.FilePermission "${java.home}/modules/-", "read"; // exploded build +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/annotation/Basic.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,76 @@ +/* + * 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.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)); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/annotation/src/m/module-info.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import p.annotation.*; + +@Foo +@Bar("bar") +@Baz({"one", "two", "three"}) +module m { + exports p.annotation; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/annotation/src/m/p/annotation/Bar.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.MODULE; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value={MODULE}) +public @interface Bar { + String value(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/annotation/src/m/p/annotation/Baz.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.MODULE; + +@Target(value={MODULE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Baz { + String[] value(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/ModuleTests/annotation/src/m/p/annotation/Foo.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p.annotation; + +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.MODULE; + +@Target(value={MODULE}) +public @interface Foo {}
--- a/test/java/lang/SecurityManager/CheckPackageAccess.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/SecurityManager/CheckPackageAccess.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,7 +33,6 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; -import java.lang.reflect.Layer; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -82,7 +81,7 @@ void test() { final boolean isModulePresent = - Layer.boot().findModule(moduleName).isPresent(); + ModuleLayer.boot().findModule(moduleName).isPresent(); System.out.format("Testing module: %1$s. Module is%2$s present.\n", moduleName, isModulePresent ? "" : " NOT");
--- a/test/java/lang/SecurityManager/CheckSecurityProvider.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/SecurityManager/CheckSecurityProvider.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ * @run main/othervm CheckSecurityProvider */ -import java.lang.reflect.Layer; import java.security.Provider; import java.security.Security; import java.util.ArrayList; @@ -45,7 +44,7 @@ */ public class CheckSecurityProvider { public static void main(String[] args) throws Exception { - Layer layer = Layer.boot(); + ModuleLayer layer = ModuleLayer.boot(); System.setSecurityManager(new SecurityManager());
--- a/test/java/lang/SecurityManager/modules/Test.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/SecurityManager/modules/Test.java Fri Apr 07 08:05:54 2017 +0000 @@ -21,8 +21,6 @@ * questions. */ -import java.lang.reflect.Module; - public class Test { public static void main(String... args) { SecurityManager sm = System.getSecurityManager();
--- a/test/java/lang/StackTraceElement/PublicConstructor.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/StackTraceElement/PublicConstructor.java Fri Apr 07 08:05:54 2017 +0000 @@ -29,7 +29,6 @@ */ import java.lang.module.ModuleDescriptor; -import java.lang.reflect.Module; public class PublicConstructor { public static void main(String... args) {
--- a/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/StackTraceElement/lib/m1/com/app/Utils.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ import java.lang.StackWalker.StackFrame; import java.lang.module.ModuleDescriptor; -import java.lang.reflect.Module; import java.util.Objects; public class Utils {
--- a/test/java/lang/System/Logger/custom/CustomLoggerTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/Logger/custom/CustomLoggerTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -46,7 +46,6 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.stream.Stream; -import java.lang.reflect.Module; import java.security.AllPermission; /**
--- a/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/BaseLoggerFinder.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ import java.security.PrivilegedAction; import java.lang.System.LoggerFinder; import java.lang.System.Logger; -import java.lang.reflect.Module; public class BaseLoggerFinder extends LoggerFinder implements TestLoggerFinder {
--- a/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/BaseLoggerFinderTest/TestLoggerFinder.java Fri Apr 07 08:05:54 2017 +0000 @@ -30,7 +30,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; import java.lang.System.Logger; -import java.lang.reflect.Module; /** * What our test provider needs to implement.
--- a/test/java/lang/System/LoggerFinder/LoggerFinderAPI/LoggerFinderAPI.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/LoggerFinderAPI/LoggerFinderAPI.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.lang.System.LoggerFinder; -import java.lang.reflect.Module; import java.util.Enumeration; import java.util.Locale; import java.util.Objects;
--- a/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/BaseDefaultLoggerFinderTest/BaseDefaultLoggerFinderTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -55,7 +55,6 @@ import jdk.internal.logger.DefaultLoggerFinder; import jdk.internal.logger.SimpleConsoleLogger; import sun.util.logging.PlatformLogger; -import java.lang.reflect.Module; /** * @test
--- a/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/BaseLoggerBridgeTest/BaseLoggerBridgeTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -47,7 +47,6 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.util.stream.Stream; -import java.lang.reflect.Module; /** * @test
--- a/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/BasePlatformLoggerTest/BasePlatformLoggerTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -47,7 +47,6 @@ import java.security.AccessControlException; import java.util.stream.Stream; import sun.util.logging.PlatformLogger; -import java.lang.reflect.Module; /** * @test
--- a/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -30,7 +30,6 @@ import java.util.List; import java.util.ResourceBundle; import java.util.Set; -import java.lang.reflect.Module; import jdk.internal.logger.BootstrapLogger; import jdk.internal.logger.LazyLoggers;
--- a/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -43,7 +43,6 @@ import java.util.stream.Stream; import jdk.internal.logger.BootstrapLogger; import jdk.internal.logger.LazyLoggers; -import java.lang.reflect.Module; /* * @test
--- a/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/LoggerBridgeTest/LoggerBridgeTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -51,7 +51,6 @@ import java.lang.System.Logger.Level; import java.util.stream.Stream; import sun.util.logging.PlatformLogger; -import java.lang.reflect.Module; /** * @test
--- a/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -53,7 +53,6 @@ import java.util.ServiceLoader; import java.util.concurrent.atomic.AtomicReference; import jdk.internal.logger.SimpleConsoleLogger; -import java.lang.reflect.Module; /** * @test
--- a/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/PlatformLoggerBridgeTest/PlatformLoggerBridgeTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -49,7 +49,6 @@ import java.lang.System.Logger.Level; import java.util.stream.Stream; import sun.util.logging.PlatformLogger; -import java.lang.reflect.Module; /** * @test
--- a/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Layer; import java.lang.reflect.Method; /* @@ -106,7 +105,7 @@ } Class<?> platformLoggerType = platformLogger.getClass(); System.out.println("platformLogger: " + platformLoggerType); - boolean simpleConsoleOnly = !Layer.boot().findModule("java.logging").isPresent(); + boolean simpleConsoleOnly = !ModuleLayer.boot().findModule("java.logging").isPresent(); if (simpleConsoleOnly) { /* Happens if the test is called with custom JDK without java.logging module or in case usage commandline option --limit-modules java.base */
--- a/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -78,7 +78,6 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; import sun.util.logging.internal.LoggingProviderImpl; -import java.lang.reflect.Module; /** * @author danielfuchs
--- a/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/System/LoggerFinder/jdk/DefaultLoggerBridgeTest/DefaultLoggerBridgeTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -48,7 +48,6 @@ import java.lang.System.Logger; import java.util.stream.Stream; import sun.util.logging.internal.LoggingProviderImpl; -import java.lang.reflect.Module; /** * @test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/WeakPairMap/Driver.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8888888 + * @summary Functional test for WeakPairMap + * @build java.base/java.lang.WeakPairMapTest + * @run main Driver + */ +public class Driver { + public static void main(String[] args) { + java.lang.WeakPairMapTest.main(args); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/lang/WeakPairMap/java.base/java/lang/WeakPairMapTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.ref.Reference; +import java.util.Objects; + +/** + * Functional test for WeakPairMap + * + * @author Peter Levart + */ +public class WeakPairMapTest { + public static void main(String[] args) { + WeakPairMap<Object, Object, String> pm = new WeakPairMap<>(); + Object key1 = new Object(); + Object key2 = new Object(); + + // check for emptiness + assertEquals(pm.containsKeyPair(key1, key2), false); + assertEquals(pm.get(key1, key2), null); + + // check for NPE(s) + for (Object k1 : new Object[]{null, key1}) { + for (Object k2 : new Object[]{null, key2}) { + for (String v : new String[]{null, "abc"}) { + + if (k1 != null && k2 != null && v != null) { + // skip non-null args + continue; + } + + try { + pm.put(k1, k2, v); + throw new AssertionError("Unexpected code path, k1=" + + k1 + ", k2=" + k2 + ", v=" + v); + } catch (NullPointerException e) { + // expected + } + + try { + pm.putIfAbsent(k1, k2, v); + throw new AssertionError("Unexpected code path, k1=" + + k1 + ", k2=" + k2 + ", v=" + v); + } catch (NullPointerException e) { + // expected + } + + if (k1 != null && k2 != null) { + // skip non-null args + continue; + } + + try { + pm.computeIfAbsent(k1, k2, (_k1, _k2) -> v); + throw new AssertionError("Unexpected code path, k1=" + + k1 + ", k2=" + k2 + ", v=" + v); + } catch (NullPointerException e) { + // expected + } + + try { + pm.containsKeyPair(k1, k2); + throw new AssertionError("Unexpected code path, k1=" + + k1 + ", k2=" + k2); + } catch (NullPointerException e) { + // expected + } + + try { + pm.get(k1, k2); + throw new AssertionError("Unexpected code path, k1=" + + k1 + ", k2=" + k2); + } catch (NullPointerException e) { + // expected + } + } + } + } + + // how much to wait when it is expected for entry to be retained + final long retentionTimeout = 500L; + // how much to wait when it is expected for entry to be removed + final long cleanupTimeout = 30_000L; + + // check insertion + assertEquals(pm.putIfAbsent(key1, key2, "abc"), null); + assertEquals(pm.get(key1, key2), "abc"); + + // check retention while both keys are still reachable + assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false); + assertEquals(pm.get(key1, key2), "abc"); + + // check cleanup when both keys are unreachable + key1 = null; + key2 = null; + assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true); + + // new insertion + key1 = new Object(); + key2 = new Object(); + assertEquals(pm.putIfAbsent(key1, key2, "abc"), null); + assertEquals(pm.get(key1, key2), "abc"); + + // check retention while both keys are still reachable + assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false); + assertEquals(pm.get(key1, key2), "abc"); + + // check cleanup when 1st key is unreachable + key1 = null; + assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true); + Reference.reachabilityFence(key2); + + // new insertion + key1 = new Object(); + key2 = new Object(); + assertEquals(pm.putIfAbsent(key1, key2, "abc"), null); + assertEquals(pm.get(key1, key2), "abc"); + + // check retention while both keys are still reachable + assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false); + assertEquals(pm.get(key1, key2), "abc"); + + // check cleanup when 2nd key is unreachable + key2 = null; + assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true); + Reference.reachabilityFence(key1); + } + + /** + * Trigger GC and wait for at most {@code millis} ms for given value to + * be removed from given WeakPairMap. + * + * @return true if element has been removed or false if not + */ + static <V> boolean gcAndWaitRemoved(WeakPairMap<?, ?, V> pm, V value, + long millis) { + System.gc(); + for (int i = 0; i < (millis + 99) / 100 && pm.values().contains(value); i++) { + try { + Thread.sleep(100L); + } catch (InterruptedException e) { + throw new AssertionError("Interrupted"); + } + } + return !pm.values().contains(value); + } + + static void assertEquals(Object actual, Object expected) { + if (!Objects.equals(actual, expected)) { + throw new AssertionError("Expected: " + expected + ", actual: " + actual); + } + } +}
--- a/test/java/lang/instrument/ATransformerManagementTestCase.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/ATransformerManagementTestCase.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,8 +24,6 @@ import java.io.*; import java.lang.instrument.*; - -import java.lang.reflect.Module; import java.security.ProtectionDomain; import java.util.*;
--- a/test/java/lang/instrument/BootstrapClassPathAgent.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/BootstrapClassPathAgent.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ import java.io.*; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; -import java.lang.reflect.Module; import java.security.ProtectionDomain; public class BootstrapClassPathAgent {
--- a/test/java/lang/instrument/BootstrapClassPathTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/BootstrapClassPathTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,7 +33,6 @@ import java.io.*; import java.lang.instrument.*; -import java.lang.reflect.Module; import java.security.ProtectionDomain; public class BootstrapClassPathTest {
--- a/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ import java.io.InputStream; import java.lang.instrument.ClassDefinition; import java.lang.instrument.Instrumentation; -import java.lang.reflect.Module; import java.util.Timer; import java.util.TimerTask;
--- a/test/java/lang/instrument/RedefineModuleAgent.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/RedefineModuleAgent.java Fri Apr 07 08:05:54 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +22,6 @@ */ import java.lang.instrument.Instrumentation; -import java.lang.reflect.Module; import java.util.List; import java.util.Map; import java.util.Set; @@ -47,4 +46,8 @@ Map<Class<?>, List<Class<?>>> extraProvides) { inst.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides); } + + static boolean isModifiableModule(Module module) { + return inst.isModifiableModule(module); + } }
--- a/test/java/lang/instrument/RedefineModuleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/RedefineModuleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,6 @@ 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; @@ -68,6 +66,10 @@ extraProvides); } + static boolean isModifiableModule(Module module) { + return RedefineModuleAgent.isModifiableModule(module); + } + /** * Use redefineModule to update java.base to read java.instrument @@ -138,13 +140,13 @@ // pre-conditions assertFalse(baseModule.canUse(service)); assertTrue(collect(ServiceLoader.load(service)).isEmpty()); - assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty()); + assertTrue(collect(ServiceLoader.load(ModuleLayer.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()); + assertTrue(collect(ServiceLoader.load(ModuleLayer.boot(), service)).isEmpty()); // update java.base to provide an implementation of TestProvider Class<?> type1 = Class.forName("jdk.internal.test.TestProviderImpl1"); @@ -162,7 +164,7 @@ assertTrue(containsInstanceOf(collect(providers), type1)); // use ServiceLoader to load implementations in the boot layer - providers = collect(ServiceLoader.load(Layer.boot(), service)); + providers = collect(ServiceLoader.load(ModuleLayer.boot(), service)); assertTrue(collect(providers).size() == 1); assertTrue(containsInstanceOf(collect(providers), type1)); @@ -184,7 +186,7 @@ assertTrue(containsInstanceOf(providers, type2)); // use ServiceLoader to load implementations in the boot layer - providers = collect(ServiceLoader.load(Layer.boot(), service)); + providers = collect(ServiceLoader.load(ModuleLayer.boot(), service)); assertTrue(collect(providers).size() == 2); assertTrue(containsInstanceOf(providers, type1)); assertTrue(containsInstanceOf(providers, type2)); @@ -279,6 +281,19 @@ } /** + * Exercise IsModifiableModule + */ + @Test + public void testIsModifiableModule() { + ClassLoader pcl = ClassLoader.getPlatformClassLoader(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + assertTrue(isModifiableModule(pcl.getUnnamedModule())); + assertTrue(isModifiableModule(scl.getUnnamedModule())); + assertTrue(isModifiableModule(RedefineModuleTest.class.getModule())); + assertTrue(isModifiableModule(Object.class.getModule())); + } + + /** * Test redefineClass with null */ public void testNulls() {
--- a/test/java/lang/instrument/RetransformAgent.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/RetransformAgent.java Fri Apr 07 08:05:54 2017 +0000 @@ -34,7 +34,6 @@ */ import java.lang.instrument.*; -import java.lang.reflect.Module; import java.security.ProtectionDomain; import java.io.*; import asmlib.*;
--- a/test/java/lang/instrument/SimpleIdentityTransformer.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/instrument/SimpleIdentityTransformer.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ import java.lang.instrument.Instrumentation; import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.Module; import java.security.*; /*
--- a/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ 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.*;
--- a/test/java/lang/invoke/modules/m1/p1/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/invoke/modules/m1/p1/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,8 +27,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import static java.lang.invoke.MethodHandles.Lookup.*; @@ -64,14 +62,14 @@ } // check setup - Module m1 = Layer.boot().findModule("m1").orElse(null); + Module m1 = ModuleLayer.boot().findModule("m1").orElse(null); assertNotNull(m1); assertTrue(p1_Type1.getModule() == m1); assertTrue(p2_Type2.getModule() == m1); assertTrue(m1.isExported("p1")); assertFalse(m1.isExported("p2")); - Module m2 = Layer.boot().findModule("m2").orElse(null); + Module m2 = ModuleLayer.boot().findModule("m2").orElse(null); assertNotNull(m2); assertTrue(q1_Type1.getModule() == m2); assertTrue(q2_Type2.getModule() == m2);
--- a/test/java/lang/module/AutomaticModulesTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/module/AutomaticModulesTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -38,8 +38,6 @@ import java.lang.module.ModuleReference; import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -69,13 +67,8 @@ { "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" }, + { "foo1.jar", "foo1" }, + { "foo10.jar", "foo10" }, { "foo-1.jar", "foo/1" }, { "foo-1.2.jar", "foo/1.2" }, @@ -93,6 +86,9 @@ { "foo-bar-10.jar", "foo.bar/10" }, { "foo-bar-10.20.jar", "foo.bar/10.20" }, + { "foo.bar1.jar", "foo.bar1" }, + { "foo.bar10.jar", "foo.bar10" }, + { "foo-1.2-SNAPSHOT.jar", "foo/1.2-SNAPSHOT" }, { "foo-bar-1.2-SNAPSHOT.jar", "foo.bar/1.2-SNAPSHOT" }, @@ -108,8 +104,12 @@ public Object[][] createBadNames() { return new Object[][]{ - { ".jar", null }, - { "_.jar", null } + { ".jar", null }, + { "_.jar", null }, + + { "foo.1.jar", null }, + { "1foo.jar", null }, + { "foo.1bar.jar", null }, }; } @@ -389,7 +389,7 @@ ModuleFinder finder = ModuleFinder.of(dir); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); Configuration cf = resolve(parent, finder, "m"); ModuleDescriptor descriptor = findDescriptor(cf, "m"); @@ -469,11 +469,11 @@ createDummyJarFile(dir.resolve("c.jar"), "q/T.class"); // module finder locates a and the modules in the directory - ModuleFinder finder - = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1), - ModuleFinder.of(dir)); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + ModuleFinder finder2 = ModuleFinder.of(dir); + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); Configuration cf = resolve(parent, finder, "a"); assertTrue(cf.modules().size() == 3); @@ -482,7 +482,7 @@ assertTrue(cf.findModule("c").isPresent()); ResolvedModule base = cf.findModule("java.base").get(); - assertTrue(base.configuration() == Layer.boot().configuration()); + assertTrue(base.configuration() == ModuleLayer.boot().configuration()); ResolvedModule a = cf.findModule("a").get(); ResolvedModule b = cf.findModule("b").get(); ResolvedModule c = cf.findModule("c").get(); @@ -534,11 +534,11 @@ createDummyJarFile(dir.resolve("d.jar"), "q/T.class"); // module finder locates a and the modules in the directory - ModuleFinder finder - = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), - ModuleFinder.of(dir)); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + ModuleFinder finder2 = ModuleFinder.of(dir); + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); Configuration cf = resolve(parent, finder, "a", "d"); assertTrue(cf.modules().size() == 4); @@ -554,7 +554,7 @@ // readability ResolvedModule base = cf.findModule("java.base").get(); - assertTrue(base.configuration() == Layer.boot().configuration()); + assertTrue(base.configuration() == ModuleLayer.boot().configuration()); ResolvedModule a = cf.findModule("a").get(); ResolvedModule b = cf.findModule("b").get(); ResolvedModule c = cf.findModule("c").get(); @@ -607,11 +607,11 @@ createDummyJarFile(dir.resolve("d.jar"), "q/T.class"); // module finder locates a and the modules in the directory - ModuleFinder finder - = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), - ModuleFinder.of(dir)); + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + ModuleFinder finder2 = ModuleFinder.of(dir); + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); Configuration cf = resolve(parent, finder, "a", "d"); assertTrue(cf.modules().size() == 4); @@ -621,7 +621,7 @@ assertTrue(cf.findModule("d").isPresent()); ResolvedModule base = cf.findModule("java.base").get(); - assertTrue(base.configuration() == Layer.boot().configuration()); + assertTrue(base.configuration() == ModuleLayer.boot().configuration()); ResolvedModule a = cf.findModule("a").get(); ResolvedModule b = cf.findModule("b").get(); ResolvedModule c = cf.findModule("c").get(); @@ -661,6 +661,189 @@ /** + * Basic test to ensure that no automatic modules are resolved when + * an automatic module is not a root or required by other modules. + */ + public void testInConfiguration4() throws IOException { + ModuleDescriptor descriptor1 + = ModuleDescriptor.newModule("m1") + .requires("java.base") + .build(); + + // automatic modules + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class"); + createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class"); + createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class"); + + // module finder locates m1 and the modules in the directory + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + ModuleFinder finder2 = ModuleFinder.of(dir); + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + + // ensure that no automatic module is resolved + assertTrue(cf.modules().size() == 1); + assertTrue(cf.findModule("m1").isPresent()); + } + + + /** + * Basic test to ensure that if an automatic module is resolved then + * all observable automatic modules are resolved. + */ + public void testInConfiguration5() throws IOException { + // m1 requires m2 + ModuleDescriptor descriptor1 + = ModuleDescriptor.newModule("m1") + .requires("m2").build(); + + // m2 requires automatic module + ModuleDescriptor descriptor2 + = ModuleDescriptor.newModule("m2") + .requires("auto1") + .build(); + + // automatic modules + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class"); + createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class"); + createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class"); + + // module finder locates m1, m2, and the modules in the directory + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + ModuleFinder finder2 = ModuleFinder.of(dir); + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + + // all automatic modules should be resolved + assertTrue(cf.modules().size() == 5); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("auto1").isPresent()); + assertTrue(cf.findModule("auto2").isPresent()); + assertTrue(cf.findModule("auto3").isPresent()); + + ResolvedModule base = parent.findModule("java.base") + .orElseThrow(() -> new RuntimeException()); + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule auto1 = cf.findModule("auto1").get(); + ResolvedModule auto2 = cf.findModule("auto2").get(); + ResolvedModule auto3 = cf.findModule("auto3").get(); + + // m1 does not read the automatic modules + assertTrue(m1.reads().size() == 2); + assertTrue(m1.reads().contains(m2)); + assertTrue(m1.reads().contains(base)); + + // m2 should read all the automatic modules + assertTrue(m2.reads().size() == 4); + assertTrue(m2.reads().contains(auto1)); + assertTrue(m2.reads().contains(auto2)); + assertTrue(m2.reads().contains(auto3)); + assertTrue(m2.reads().contains(base)); + + assertTrue(auto1.reads().contains(m1)); + assertTrue(auto1.reads().contains(m2)); + assertTrue(auto1.reads().contains(auto2)); + assertTrue(auto1.reads().contains(auto3)); + assertTrue(auto1.reads().contains(base)); + + assertTrue(auto2.reads().contains(m1)); + assertTrue(auto2.reads().contains(m2)); + assertTrue(auto2.reads().contains(auto1)); + assertTrue(auto2.reads().contains(auto3)); + assertTrue(auto2.reads().contains(base)); + + assertTrue(auto3.reads().contains(m1)); + assertTrue(auto3.reads().contains(m2)); + assertTrue(auto3.reads().contains(auto1)); + assertTrue(auto3.reads().contains(auto2)); + assertTrue(auto3.reads().contains(base)); + } + + + /** + * Basic test of automatic modules in a child configuration. All automatic + * modules that are found with the before finder should be resolved. The + * automatic modules that are found by the after finder and not shadowed + * by the before finder, or parent configurations, should also be resolved. + */ + public void testInConfiguration6() throws IOException { + // m1 requires auto1 + ModuleDescriptor descriptor1 + = ModuleDescriptor.newModule("m1") + .requires("auto1") + .build(); + + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class"); + + // module finder locates m1 and auto1 + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + ModuleFinder finder2 = ModuleFinder.of(dir); + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); + + Configuration parent = ModuleLayer.boot().configuration(); + Configuration cf1 = resolve(parent, finder, "m1"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("auto1").isPresent()); + + ResolvedModule base = parent.findModule("java.base") + .orElseThrow(() -> new RuntimeException()); + ResolvedModule m1 = cf1.findModule("m1").get(); + ResolvedModule auto1 = cf1.findModule("auto1").get(); + + assertTrue(m1.reads().size() == 2); + assertTrue(m1.reads().contains(auto1)); + assertTrue(m1.reads().contains(base)); + + assertTrue(auto1.reads().contains(m1)); + assertTrue(auto1.reads().contains(base)); + + + // create child configuration - the after finder locates auto1 + + dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class"); + ModuleFinder beforeFinder = ModuleFinder.of(dir); + + dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class"); + createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class"); + createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class"); + ModuleFinder afterFinder = ModuleFinder.of(dir); + + Configuration cf2 = cf1.resolve(beforeFinder, afterFinder, Set.of("auto2")); + + // auto1 should be found in parent and should not be in cf2 + assertTrue(cf2.modules().size() == 2); + assertTrue(cf2.findModule("auto2").isPresent()); + assertTrue(cf2.findModule("auto3").isPresent()); + + ResolvedModule auto2 = cf2.findModule("auto2").get(); + ResolvedModule auto3 = cf2.findModule("auto3").get(); + + assertTrue(auto2.reads().contains(m1)); + assertTrue(auto2.reads().contains(auto1)); + assertTrue(auto2.reads().contains(auto3)); + assertTrue(auto2.reads().contains(base)); + + assertTrue(auto3.reads().contains(m1)); + assertTrue(auto3.reads().contains(auto1)); + assertTrue(auto3.reads().contains(auto2)); + assertTrue(auto3.reads().contains(base)); + } + + + /** * Basic test of a configuration created with automatic modules * a requires b* and c* * b* contains p @@ -684,7 +867,7 @@ = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), ModuleFinder.of(dir)); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); resolve(parent, finder, "a"); } @@ -711,13 +894,13 @@ = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), ModuleFinder.of(dir)); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); resolve(parent, finder, "a"); } /** - * Basic test of Layer containing automatic modules + * Basic test of layer containing automatic modules */ public void testInLayer() throws IOException { ModuleDescriptor descriptor @@ -736,12 +919,12 @@ = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), ModuleFinder.of(dir)); - Configuration parent = Layer.boot().configuration(); + Configuration parent = ModuleLayer.boot().configuration(); Configuration cf = resolve(parent, finder, "a"); assertTrue(cf.modules().size() == 3); // each module gets its own loader - Layer layer = Layer.boot().defineModules(cf, mn -> new ClassLoader() { }); + ModuleLayer layer = ModuleLayer.boot().defineModules(cf, mn -> new ClassLoader() { }); // an unnamed module Module unnamed = (new ClassLoader() { }).getUnnamedModule(); @@ -804,7 +987,7 @@ */ static void testReadAllBootModules(Configuration cf, String mn) { - Set<String> bootModules = Layer.boot().modules().stream() + Set<String> bootModules = ModuleLayer.boot().modules().stream() .map(Module::getName) .collect(Collectors.toSet()); @@ -813,10 +996,10 @@ } /** - * Test that the given Module reads all module in the given Layer - * and its parent Layers. + * Test that the given Module reads all module in the given layer + * and its parent layers. */ - static void testsReadsAll(Module m, Layer layer) { + static void testsReadsAll(Module m, ModuleLayer layer) { // check that m reads all modules in the layer layer.configuration().modules().stream() .map(ResolvedModule::name)
--- a/test/java/lang/module/ConfigurationTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/module/ConfigurationTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -40,7 +40,6 @@ import java.lang.module.ModuleFinder; import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -1708,7 +1707,7 @@ ModuleFinder finder = ModuleUtils.finderOf(descriptor); - Configuration bootConfiguration = Layer.boot().configuration(); + Configuration bootConfiguration = ModuleLayer.boot().configuration(); // m1 contains package java.lang, java.base exports package java.lang to m1 resolve(bootConfiguration, finder, "m1"); @@ -1989,14 +1988,14 @@ @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull5() { - Configuration cf = Layer.boot().configuration(); + Configuration cf = ModuleLayer.boot().configuration(); Configuration.resolve(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 cf = ModuleLayer.boot().configuration(); Configuration.resolve(empty, List.of(cf), empty, null); } @@ -2024,14 +2023,14 @@ @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull5() { - Configuration cf = Layer.boot().configuration(); + Configuration cf = ModuleLayer.boot().configuration(); Configuration.resolveAndBind(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 cf = ModuleLayer.boot().configuration(); Configuration.resolveAndBind(empty, List.of(cf), empty, null); } @@ -2044,14 +2043,14 @@ @Test(expectedExceptions = { UnsupportedOperationException.class }) public void testImmutableSet1() { - Configuration cf = Layer.boot().configuration(); + Configuration cf = ModuleLayer.boot().configuration(); ResolvedModule base = cf.findModule("java.base").get(); cf.modules().add(base); } @Test(expectedExceptions = { UnsupportedOperationException.class }) public void testImmutableSet2() { - Configuration cf = Layer.boot().configuration(); + Configuration cf = ModuleLayer.boot().configuration(); ResolvedModule base = cf.findModule("java.base").get(); base.reads().add(base); }
--- a/test/java/lang/module/ModuleDescriptorTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/module/ModuleDescriptorTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -41,7 +41,6 @@ import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleDescriptor.Version; -import java.lang.reflect.Module; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections;
--- a/test/java/lang/module/ModuleFinderTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/module/ModuleFinderTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -529,6 +529,30 @@ /** + * Test ModuleFinder.of with a directory containing hidden files + */ + public void testOfWithHiddenFiles() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createExplodedModule(dir.resolve("m"), "m", + "com/.ignore", + "com/foo/.ignore", + "com/foo/foo.properties"); + + ModuleFinder finder = ModuleFinder.of(dir); + ModuleReference mref = finder.find("m").orElse(null); + assertNotNull(mref); + + Set<String> expectedPackages; + if (System.getProperty("os.name").startsWith("Windows")) { + expectedPackages = Set.of("com", "com.foo"); + } else { + expectedPackages = Set.of("com.foo"); + } + assertEquals(mref.descriptor().packages(), expectedPackages); + } + + + /** * Test ModuleFinder.of with a truncated module-info.class */ public void testOfWithTruncatedModuleInfo() throws Exception {
--- a/test/java/lang/module/ModuleReader/ModuleReaderTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/module/ModuleReader/ModuleReaderTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -37,7 +37,6 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; -import java.lang.reflect.Module; import java.net.URI; import java.net.URL; import java.net.URLConnection;
--- a/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -36,7 +36,6 @@ import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Module; import jdk.internal.misc.Unsafe;
--- a/test/java/lang/reflect/Layer/BasicLayerTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1219 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * 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 java.base/jdk.internal.misc - * @build BasicLayerTest ModuleUtils - * @compile layertest/Test.java - * @run testng BasicLayerTest - * @summary Basic tests for java.lang.reflect.Layer - */ - -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; - -import jdk.internal.misc.SharedSecrets; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -@Test -public class BasicLayerTest { - - /** - * Creates a "non-strict" builder for building a module. This allows the - * test the create ModuleDescriptor objects that do not require java.base. - */ - private static ModuleDescriptor.Builder newBuilder(String mn) { - return SharedSecrets.getJavaLangModuleAccess() - .newModuleBuilder(mn, false, Set.of()); - } - - /** - * Exercise Layer.empty() - */ - public void testEmpty() { - Layer emptyLayer = Layer.empty(); - - assertTrue(emptyLayer.parents().isEmpty()); - - assertTrue(emptyLayer.configuration() == Configuration.empty()); - - assertTrue(emptyLayer.modules().isEmpty()); - - assertFalse(emptyLayer.findModule("java.base").isPresent()); - - try { - emptyLayer.findLoader("java.base"); - assertTrue(false); - } catch (IllegalArgumentException expected) { } - } - - - /** - * Exercise Layer.boot() - */ - public void testBoot() { - Layer bootLayer = Layer.boot(); - - // configuration - Configuration cf = bootLayer.configuration(); - assertTrue(cf.findModule("java.base").get() - .reference() - .descriptor() - .exports() - .stream().anyMatch(e -> (e.source().equals("java.lang") - && !e.isQualified()))); - - // modules - Set<Module> modules = bootLayer.modules(); - assertTrue(modules.contains(Object.class.getModule())); - int count = (int) modules.stream().map(Module::getName).count(); - assertEquals(count, modules.size()); // module names are unique - - // findModule - Module base = Object.class.getModule(); - assertTrue(bootLayer.findModule("java.base").get() == base); - assertTrue(base.getLayer() == bootLayer); - - // findLoader - assertTrue(bootLayer.findLoader("java.base") == null); - - // parents - assertTrue(bootLayer.parents().size() == 1); - assertTrue(bootLayer.parents().get(0) == Layer.empty()); - } - - - /** - * Exercise Layer defineModules, created with empty layer as parent - */ - public void testLayerOnEmpty() { - ModuleDescriptor descriptor1 = newBuilder("m1") - .requires("m2") - .exports("p1") - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires("m3") - .build(); - - ModuleDescriptor descriptor3 = newBuilder("m3") - .build(); - - ModuleFinder finder - = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - - Configuration cf = resolve(finder, "m1"); - - // map each module to its own class loader for this test - ClassLoader loader1 = new ClassLoader() { }; - ClassLoader loader2 = new ClassLoader() { }; - ClassLoader loader3 = new ClassLoader() { }; - Map<String, ClassLoader> map = new HashMap<>(); - map.put("m1", loader1); - map.put("m2", loader2); - map.put("m3", loader3); - - Layer layer = Layer.empty().defineModules(cf, map::get); - - // configuration - assertTrue(layer.configuration() == cf); - assertTrue(layer.configuration().modules().size() == 3); - - // modules - Set<Module> modules = layer.modules(); - assertTrue(modules.size() == 3); - Set<String> names = modules.stream() - .map(Module::getName) - .collect(Collectors.toSet()); - assertTrue(names.contains("m1")); - assertTrue(names.contains("m2")); - assertTrue(names.contains("m3")); - - // findModule - Module m1 = layer.findModule("m1").get(); - Module m2 = layer.findModule("m2").get(); - Module m3 = layer.findModule("m3").get(); - assertEquals(m1.getName(), "m1"); - assertEquals(m2.getName(), "m2"); - assertEquals(m3.getName(), "m3"); - assertTrue(m1.getDescriptor() == descriptor1); - assertTrue(m2.getDescriptor() == descriptor2); - assertTrue(m3.getDescriptor() == descriptor3); - assertTrue(m1.getLayer() == layer); - assertTrue(m2.getLayer() == layer); - assertTrue(m3.getLayer() == layer); - assertTrue(modules.contains(m1)); - assertTrue(modules.contains(m2)); - assertTrue(modules.contains(m3)); - assertFalse(layer.findModule("godot").isPresent()); - - // findLoader - assertTrue(layer.findLoader("m1") == loader1); - assertTrue(layer.findLoader("m2") == loader2); - assertTrue(layer.findLoader("m3") == loader3); - try { - ClassLoader loader = layer.findLoader("godot"); - assertTrue(false); - } catch (IllegalArgumentException ignore) { } - - // parents - assertTrue(layer.parents().size() == 1); - assertTrue(layer.parents().get(0) == Layer.empty()); - } - - - /** - * Exercise Layer defineModules, created with boot layer as parent - */ - public void testLayerOnBoot() { - ModuleDescriptor descriptor1 = newBuilder("m1") - .requires("m2") - .requires("java.base") - .exports("p1") - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires("java.base") - .build(); - - ModuleFinder finder - = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration parent = Layer.boot().configuration(); - Configuration cf = resolve(parent, finder, "m1"); - - ClassLoader loader = new ClassLoader() { }; - - Layer layer = Layer.boot().defineModules(cf, mn -> loader); - - // configuration - assertTrue(layer.configuration() == cf); - assertTrue(layer.configuration().modules().size() == 2); - - // modules - Set<Module> modules = layer.modules(); - assertTrue(modules.size() == 2); - Set<String> names = modules.stream() - .map(Module::getName) - .collect(Collectors.toSet()); - assertTrue(names.contains("m1")); - assertTrue(names.contains("m2")); - - // findModule - Module m1 = layer.findModule("m1").get(); - Module m2 = layer.findModule("m2").get(); - assertEquals(m1.getName(), "m1"); - assertEquals(m2.getName(), "m2"); - assertTrue(m1.getDescriptor() == descriptor1); - assertTrue(m2.getDescriptor() == descriptor2); - assertTrue(m1.getLayer() == layer); - assertTrue(m2.getLayer() == layer); - assertTrue(modules.contains(m1)); - assertTrue(modules.contains(m2)); - assertTrue(layer.findModule("java.base").get() == Object.class.getModule()); - assertFalse(layer.findModule("godot").isPresent()); - - // findLoader - assertTrue(layer.findLoader("m1") == loader); - assertTrue(layer.findLoader("m2") == loader); - assertTrue(layer.findLoader("java.base") == null); - - // parents - assertTrue(layer.parents().size() == 1); - assertTrue(layer.parents().get(0) == Layer.boot()); - } - - - /** - * Exercise Layer defineModules with a configuration of two modules that - * have the same module-private package. - */ - public void testPackageContainedInSelfAndOther() { - ModuleDescriptor descriptor1 = newBuilder("m1") - .requires("m2") - .packages(Set.of("p")) - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .packages(Set.of("p")) - .build(); - - ModuleFinder finder - = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf = resolve(finder, "m1"); - assertTrue(cf.modules().size() == 2); - - // one loader per module, should be okay - Layer.empty().defineModules(cf, mn -> new ClassLoader() { }); - - // same class loader - try { - ClassLoader loader = new ClassLoader() { }; - Layer.empty().defineModules(cf, mn -> loader); - assertTrue(false); - } catch (LayerInstantiationException expected) { } - } - - - /** - * Exercise Layer defineModules with a configuration that is a partitioned - * graph. The same package is exported in both partitions. - */ - public void testSameExportInPartitionedGraph() { - - // m1 reads m2, m2 exports p to m1 - ModuleDescriptor descriptor1 = newBuilder("m1") - .requires("m2") - .build(); - ModuleDescriptor descriptor2 = newBuilder("m2") - .exports("p", Set.of("m1")) - .build(); - - // m3 reads m4, m4 exports p to m3 - ModuleDescriptor descriptor3 = newBuilder("m3") - .requires("m4") - .build(); - ModuleDescriptor descriptor4 = newBuilder("m4") - .exports("p", Set.of("m3")) - .build(); - - ModuleFinder finder - = ModuleUtils.finderOf(descriptor1, - descriptor2, - descriptor3, - descriptor4); - - Configuration cf = resolve(finder, "m1", "m3"); - assertTrue(cf.modules().size() == 4); - - // one loader per module - Layer.empty().defineModules(cf, mn -> new ClassLoader() { }); - - // m1 & m2 in one loader, m3 & m4 in another loader - ClassLoader loader1 = new ClassLoader() { }; - ClassLoader loader2 = new ClassLoader() { }; - Map<String, ClassLoader> map = new HashMap<>(); - map.put("m1", loader1); - map.put("m2", loader1); - map.put("m3", loader2); - map.put("m4", loader2); - Layer.empty().defineModules(cf, map::get); - - // same loader - try { - ClassLoader loader = new ClassLoader() { }; - Layer.empty().defineModules(cf, mn -> loader); - assertTrue(false); - } catch (LayerInstantiationException expected) { } - } - - - /** - * 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 testContainsSamePackageAsBootLayer() { - - // check assumption that java.base contains sun.launcher - ModuleDescriptor base = Object.class.getModule().getDescriptor(); - assertTrue(base.packages().contains("sun.launcher")); - - ModuleDescriptor descriptor = newBuilder("m1") - .requires("java.base") - .packages(Set.of("sun.launcher")) - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor); - - Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); - assertTrue(cf.modules().size() == 1); - - ClassLoader loader = new ClassLoader() { }; - Layer layer = Layer.boot().defineModules(cf, mn -> loader); - assertTrue(layer.modules().size() == 1); - } - - - /** - * Test layers with implied readability. - * - * The test consists of three configurations: - * - Configuration/layer1: m1, m2 requires transitive m1 - * - Configuration/layer2: m3 requires m1 - */ - public void testImpliedReadabilityWithLayers1() { - - // cf1: m1 and m2, m2 requires transitive m1 - - ModuleDescriptor descriptor1 = newBuilder("m1") - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") - .build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf1 = resolve(finder1, "m2"); - - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - - - // cf2: m3, m3 requires m2 - - ModuleDescriptor descriptor3 = newBuilder("m3") - .requires("m2") - .build(); - - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - - Configuration cf2 = resolve(cf1, finder2, "m3"); - - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - - 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(); - Module m3 = layer2.findModule("m3").get(); - - assertTrue(m1.getLayer() == layer1); - assertTrue(m2.getLayer() == layer1); - assertTrue(m3.getLayer() == layer2); - - assertTrue(m1.getClassLoader() == cl1); - assertTrue(m2.getClassLoader() == cl1); - assertTrue(m3.getClassLoader() == cl2); - - assertTrue(m1.canRead(m1)); - assertFalse(m1.canRead(m2)); - assertFalse(m1.canRead(m3)); - - assertTrue(m2.canRead(m1)); - assertTrue(m2.canRead(m2)); - assertFalse(m2.canRead(m3)); - - assertTrue(m3.canRead(m1)); - assertTrue(m3.canRead(m2)); - assertTrue(m3.canRead(m3)); - } - - - /** - * Test layers with implied readability. - * - * The test consists of three configurations: - * - Configuration/layer1: m1 - * - Configuration/layer2: m2 requires transitive m3, m3 requires m2 - */ - public void testImpliedReadabilityWithLayers2() { - - // cf1: m1 - - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - - Configuration cf1 = resolve(finder1, "m1"); - - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - - - // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") - .build(); - - ModuleDescriptor descriptor3 = newBuilder("m3") - .requires("m2") - .build(); - - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); - - Configuration cf2 = resolve(cf1, finder2, "m3"); - - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - - 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(); - Module m3 = layer2.findModule("m3").get(); - - assertTrue(m1.getLayer() == layer1); - assertTrue(m2.getLayer() == layer2); - assertTrue(m3.getLayer() == layer2); - - assertTrue(m1.canRead(m1)); - assertFalse(m1.canRead(m2)); - assertFalse(m1.canRead(m3)); - - assertTrue(m2.canRead(m1)); - assertTrue(m2.canRead(m2)); - assertFalse(m2.canRead(m3)); - - assertTrue(m3.canRead(m1)); - assertTrue(m3.canRead(m2)); - assertTrue(m3.canRead(m3)); - } - - - /** - * Test layers with implied readability. - * - * The test consists of three configurations: - * - Configuration/layer1: m1 - * - Configuration/layer2: m2 requires transitive m1 - * - Configuration/layer3: m3 requires m1 - */ - public void testImpliedReadabilityWithLayers3() { - - // cf1: m1 - - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - - Configuration cf1 = resolve(finder1, "m1"); - - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - - - // cf2: m2 requires transitive m1 - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") - .build(); - - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - - Configuration cf2 = resolve(cf1, finder2, "m2"); - - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - - - // cf3: m3 requires m2 - - ModuleDescriptor descriptor3 = newBuilder("m3") - .requires("m2") - .build(); - - ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); - - Configuration cf3 = resolve(cf2, finder3, "m3"); - - ClassLoader cl3 = new ClassLoader() { }; - Layer layer3 = layer2.defineModules(cf3, mn -> cl3); - - 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(); - Module m3 = layer3.findModule("m3").get(); - - assertTrue(m1.getLayer() == layer1); - assertTrue(m2.getLayer() == layer2); - assertTrue(m3.getLayer() == layer3); - - assertTrue(m1.canRead(m1)); - assertFalse(m1.canRead(m2)); - assertFalse(m1.canRead(m3)); - - assertTrue(m2.canRead(m1)); - assertTrue(m2.canRead(m2)); - assertFalse(m2.canRead(m3)); - - assertTrue(m3.canRead(m1)); - assertTrue(m3.canRead(m2)); - assertTrue(m3.canRead(m3)); - } - - - /** - * Test layers with implied readability. - * - * The test consists of two configurations: - * - Configuration/layer1: m1, m2 requires transitive m1 - * - Configuration/layer2: m3 requires transitive m2, m4 requires m3 - */ - public void testImpliedReadabilityWithLayers4() { - - // cf1: m1, m2 requires transitive m1 - - ModuleDescriptor descriptor1 = newBuilder("m1") - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") - .build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf1 = resolve(finder1, "m2"); - - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - - - // cf2: m3 requires transitive m2, m4 requires m3 - - ModuleDescriptor descriptor3 = newBuilder("m3") - .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") - .build(); - - ModuleDescriptor descriptor4 = newBuilder("m4") - .requires("m3") - .build(); - - - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - - Configuration cf2 = resolve(cf1, finder2, "m3", "m4"); - - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - - 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(); - Module m3 = layer2.findModule("m3").get(); - Module m4 = layer2.findModule("m4").get(); - - assertTrue(m1.getLayer() == layer1); - assertTrue(m2.getLayer() == layer1); - assertTrue(m3.getLayer() == layer2); - assertTrue(m4.getLayer() == layer2); - - assertTrue(m1.canRead(m1)); - assertFalse(m1.canRead(m2)); - assertFalse(m1.canRead(m3)); - assertFalse(m1.canRead(m4)); - - assertTrue(m2.canRead(m1)); - assertTrue(m2.canRead(m2)); - assertFalse(m1.canRead(m3)); - assertFalse(m1.canRead(m4)); - - assertTrue(m3.canRead(m1)); - assertTrue(m3.canRead(m2)); - assertTrue(m3.canRead(m3)); - assertFalse(m3.canRead(m4)); - - assertTrue(m4.canRead(m1)); - assertTrue(m4.canRead(m2)); - assertTrue(m4.canRead(m3)); - assertTrue(m4.canRead(m4)); - } - - - /** - * Test layers with a qualified export. The module exporting the package - * does not read the target module. - * - * m1 { exports p to m2 } - * m2 { } - */ - public void testQualifiedExports1() { - ModuleDescriptor descriptor1 = newBuilder("m1"). - exports("p", Set.of("m2")) - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf = resolve(finder1, "m1", "m2"); - - ClassLoader cl = new ClassLoader() { }; - Layer layer = Layer.empty().defineModules(cf, mn -> cl); - assertTrue(layer.modules().size() == 2); - - Module m1 = layer.findModule("m1").get(); - Module m2 = layer.findModule("m2").get(); - - // check m1 exports p to m2 - assertFalse(m1.isExported("p")); - assertTrue(m1.isExported("p", m2)); - assertFalse(m1.isOpen("p", m2)); - } - - - /** - * Test layers with a qualified export. The module exporting the package - * reads the target module. - * - * m1 { exports p to m2; } - * m2 { requires m1; } - */ - public void testQualifiedExports2() { - ModuleDescriptor descriptor1 = newBuilder("m1") - .exports("p", Set.of("m2")) - .build(); - - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires("m1") - .build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf = resolve(finder1, "m2"); - ClassLoader cl = new ClassLoader() { }; - Layer layer = Layer.empty().defineModules(cf, mn -> cl); - assertTrue(layer.modules().size() == 2); - - Module m1 = layer.findModule("m1").get(); - Module m2 = layer.findModule("m2").get(); - - // check m1 exports p to m2 - assertFalse(m1.isExported("p")); - assertTrue(m1.isExported("p", m2)); - assertFalse(m1.isOpen("p", m2)); - } - - - /** - * Test layers with a qualified export. The module exporting the package - * does not read the target module in the parent layer. - * - * - Configuration/layer1: m1 { } - * - Configuration/layer2: m2 { exports p to m1; } - */ - public void testQualifiedExports3() { - // create layer1 with m1 - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolve(finder1, "m1"); - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - assertTrue(layer1.modules().size() == 1); - - // create layer2 with m2 - ModuleDescriptor descriptor2 = newBuilder("m2") - .exports("p", Set.of("m1")) - .build(); - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolve(cf1, finder2, "m2"); - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer2.modules().size() == 1); - - Module m1 = layer1.findModule("m1").get(); - Module m2 = layer2.findModule("m2").get(); - - // check m2 exports p to layer1/m1 - assertFalse(m2.isExported("p")); - assertTrue(m2.isExported("p", m1)); - assertFalse(m2.isOpen("p", m1)); - } - - - /** - * Test layers with a qualified export. The module exporting the package - * reads the target module in the parent layer. - * - * - Configuration/layer1: m1 { } - * - Configuration/layer2: m2 { requires m1; exports p to m1; } - */ - public void testQualifiedExports4() { - // create layer1 with m1 - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolve(finder1, "m1"); - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - assertTrue(layer1.modules().size() == 1); - - // create layer2 with m2 - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires("m1") - .exports("p", Set.of("m1")) - .build(); - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolve(cf1, finder2, "m2"); - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer2.modules().size() == 1); - - Module m1 = layer1.findModule("m1").get(); - Module m2 = layer2.findModule("m2").get(); - - // check m2 exports p to layer1/m1 - assertFalse(m2.isExported("p")); - assertTrue(m2.isExported("p", m1)); - assertFalse(m2.isOpen("p", m1)); - } - - /** - * Test layers with a qualified export. The module exporting the package - * does not read the target module. - * - * - Configuration/layer1: m1 - * - Configuration/layer2: m1, m2 { exports p to m1; } - */ - public void testQualifiedExports5() { - // create layer1 with m1 - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolve(finder1, "m1"); - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - assertTrue(layer1.modules().size() == 1); - - // create layer2 with m1 and m2 - ModuleDescriptor descriptor2 = newBuilder("m2").exports("p", Set.of("m1")).build(); - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf2 = resolve(cf1, finder2, "m1", "m2"); - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer2.modules().size() == 2); - - Module m1_v1 = layer1.findModule("m1").get(); - Module m1_v2 = layer2.findModule("m1").get(); - Module m2 = layer2.findModule("m2").get(); - - // check m2 exports p to layer2/m2 - assertFalse(m2.isExported("p")); - assertTrue(m2.isExported("p", m1_v2)); - assertFalse(m2.isExported("p", m1_v1)); - } - - - /** - * Test layers with a qualified export. The module exporting the package - * reads the target module in the parent layer (due to requires transitive). - * - * - Configuration/layer1: m1, m2 { requires transitive m1; } - * - Configuration/layer2: m1, m3 { requires m2; exports p to m1; } - */ - public void testQualifiedExports6() { - // create layer1 with m1 and m2 - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - ModuleDescriptor descriptor2 = newBuilder("m2") - .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") - .build(); - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolve(finder1, "m2"); - ClassLoader loader1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> loader1); - assertTrue(layer1.modules().size() == 2); - - // create layer2 with m1 and m3 - ModuleDescriptor descriptor3 = newBuilder("m3") - .requires("m2") - .exports("p", Set.of("m1")) - .build(); - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); - Configuration cf2 = resolve(cf1, finder2, "m1", "m3"); - ClassLoader loader2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> loader2); - assertTrue(layer2.modules().size() == 2); - - Module m1_v1 = layer1.findModule("m1").get(); - Module m2 = layer1.findModule("m2").get(); - - Module m1_v2 = layer2.findModule("m1").get(); - Module m3 = layer2.findModule("m3").get(); - - assertTrue(m3.canRead(m1_v1)); - assertFalse(m3.canRead(m1_v2)); - - assertFalse(m3.isExported("p")); - assertTrue(m3.isExported("p", m1_v1)); - assertFalse(m3.isExported("p", m1_v2)); - assertFalse(m3.isExported("p", m2)); - } - - - /** - * Test layers with a qualified export. The target module is not in any layer. - * - * - Configuration/layer1: m1 { } - * - Configuration/layer2: m2 { exports p to m3; } - */ - public void testQualifiedExports7() { - // create layer1 with m1 - ModuleDescriptor descriptor1 = newBuilder("m1").build(); - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolve(finder1, "m1"); - ClassLoader cl1 = new ClassLoader() { }; - Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); - assertTrue(layer1.modules().size() == 1); - - // create layer2 with m2 - ModuleDescriptor descriptor2 = newBuilder("m2") - .exports("p", Set.of("m3")) - .build(); - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolve(cf1, finder2, "m2"); - ClassLoader cl2 = new ClassLoader() { }; - Layer layer2 = layer1.defineModules(cf2, mn -> cl2); - assertTrue(layer2.modules().size() == 1); - - Module m1 = layer1.findModule("m1").get(); - Module m2 = layer2.findModule("m2").get(); - - // check m2 does not export p to anyone - assertFalse(m2.isExported("p")); - assertFalse(m2.isExported("p", m1)); - } - - /** - * Attempt to use Layer defineModules to create a layer with a module - * defined to a class loader that already has a module of the same name - * defined to the class loader. - */ - @Test(expectedExceptions = { LayerInstantiationException.class }) - public void testModuleAlreadyDefinedToLoader() { - - ModuleDescriptor md = newBuilder("m") - .requires("java.base") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(md); - - Configuration parent = Layer.boot().configuration(); - - Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); - - ClassLoader loader = new ClassLoader() { }; - - Layer.boot().defineModules(cf, mn -> loader); - - // should throw LayerInstantiationException as m1 already defined to loader - Layer.boot().defineModules(cf, mn -> loader); - - } - - - /** - * Attempt to use Layer defineModules to create a Layer with a module - * containing package {@code p} where the class loader already has a module - * defined to it containing package {@code p}. - */ - @Test(expectedExceptions = { LayerInstantiationException.class }) - public void testPackageAlreadyInNamedModule() { - - ModuleDescriptor md1 = newBuilder("m1") - .packages(Set.of("p")) - .requires("java.base") - .build(); - - ModuleDescriptor md2 = newBuilder("m2") - .packages(Set.of("p")) - .requires("java.base") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(md1, md2); - - ClassLoader loader = new ClassLoader() { }; - - // define m1 containing package p to class loader - - Configuration parent = Layer.boot().configuration(); - - Configuration cf1 = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); - - Layer layer1 = Layer.boot().defineModules(cf1, mn -> loader); - - // attempt to define m2 containing package p to class loader - - Configuration cf2 = parent.resolve(finder, ModuleFinder.of(), Set.of("m2")); - - // should throw exception because p already in m1 - Layer layer2 = Layer.boot().defineModules(cf2, mn -> loader); - - } - - - /** - * Attempt to use Layer defineModules to create a Layer with a module - * containing a package in which a type is already loaded by the class - * loader. - */ - @Test(expectedExceptions = { LayerInstantiationException.class }) - public void testPackageAlreadyInUnnamedModule() throws Exception { - - Class<?> c = layertest.Test.class; - assertFalse(c.getModule().isNamed()); // in unnamed module - - ModuleDescriptor md = newBuilder("m") - .packages(Set.of(c.getPackageName())) - .requires("java.base") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(md); - - Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); - - Layer.boot().defineModules(cf, mn -> c.getClassLoader()); - } - - - /** - * Attempt to create a Layer with a module named "java.base". - */ - public void testLayerWithJavaBase() { - ModuleDescriptor descriptor = newBuilder("java.base") - .exports("java.lang") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor); - - Configuration cf = Layer.boot() - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of("java.base")); - assertTrue(cf.modules().size() == 1); - - 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) { } - } - - - @DataProvider(name = "javaPackages") - public Object[][] javaPackages() { - return new Object[][] { { "m1", "java" }, { "m2", "java.x" } }; - } - - /** - * 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(dataProvider = "javaPackages") - public void testLayerWithJavaPackage(String mn, String pn) { - ModuleDescriptor descriptor = newBuilder(mn).packages(Set.of(pn)).build(); - ModuleFinder finder = ModuleUtils.finderOf(descriptor); - - Configuration cf = Layer.boot() - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of(mn)); - 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<Module> om = layer.findModule(mn); - assertTrue(om.isPresent()); - Module foo = om.get(); - assertTrue(foo.getClassLoader() == pcl); - assertTrue(foo.getPackages().length == 1); - assertTrue(foo.getPackages()[0].equals(pn)); - } - - - /** - * Attempt to create a Layer with a module defined to the boot loader - */ - @Test(expectedExceptions = { LayerInstantiationException.class }) - public void testLayerWithBootLoader() { - ModuleDescriptor descriptor = newBuilder("m1") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor); - - Configuration cf = Layer.boot() - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of("m1")); - assertTrue(cf.modules().size() == 1); - - Layer.boot().defineModules(cf, mn -> null ); - } - - - /** - * Parent of configuration != configuration of parent Layer - */ - @Test(expectedExceptions = { IllegalArgumentException.class }) - public void testIncorrectParent1() { - - ModuleDescriptor descriptor1 = newBuilder("m1") - .requires("java.base") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - - Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); - - ClassLoader loader = new ClassLoader() { }; - Layer.empty().defineModules(cf, mn -> loader); - } - - - /** - * Parent of configuration != configuration of parent Layer - */ - @Test(expectedExceptions = { IllegalArgumentException.class }) - public void testIncorrectParent2() { - - ModuleDescriptor descriptor1 = newBuilder("m1") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - - Configuration cf = resolve(finder, "m1"); - - ClassLoader loader = new ClassLoader() { }; - Layer.boot().defineModules(cf, mn -> loader); - } - - - // null handling - - @Test(expectedExceptions = { NullPointerException.class }) - public void testCreateWithNull1() { - ClassLoader loader = new ClassLoader() { }; - Layer.empty().defineModules(null, mn -> loader); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testCreateWithNull2() { - Configuration cf = resolve(Layer.boot().configuration(), ModuleFinder.of()); - Layer.boot().defineModules(cf, null); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testCreateWithNull3() { - ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer.empty().defineModulesWithOneLoader(null, scl); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testCreateWithNull4() { - ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer.empty().defineModulesWithManyLoaders(null, scl); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testFindModuleWithNull() { - Layer.boot().findModule(null); - } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testFindLoaderWithNull() { - Layer.boot().findLoader(null); - } - - - // immutable sets - - @Test(expectedExceptions = { UnsupportedOperationException.class }) - public void testImmutableSet() { - Module base = Object.class.getModule(); - Layer.boot().modules().add(base); - } - - - /** - * Resolve the given modules, by name, and returns the resulting - * Configuration. - */ - private static Configuration resolve(Configuration cf, - ModuleFinder finder, - String... roots) { - return cf.resolve(finder, ModuleFinder.of(), Set.of(roots)); - } - - private static Configuration resolve(ModuleFinder finder, - String... roots) { - return resolve(Configuration.empty(), finder, roots); - } -}
--- a/test/java/lang/reflect/Layer/LayerAndLoadersTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,724 +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. - */ - -/** - * @test - * @library /lib/testlibrary - * @modules jdk.compiler - * @build LayerAndLoadersTest CompilerUtils ModuleUtils - * @run testng LayerAndLoadersTest - * @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; -import java.lang.module.ModuleReference; -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; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.stream.Collectors; - -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -@Test -public class LayerAndLoadersTest { - - 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 MODS_DIR = Paths.get("mods"); - - @BeforeTest - public void setup() throws Exception { - - // javac -d mods --module-source-path src src/** - assertTrue(CompilerUtils.compile(SRC_DIR, MODS_DIR, - "--module-source-path", SRC_DIR.toString())); - } - - - /** - * Basic test of Layer defineModulesWithOneLoader - * - * Test scenario: - * m1 requires m2 and m3 - */ - public void testWithOneLoader() throws Exception { - - Configuration cf = resolve("m1"); - - ClassLoader scl = ClassLoader.getSystemClassLoader(); - - Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); - - checkLayer(layer, "m1", "m2", "m3"); - - ClassLoader cl1 = layer.findLoader("m1"); - ClassLoader cl2 = layer.findLoader("m2"); - ClassLoader cl3 = layer.findLoader("m3"); - - assertTrue(cl1.getParent() == scl); - assertTrue(cl2 == cl1); - assertTrue(cl3 == cl1); - - invoke(layer, "m1", "p.Main"); - - } - - - /** - * Basic test of Layer defineModulesWithManyLoaders - * - * Test scenario: - * m1 requires m2 and m3 - */ - public void testWithManyLoaders() throws Exception { - - Configuration cf = resolve("m1"); - - ClassLoader scl = ClassLoader.getSystemClassLoader(); - - Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); - - checkLayer(layer, "m1", "m2", "m3"); - - ClassLoader cl1 = layer.findLoader("m1"); - ClassLoader cl2 = layer.findLoader("m2"); - ClassLoader cl3 = layer.findLoader("m3"); - - assertTrue(cl1.getParent() == scl); - assertTrue(cl2.getParent() == scl); - assertTrue(cl3.getParent() == scl); - assertTrue(cl2 != cl1); - assertTrue(cl3 != cl1); - assertTrue(cl3 != cl2); - - invoke(layer, "m1", "p.Main"); - - } - - - /** - * Basic test of Layer defineModulesWithOneLoader where one of the modules - * is a service provider module. - * - * Test scenario: - * m1 requires m2 and m3 - * m1 uses S - * m4 provides S with ... - */ - public void testServicesWithOneLoader() throws Exception { - - Configuration cf = resolveAndBind("m1"); - - ClassLoader scl = ClassLoader.getSystemClassLoader(); - - Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); - - checkLayer(layer, "m1", "m2", "m3", "m4"); - - ClassLoader cl1 = layer.findLoader("m1"); - ClassLoader cl2 = layer.findLoader("m2"); - ClassLoader cl3 = layer.findLoader("m3"); - ClassLoader cl4 = layer.findLoader("m4"); - - assertTrue(cl1.getParent() == scl); - assertTrue(cl2 == cl1); - assertTrue(cl3 == cl1); - assertTrue(cl4 == cl1); - - Class<?> serviceType = cl1.loadClass("p.Service"); - assertTrue(serviceType.getClassLoader() == cl1); - - Iterator<?> iter = ServiceLoader.load(serviceType, cl1).iterator(); - Object provider = iter.next(); - assertTrue(serviceType.isInstance(provider)); - assertTrue(provider.getClass().getClassLoader() == cl1); - assertFalse(iter.hasNext()); - - } - - - /** - * Basic test of Layer defineModulesWithManyLoaders where one of the - * modules is a service provider module. - * - * Test scenario: - * m1 requires m2 and m3 - * m1 uses S - * m4 provides S with ... - */ - public void testServicesWithManyLoaders() throws Exception { - - Configuration cf = resolveAndBind("m1"); - - ClassLoader scl = ClassLoader.getSystemClassLoader(); - - Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); - - checkLayer(layer, "m1", "m2", "m3", "m4"); - - ClassLoader cl1 = layer.findLoader("m1"); - ClassLoader cl2 = layer.findLoader("m2"); - ClassLoader cl3 = layer.findLoader("m3"); - ClassLoader cl4 = layer.findLoader("m4"); - - assertTrue(cl1.getParent() == scl); - assertTrue(cl2.getParent() == scl); - assertTrue(cl3.getParent() == scl); - assertTrue(cl4.getParent() == scl); - assertTrue(cl2 != cl1); - assertTrue(cl3 != cl1); - assertTrue(cl3 != cl2); - assertTrue(cl4 != cl1); - assertTrue(cl4 != cl2); - assertTrue(cl4 != cl3); - - Class<?> serviceType = cl1.loadClass("p.Service"); - assertTrue(serviceType.getClassLoader() == cl1); - - // Test that the service provider can be located via any of - // the class loaders in the layer - for (Module m : layer.modules()) { - ClassLoader loader = m.getClassLoader(); - Iterator<?> iter = ServiceLoader.load(serviceType, loader).iterator(); - Object provider = iter.next(); - assertTrue(serviceType.isInstance(provider)); - assertTrue(provider.getClass().getClassLoader() == cl4); - assertFalse(iter.hasNext()); - } - - } - - - /** - * Tests that the class loaders created by defineModulesWithXXX delegate - * to the given parent class loader. - */ - public void testDelegationToParent() throws Exception { - - Configuration cf = resolve("m1"); - - ClassLoader parent = this.getClass().getClassLoader(); - String cn = this.getClass().getName(); - - // one loader - Layer layer = Layer.boot().defineModulesWithOneLoader(cf, parent); - testLoad(layer, cn); - - // one loader with boot loader as parent - layer = Layer.boot().defineModulesWithOneLoader(cf, null); - testLoadFail(layer, cn); - - // many loaders - layer = Layer.boot().defineModulesWithManyLoaders(cf, parent); - testLoad(layer, cn); - - // many loader with boot loader as parent - layer = Layer.boot().defineModulesWithManyLoaders(cf, null); - testLoadFail(layer, cn); - - } - - - /** - * Test defineModulesWithXXX when modules that have overlapping packages. - * - * Test scenario: - * m1 exports p - * m2 exports p - */ - public void testOverlappingPackages() { - - ModuleDescriptor descriptor1 - = ModuleDescriptor.newModule("m1").exports("p").build(); - - ModuleDescriptor descriptor2 - = ModuleDescriptor.newModule("m2").exports("p").build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf = Layer.boot() - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); - - // cannot define both module m1 and m2 to the same class loader - try { - Layer.boot().defineModulesWithOneLoader(cf, null); - assertTrue(false); - } catch (LayerInstantiationException expected) { } - - // should be okay to have one module per class loader - Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, null); - checkLayer(layer, "m1", "m2"); - - } - - - /** - * Test Layer defineModulesWithXXX with split delegation. - * - * Test scenario: - * layer1: m1 exports p, m2 exports p - * layer2: m3 reads m1, m4 reads m2 - */ - public void testSplitDelegation() { - - ModuleDescriptor descriptor1 - = ModuleDescriptor.newModule("m1").exports("p").build(); - - ModuleDescriptor descriptor2 - = ModuleDescriptor.newModule("m2").exports("p").build(); - - ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - - Configuration cf1 = Layer.boot() - .configuration() - .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2")); - - Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); - checkLayer(layer1, "m1", "m2"); - - ModuleDescriptor descriptor3 - = ModuleDescriptor.newModule("m3").requires("m1").build(); - - ModuleDescriptor descriptor4 - = ModuleDescriptor.newModule("m4").requires("m2").build(); - - ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - - Configuration cf2 = cf1.resolve(finder2, ModuleFinder.of(), - Set.of("m3", "m4")); - - // package p cannot be supplied by two class loaders - try { - layer1.defineModulesWithOneLoader(cf2, null); - assertTrue(false); - } catch (LayerInstantiationException expected) { } - - // no split delegation when modules have their own class loader - Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); - checkLayer(layer2, "m3", "m4"); - - } - - - /** - * Test Layer defineModulesWithXXX when the modules that override same - * named modules in the parent layer. - * - * Test scenario: - * layer1: m1, m2, m3 => same loader - * layer2: m1, m2, m4 => same loader - */ - public void testOverriding1() throws Exception { - - Configuration cf1 = resolve("m1"); - - Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); - checkLayer(layer1, "m1", "m2", "m3"); - - ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); - - Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); - checkLayer(layer2, "m1", "m2", "m3"); - invoke(layer1, "m1", "p.Main"); - - ClassLoader loader1 = layer1.findLoader("m1"); - ClassLoader loader2 = layer1.findLoader("m2"); - ClassLoader loader3 = layer1.findLoader("m3"); - - ClassLoader loader4 = layer2.findLoader("m1"); - ClassLoader loader5 = layer2.findLoader("m2"); - ClassLoader loader6 = layer2.findLoader("m3"); - - assertTrue(loader1 == loader2); - assertTrue(loader1 == loader3); - - assertTrue(loader4 == loader5); - assertTrue(loader4 == loader6); - assertTrue(loader4 != loader1); - - assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); - assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1); - assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1); - - assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); - assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader4); - assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader4); - - } - - - /** - * Test Layer defineModulesWithXXX when the modules that override same - * named modules in the parent layer. - * - * Test scenario: - * layer1: m1, m2, m3 => loader pool - * layer2: m1, m2, m3 => loader pool - */ - public void testOverriding2() throws Exception { - - Configuration cf1 = resolve("m1"); - - Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); - checkLayer(layer1, "m1", "m2", "m3"); - - ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); - - Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); - checkLayer(layer2, "m1", "m2", "m3"); - invoke(layer1, "m1", "p.Main"); - - ClassLoader loader1 = layer1.findLoader("m1"); - ClassLoader loader2 = layer1.findLoader("m2"); - ClassLoader loader3 = layer1.findLoader("m3"); - - ClassLoader loader4 = layer2.findLoader("m1"); - ClassLoader loader5 = layer2.findLoader("m2"); - ClassLoader loader6 = layer2.findLoader("m3"); - - assertTrue(loader4 != loader1); - assertTrue(loader5 != loader2); - assertTrue(loader6 != loader3); - - assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); - assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2); - assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3); - - // p.Main is not visible via loader2 - try { - loader2.loadClass("p.Main"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - // w.Hello is not visible via loader2 - try { - loader2.loadClass("w.Hello"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - // p.Main is not visible via loader3 - try { - loader3.loadClass("p.Main"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - // q.Hello is not visible via loader3 - try { - loader3.loadClass("q.Hello"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - - assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); - assertTrue(loader5.loadClass("q.Hello").getClassLoader() == loader5); - assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); - - // p.Main is not visible via loader5 - try { - loader5.loadClass("p.Main"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - // w.Hello is not visible via loader5 - try { - loader5.loadClass("w.Hello"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - // p.Main is not visible via loader6 - try { - loader6.loadClass("p.Main"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - // q.Hello is not visible via loader6 - try { - loader6.loadClass("q.Hello"); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - - } - - - /** - * Test Layer defineModulesWithXXX when the modules that override same - * named modules in the parent layer. - * - * layer1: m1, m2, m3 => same loader - * layer2: m1, m3 => same loader - */ - public void testOverriding3() throws Exception { - - Configuration cf1 = resolve("m1"); - - Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); - checkLayer(layer1, "m1", "m2", "m3"); - - ModuleFinder finder = finderFor("m1", "m3"); - - Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); - - Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); - checkLayer(layer2, "m1", "m3"); - invoke(layer1, "m1", "p.Main"); - - ClassLoader loader1 = layer1.findLoader("m1"); - ClassLoader loader2 = layer2.findLoader("m1"); - - assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); - assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1); - assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1); - - assertTrue(loader2.loadClass("p.Main").getClassLoader() == loader2); - assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader1); - assertTrue(loader2.loadClass("w.Hello").getClassLoader() == loader2); - - } - - - /** - * Test Layer defineModulesWithXXX when the modules that override same - * named modules in the parent layer. - * - * layer1: m1, m2, m3 => loader pool - * layer2: m1, m3 => loader pool - */ - public void testOverriding4() throws Exception { - - Configuration cf1 = resolve("m1"); - - Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); - checkLayer(layer1, "m1", "m2", "m3"); - - ModuleFinder finder = finderFor("m1", "m3"); - - Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); - - Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); - checkLayer(layer2, "m1", "m3"); - invoke(layer1, "m1", "p.Main"); - - ClassLoader loader1 = layer1.findLoader("m1"); - ClassLoader loader2 = layer1.findLoader("m2"); - ClassLoader loader3 = layer1.findLoader("m3"); - - ClassLoader loader4 = layer2.findLoader("m1"); - ClassLoader loader5 = layer2.findLoader("m2"); - ClassLoader loader6 = layer2.findLoader("m3"); - - assertTrue(loader4 != loader1); - assertTrue(loader5 == loader2); // m2 not overridden - assertTrue(loader6 != loader3); - - assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); - assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2); - assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3); - - assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader2); - - assertTrue(loader3.loadClass("w.Hello").getClassLoader() == loader3); - - assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); - assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader2); - assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader6); - - assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); - - } - - - /** - * Basic test of resource loading with a class loader created by - * Layer.defineModulesWithOneLoader. - */ - public void testResourcesOneLoader() throws Exception { - Configuration cf = resolve("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 = resolve("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<URL> urls = loader.getResources(name); - assertTrue(urls.hasMoreElements()); - } - - - // -- supporting methods -- - - - /** - * Resolve the given modules, by name, and returns the resulting - * Configuration. - */ - private static Configuration resolve(String... roots) { - ModuleFinder finder = ModuleFinder.of(MODS_DIR); - return Layer.boot() - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of(roots)); - } - - /** - * Resolve the given modules, by name, and returns the resulting - * Configuration. - */ - private static Configuration resolveAndBind(String... roots) { - ModuleFinder finder = ModuleFinder.of(MODS_DIR); - return Layer.boot() - .configuration() - .resolveAndBind(finder, ModuleFinder.of(), Set.of(roots)); - } - - - /** - * Invokes the static void main(String[]) method on the given class - * in the given module. - */ - private static void invoke(Layer layer, String mn, String mc) throws Exception { - ClassLoader loader = layer.findLoader(mn); - Class<?> c = loader.loadClass(mc); - Method mainMethod = c.getMethod("main", String[].class); - mainMethod.invoke(null, (Object)new String[0]); - } - - - /** - * Checks that the given layer contains exactly the expected modules - * (by name). - */ - private void checkLayer(Layer layer, String ... expected) { - Set<String> names = layer.modules().stream() - .map(Module::getName) - .collect(Collectors.toSet()); - assertTrue(names.size() == expected.length); - for (String name : expected) { - assertTrue(names.contains(name)); - } - } - - - /** - * Test that a class can be loaded via the class loader of all modules - * in the given layer. - */ - static void testLoad(Layer layer, String cn) throws Exception { - for (Module m : layer.modules()) { - ClassLoader l = m.getClassLoader(); - l.loadClass(cn); - } - } - - - /** - * Test that a class cannot be loaded via any of the class loaders of - * the modules in the given layer. - */ - static void testLoadFail(Layer layer, String cn) throws Exception { - for (Module m : layer.modules()) { - ClassLoader l = m.getClassLoader(); - try { - l.loadClass(cn); - assertTrue(false); - } catch (ClassNotFoundException expected) { } - } - } - - - /** - * Returns a ModuleFinder that only finds the given test modules - */ - static ModuleFinder finderFor(String... names) { - - ModuleFinder finder = ModuleFinder.of(MODS_DIR); - - Map<String, ModuleReference> mrefs = new HashMap<>(); - for (String name : names) { - Optional<ModuleReference> omref = finder.find(name); - assert omref.isPresent(); - mrefs.put(name, omref.get()); - } - - return new ModuleFinder() { - @Override - public Optional<ModuleReference> find(String name) { - ModuleReference mref = mrefs.get(name); - return Optional.ofNullable(mref); - } - @Override - public Set<ModuleReference> findAll() { - return mrefs.values().stream().collect(Collectors.toSet()); - } - }; - } - -}
--- a/test/java/lang/reflect/Layer/LayerControllerTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* - * 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.newModule("m1") - .packages(Set.of("p1")) - .requires("java.base") - .build(); - - ModuleDescriptor descriptor2 - = ModuleDescriptor.newModule("m2") - .requires("java.base") - .packages(Set.of("p2")) - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Layer bootLayer = Layer.boot(); - - Configuration cf = bootLayer.configuration() - .resolve(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) { } - } -}
--- a/test/java/lang/reflect/Layer/layertest/Test.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * Supporting class for tests of java.lang.reflect.Layer. - */ - -package layertest; - -public class Test { } -
--- a/test/java/lang/reflect/Layer/src/m1/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +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. - */ - -module m1 { - requires m2; - requires m3; - exports p; - uses p.Service; -}
--- a/test/java/lang/reflect/Layer/src/m1/p/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p; - -import java.net.URL; - -public class Main { - public static void main(String[] args) { - - URL url1 = Main.class.getResource("Main.class"); - if (url1 == null) throw new RuntimeException(); - URL url2 = Main.class.getResource("/p/Main.class"); - if (url2 == null) throw new RuntimeException(); - - q.Hello.hello(); - w.Hello.hello(); - } -}
--- a/test/java/lang/reflect/Layer/src/m1/p/Service.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package p; - -public interface Service { }
--- a/test/java/lang/reflect/Layer/src/m2/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m2 { - exports q; -}
--- a/test/java/lang/reflect/Layer/src/m2/q/Hello.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package q; - -import java.net.URL; - -public class Hello { - - public static void hello() { - - URL url1 = Hello.class.getResource("Hello.class"); - if (url1 == null) throw new RuntimeException(); - URL url2 = Hello.class.getResource("/q/Hello.class"); - if (url2 == null) throw new RuntimeException(); - - System.out.println("Hello!"); - } - -}
--- a/test/java/lang/reflect/Layer/src/m3/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m3 { - // qualified export - exports w to m1; -}
--- a/test/java/lang/reflect/Layer/src/m3/w/Hello.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package w; - -import java.net.URL; - -public class Hello { - - public static void hello() { - - URL url1 = Hello.class.getResource("Hello.class"); - if (url1 == null) throw new RuntimeException(); - URL url2 = Hello.class.getResource("/w/Hello.class"); - if (url2 == null) throw new RuntimeException(); - - System.out.println("Hello!"); - } - -}
--- a/test/java/lang/reflect/Layer/src/m4/impl/ServiceImpl.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package impl; - -public class ServiceImpl implements p.Service { -}
--- a/test/java/lang/reflect/Layer/src/m4/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module m4 { - requires m1; - provides p.Service with impl.ServiceImpl; -}
--- a/test/java/lang/reflect/Module/AddExportsTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * 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 - * @modules java.base/jdk.internal.misc - * java.desktop - * @run main/othervm --add-exports=java.desktop/sun.awt=java.base AddExportsTest - * @run main/othervm --add-exports=java.desktop/sun.awt=ALL-UNNAMED AddExportsTest - * @summary Test Module isExported methods with exports changed by -AddExportsTest - */ - -import java.lang.reflect.Layer; -import java.lang.reflect.Module; -import java.util.Optional; -import java.util.stream.Stream; - -import jdk.internal.misc.VM; - -public class AddExportsTest { - /* - * jtreg sets -Dtest.modules system property to the internal APIs - * specified at @modules tag. The test will exclude --add-exports set - * for @modules. - */ - private static final String TEST_MODULES = System.getProperty("test.modules"); - - public static void main(String[] args) { - - Optional<String> oaddExports = Stream.of(VM.getRuntimeArguments()) - .filter(arg -> arg.startsWith("--add-exports=")) - .filter(arg -> !arg.equals("--add-exports=" + TEST_MODULES + "=ALL-UNNAMED")) - .map(arg -> arg.substring("--add-exports=".length(), arg.length())) - .findFirst(); - - assertTrue(oaddExports.isPresent()); - - Layer bootLayer = Layer.boot(); - - Module unnamedModule = AddExportsTest.class.getModule(); - assertFalse(unnamedModule.isNamed()); - - for (String expr : oaddExports.get().split(",")) { - - String[] s = expr.split("="); - assertTrue(s.length == 2); - - // $MODULE/$PACKAGE - String[] moduleAndPackage = s[0].split("/"); - assertTrue(moduleAndPackage.length == 2); - - String mn = moduleAndPackage[0]; - String pn = moduleAndPackage[1]; - - // source module - Module source; - Optional<Module> om = bootLayer.findModule(mn); - assertTrue(om.isPresent(), mn + " not in boot layer"); - source = om.get(); - - // package should not be exported unconditionally - assertFalse(source.isExported(pn), - pn + " should not be exported unconditionally"); - - // $TARGET - String tn = s[1]; - if ("ALL-UNNAMED".equals(tn)) { - - // package is exported to all unnamed modules - assertTrue(source.isExported(pn, unnamedModule), - pn + " should be exported to all unnamed modules"); - - } else { - - om = bootLayer.findModule(tn); - assertTrue(om.isPresent()); - Module target = om.get(); - - // package should be exported to target module - assertTrue(source.isExported(pn, target), - pn + " should be exported to " + target); - - // package should not be exported to unnamed modules - assertFalse(source.isExported(pn, unnamedModule), - pn + " should not be exported to unnamed modules"); - - } - - } - } - - static void assertTrue(boolean cond) { - if (!cond) throw new RuntimeException(); - } - - static void assertTrue(boolean cond, String msg) { - if (!cond) throw new RuntimeException(msg); - } - - static void assertFalse(boolean cond) { - if (cond) throw new RuntimeException(); - } - - static void assertFalse(boolean cond, String msg) { - if (cond) throw new RuntimeException(msg); - } - -}
--- a/test/java/lang/reflect/Module/AnnotationsTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* - * 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<Attribute> attrs = new ArrayList<>(); - attrs.add(new ClassFileAttributes.ModuleAttribute()); - attrs.add(new ClassFileAttributes.ModulePackagesAttribute()); - 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() - .resolve(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; - } -}
--- a/test/java/lang/reflect/Module/BasicModuleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.lang.module.ModuleDescriptor.Exports; -import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; -import java.nio.file.spi.FileSystemProvider; // service type in java.base -import java.util.function.Predicate; -import java.util.stream.Stream; -import javax.print.PrintServiceLookup; // service type in java.desktop - -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/* - * @test - * @summary Basic test of java.lang.reflect.Module - * @modules java.desktop java.xml - * @run testng BasicModuleTest - */ - -public class BasicModuleTest { - - /** - * Tests that the given module reads all modules in the boot Layer. - */ - private void testReadsAllBootModules(Module m) { - Layer bootLayer = Layer.boot(); - bootLayer.configuration() - .modules() - .stream() - .map(ResolvedModule::name) - .map(bootLayer::findModule) - .forEach(target -> assertTrue(m.canRead(target.get()))); - } - - /** - * Returns {@code true} if the array contains the given object. - */ - private <T> boolean contains(T[] array, T obj) { - return Stream.of(array).anyMatch(obj::equals); - } - - /** - * Returns a {@code Predicate} to test if a package is exported. - */ - private Predicate<Exports> doesExport(String pn) { - return e -> (e.source().equals(pn) && !e.isQualified()); - } - - - - @Test - public void testThisModule() { - Module thisModule = BasicModuleTest.class.getModule(); - Module baseModule = Object.class.getModule(); - - assertFalse(thisModule.isNamed()); - assertTrue(thisModule.getName() == null); - assertTrue(thisModule.getDescriptor() == null); - assertTrue(thisModule.getLayer() == null); - assertTrue(thisModule.toString().startsWith("unnamed module ")); - - ClassLoader thisLoader = BasicModuleTest.class.getClassLoader(); - assertTrue(thisLoader == thisModule.getClassLoader()); - assertTrue(thisLoader.getUnnamedModule() == thisModule); - - // unnamed modules read all other modules - ClassLoader cl; - cl = ClassLoader.getPlatformClassLoader(); - assertTrue(thisModule.canRead(cl.getUnnamedModule())); - cl = ClassLoader.getSystemClassLoader(); - assertTrue(thisModule.canRead(cl.getUnnamedModule())); - testReadsAllBootModules(thisModule); - - // unnamed modules export all packages - assertTrue(thisModule.isExported("")); - assertTrue(thisModule.isExported("", thisModule)); - assertTrue(thisModule.isExported("", baseModule)); - assertTrue(thisModule.isExported("p")); - assertTrue(thisModule.isExported("p", thisModule)); - assertTrue(thisModule.isExported("p", baseModule)); - - // this test is in the unnamed package - assertTrue(contains(thisModule.getPackages(), "")); - } - - - @Test - public void testUnnamedModules() { - Module thisModule = BasicModuleTest.class.getModule(); - Module baseModule = Object.class.getModule(); - - ClassLoader loader1 = ClassLoader.getSystemClassLoader(); - ClassLoader loader2 = loader1.getParent(); - - Module m1 = loader1.getUnnamedModule(); - Module m2 = loader2.getUnnamedModule(); - - assertTrue(m1 != m2); - - assertFalse(m1.isNamed()); - assertFalse(m2.isNamed()); - - assertTrue(m1.getLayer() == null); - assertTrue(m2.getLayer() == null); - - assertTrue(m1.toString().startsWith("unnamed module ")); - assertTrue(m2.toString().startsWith("unnamed module ")); - - // unnamed module reads all modules - assertTrue(m1.canRead(m2)); - assertTrue(m2.canRead(m1)); - - testReadsAllBootModules(m1); - testReadsAllBootModules(m2); - - assertTrue(m1.isExported("")); - assertTrue(m1.isExported("", thisModule)); - assertTrue(m1.isExported("", baseModule)); - assertTrue(m1.isExported("p")); - assertTrue(m1.isExported("p", thisModule)); - assertTrue(m1.isExported("p", baseModule)); - } - - - - @Test - public void testBaseModule() { - Module base = Object.class.getModule(); - Module thisModule = BasicModuleTest.class.getModule(); - - // getName - assertTrue(base.getName().equals("java.base")); - - // getDescriptor - assertTrue(base.getDescriptor().exports().stream() - .anyMatch(doesExport("java.lang"))); - - // getClassLoader - assertTrue(base.getClassLoader() == null); - - // getLayer - assertTrue(base.getLayer() == Layer.boot()); - - // toString - assertEquals(base.toString(), "module java.base"); - - // getPackages - assertTrue(contains(base.getPackages(), "java.lang")); - - // canRead - assertTrue(base.canRead(base)); - assertFalse(base.canRead(thisModule)); - - // addReads - try { - base.addReads(thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(base.canRead(thisModule)); - - // 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)); - - // addExports - try { - base.addExports("java.lang", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - try { - base.addExports("jdk.internal.misc", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(base.isExported("jdk.internal.misc")); - assertFalse(base.isExported("jdk.internal.misc", thisModule)); - - // 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)); - - // addOpens - try { - base.addOpens("jdk.internal.misc", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(base.isOpen("jdk.internal.misc")); - assertFalse(base.isOpen("jdk.internal.misc", thisModule)); - - // canUse - assertTrue(base.canUse(FileSystemProvider.class)); - assertFalse(base.canUse(Thread.class)); - - // addUses - try { - base.addUses(FileSystemProvider.class); - assertTrue(false); - } catch (IllegalCallerException expected) { } - try { - base.addUses(Thread.class); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(base.canUse(Thread.class)); - } - - - @Test - public void testDesktopModule() { - Module desktop = java.awt.Component.class.getModule(); - Module base = Object.class.getModule(); - Module xml = javax.xml.XMLConstants.class.getModule(); - Module thisModule = BasicModuleTest.class.getModule(); - - // name - assertTrue(desktop.getName().equals("java.desktop")); - - // descriptor - assertTrue(desktop.getDescriptor().exports().stream() - .anyMatch(doesExport("java.awt"))); - - // getClassLoader - assertTrue(desktop.getClassLoader() == null); - - // getLayer - assertTrue(desktop.getLayer() == Layer.boot()); - - // toString - assertEquals(desktop.toString(), "module java.desktop"); - - // getPackages - assertTrue(contains(desktop.getPackages(), "java.awt")); - assertTrue(contains(desktop.getPackages(), "sun.awt")); - - // canRead - assertTrue(desktop.canRead(base)); - assertTrue(desktop.canRead(xml)); - - // addReads - try { - desktop.addReads(thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(desktop.canRead(thisModule)); - - // isExported - assertTrue(desktop.isExported("java.awt")); - assertTrue(desktop.isExported("java.awt", thisModule)); - assertFalse(desktop.isExported("sun.awt")); - assertFalse(desktop.isExported("sun.awt", thisModule)); - assertTrue(desktop.isExported("sun.awt", desktop)); - assertFalse(desktop.isExported("java.wombat")); - assertFalse(desktop.isExported("java.wombat", thisModule)); - assertFalse(desktop.isExported("java.wombat", base)); - - // addExports - try { - desktop.addExports("java.awt", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - try { - desktop.addExports("sun.awt", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(desktop.isExported("sun.awt")); - assertFalse(desktop.isExported("sun.awt", thisModule)); - - // isOpen - assertFalse(desktop.isOpen("java.awt")); - assertFalse(desktop.isOpen("java.awt", thisModule)); - assertTrue(desktop.isOpen("java.awt", desktop)); - assertFalse(desktop.isOpen("sun.awt")); - assertFalse(desktop.isOpen("sun.awt", thisModule)); - assertTrue(desktop.isOpen("sun.awt", desktop)); - assertFalse(desktop.isOpen("java.wombat")); - assertFalse(desktop.isOpen("java.wombat", thisModule)); - assertFalse(desktop.isOpen("java.wombat", desktop)); - - // addOpens - try { - base.addOpens("sun.awt", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(desktop.isOpen("sun.awt")); - assertFalse(desktop.isOpen("sun.awt", thisModule)); - - // canUse - assertTrue(base.canUse(FileSystemProvider.class)); - assertFalse(base.canUse(Thread.class)); - - // addUses - try { - desktop.addUses(PrintServiceLookup.class); - assertTrue(false); - } catch (IllegalCallerException expected) { } - try { - desktop.addUses(Thread.class); - assertTrue(false); - } catch (IllegalCallerException expected) { } - assertFalse(desktop.canUse(Thread.class)); - } - -}
--- a/test/java/lang/reflect/Module/WithSecurityManager.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* - * 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 - * @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 - */ - -import java.io.IOException; -import java.io.InputStream; -import java.lang.module.Configuration; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReference; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; -import java.util.Collections; -import java.util.Optional; -import java.util.Set; - -/** - * Test java.lang.reflect.Module methods that specify permission checks. - */ - -public class WithSecurityManager { - - // a module that will be loaded into a child layer - 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"); - - // base module, in the boot layer - Module base = Object.class.getModule(); - - // another module, in a child layer - Module other = loadModuleInChildLayer(ANOTHER_MODULE); - assertTrue(other.getLayer() != Layer.boot()); - - System.setSecurityManager(new SecurityManager()); - - test(base, "java/lang/Object.class", allow); - test(other, ANOTHER_MODULE_RESOURCE, allow); - } - - /** - * Test the permission checks by invoking methods on the given module. - * - * If {@code allow} is {@code true} then the permission checks should succeed. - */ - static void test(Module m, String name, boolean allow) throws IOException { - - // test Module::getClassLoader - System.out.format("Test getClassLoader on %s ...%n", m); - try { - ClassLoader cl = m.getClassLoader(); - System.out.println(cl); - if (!allow) - assertTrue("getClassLoader should have failed", false); - } catch (SecurityException e) { - System.out.println(e + " thrown"); - if (allow) - throw e; - } - - // test Module::getResourceAsStream - System.out.format("Test getResourceAsStream(\"%s\") on %s ...%n", name, m); - try (InputStream in = m.getResourceAsStream(name)) { - System.out.println(in); - if (allow && (in == null)) - assertTrue(name + " not found", false); - if (!allow && (in != null)) - assertTrue(name + " should not be found", false); - } - - } - - /** - * Create a module layer that contains the given system module. - */ - static Module loadModuleInChildLayer(String mn) { - Optional<ModuleReference> omref = ModuleFinder.ofSystem().find(mn); - assertTrue("module " + mn + " not a system module", omref.isPresent()); - - // create a ModuleFinder that only finds this module - ModuleReference mref = omref.get(); - ModuleFinder finder = new ModuleFinder() { - @Override - public Optional<ModuleReference> find(String name) { - if (name.equals(mn)) - return Optional.of(mref); - else - return Optional.empty(); - } - - @Override - public Set<ModuleReference> findAll() { - return Collections.singleton(mref); - } - }; - - // create a child configuration and layer with this module - Layer bootLayer = Layer.boot(); - Configuration cf = bootLayer - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of(ANOTHER_MODULE)); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, null); - - Optional<Module> om = layer.findModule(mn); - assertTrue("module " + mn + " not in child layer", om.isPresent()); - return om.get(); - } - - static void assertTrue(String msg, boolean e) { - if (!e) - throw new RuntimeException(msg); - } - - static void assertTrue(boolean e) { - if (!e) - throw new RuntimeException(); - } - -}
--- a/test/java/lang/reflect/Module/access/AccessTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +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.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; - -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 jdk.compiler - * @build AccessTest CompilerUtils jdk.testlibrary.* - * @run testng AccessTest - * @summary Driver for test that checks access to access to types in - * exported and non-exported packages. - */ - -@Test -public class AccessTest { - - 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 MODS_DIR = Paths.get("mods"); - - - // the names of the modules in this test - private static List<String> modules = Arrays.asList("test", "target"); - - - /** - * Compiles all modules used by the test - */ - @BeforeTest - public void compileAll() throws Exception { - for (String mn : modules) { - Path src = SRC_DIR.resolve(mn); - Path mods = MODS_DIR.resolve(mn); - assertTrue(CompilerUtils.compile(src, mods)); - } - } - - /** - * Run the test - */ - public void runTest() throws Exception { - 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) - .getExitValue(); - - assertTrue(exitValue == 0); - } - -}
--- a/test/java/lang/reflect/Module/access/src/target/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +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. - */ - -module target { - exports p1; - exports p2; -}
--- a/test/java/lang/reflect/Module/access/src/target/p1/Helper.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +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. - */ - -package p1; - -import java.lang.reflect.Module; - -/** - * Helper class in target module to allow test invoke addExports[Private] - */ - -public class Helper { - Helper() { } - - public static void addExports(String pn, Module who) { - Helper.class.getModule().addExports(pn, who); - } - - public static void addOpens(String pn, Module who) { - Helper.class.getModule().addOpens(pn, who); - } -}
--- a/test/java/lang/reflect/Module/access/src/target/p1/Public.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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. - */ - -package p1; - -public class Public { - - // public constructor - public Public() { } - - // non-public constructor - private Public(Void ignore) { } - - // public field - public static Object f1; - - // non-public field - private static Object f2; - - // public method - public static void foo() { } - - // non-public method - private static void bar() { } -}
--- a/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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. - */ - -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() { } -}
--- a/test/java/lang/reflect/Module/access/src/target/q1/Public.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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. - */ - -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() { } -}
--- a/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +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. - */ - -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() { } -}
--- a/test/java/lang/reflect/Module/access/src/test/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -module test { }
--- a/test/java/lang/reflect/Module/access/src/test/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,379 +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. - */ - -package test; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Layer; -import java.lang.reflect.Method; -import java.lang.reflect.Module; - -/** - * 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(); - Module targetModule = getTargetModule(); - - assertTrue(targetModule.isExported("p1")); - assertTrue(targetModule.isExported("p1", thisModule)); - assertTrue(targetModule.isExported("p1", targetModule)); - - assertFalse(targetModule.isOpen("p1")); - assertFalse(targetModule.isOpen("p1", thisModule)); - assertTrue(targetModule.isOpen("p1", targetModule)); - - Class<?> clazz = Class.forName("p1.Public"); - Constructor<?> ctor1 = clazz.getConstructor(); // public - Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public - - Field f1 = clazz.getField("f1"); // public - Field f2 = clazz.getDeclaredField("f2"); // non-public - - Method m1 = clazz.getMethod("foo"); // public - Method m2 = clazz.getDeclaredMethod("bar"); // non-public - - tryAccessConstructor(ctor1, true); - tryAccessConstructor(ctor2, false); - tryAccessMethod(m1, true); - tryAccessMethod(m2, false); - tryAccessObjectField(f1, true); - tryAccessObjectField(f2, false); - - trySetAccessible(ctor1, true); - trySetAccessible(ctor2, false); - trySetAccessible(m1, true); - trySetAccessible(m2, false); - trySetAccessible(f1, true); - trySetAccessible(f2, false); - - targetAddOpens("p1", thisModule); - - tryAccessConstructor(ctor1, true); - tryAccessConstructor(ctor2, false); - tryAccessMethod(m1, true); - tryAccessMethod(m2, false); - tryAccessObjectField(f1, true); - tryAccessObjectField(f2, false); - - trySetAccessible(ctor1, true); - trySetAccessible(ctor2, true); - trySetAccessible(m1, true); - trySetAccessible(m2, true); - trySetAccessible(f1, true); - trySetAccessible(f2, true); - } - - static void testNonPublicClassInExportedPackage() throws Exception { - Module thisModule = Main.class.getModule(); - Module targetModule = getTargetModule(); - - assertTrue(targetModule.isExported("p2")); - assertTrue(targetModule.isExported("p2", thisModule)); - assertTrue(targetModule.isExported("p2", targetModule)); - - assertFalse(targetModule.isOpen("p2")); - assertFalse(targetModule.isOpen("p2", thisModule)); - assertTrue(targetModule.isOpen("p1", targetModule)); - - Class<?> clazz = Class.forName("p2.NonPublic"); - Constructor<?> ctor1 = clazz.getConstructor(); - Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class); - - Field f1 = clazz.getField("f1"); // public - Field f2 = clazz.getDeclaredField("f2"); // non-public - - Method m1 = clazz.getMethod("foo"); // public - Method m2 = clazz.getDeclaredMethod("bar"); // non-public - - tryAccessConstructor(ctor1, false); - tryAccessConstructor(ctor2, false); - tryAccessMethod(m1, false); - tryAccessMethod(m2, false); - tryAccessObjectField(f1, false); - tryAccessObjectField(f2, false); - - trySetAccessible(ctor1, false); - trySetAccessible(ctor2, false); - trySetAccessible(m1, false); - trySetAccessible(m2, false); - trySetAccessible(f1, false); - trySetAccessible(f2, false); - - targetAddExports("p2", thisModule); - - 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); - } - - - static Module getTargetModule() { - return Layer.boot().findModule("target").get(); - } - - static void tryAccessConstructor(Constructor<?> ctor, boolean shouldSucceed) { - try { - ctor.newInstance(); - assertTrue(shouldSucceed); - } catch (Exception e) { - assertFalse(shouldSucceed); - } - } - - static void tryAccessMethod(Method method, boolean shouldSucceed) { - try { - method.invoke(null); - assertTrue(shouldSucceed); - } catch (Exception e) { - e.printStackTrace(); - assertFalse(shouldSucceed); - } - } - - static void tryAccessObjectField(Field f, boolean shouldSucceed) { - try { - f.get(null); - assertTrue(shouldSucceed); - } catch (Exception e) { - assertFalse(shouldSucceed); - } - try { - f.set(null, new Object()); - assertTrue(shouldSucceed); - } 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("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(); - } - - static void assertFalse(boolean expr) { - assertTrue(!expr); - } -}
--- a/test/java/lang/reflect/Module/addXXX/Driver.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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/* m4/* - * @run testng/othervm test/test.Main - * @summary Basic test case for Module::addXXX methods - */
--- a/test/java/lang/reflect/Module/addXXX/m1/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -module m1 { - exports p1; -}
--- a/test/java/lang/reflect/Module/addXXX/m1/p1/C.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package p1; - -public class C { - public C() { } -}
--- a/test/java/lang/reflect/Module/addXXX/m2/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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 p2; -}
--- a/test/java/lang/reflect/Module/addXXX/m2/p2/C.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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; - -import java.lang.reflect.Module; - -public class C { - - public static void export(String pn, Module m) { - C.class.getModule().addExports(pn, m); - } -}
--- a/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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.internal; - -public class C { -}
--- a/test/java/lang/reflect/Module/addXXX/m3/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -module m3 { - exports p3 to test; - opens p3 to test; -}
--- a/test/java/lang/reflect/Module/addXXX/m3/p3/C.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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; - -public class C { -}
--- a/test/java/lang/reflect/Module/addXXX/m4/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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 m4 { - exports p4; -}
--- a/test/java/lang/reflect/Module/addXXX/m4/p4/C.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * 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; - -import java.lang.reflect.Constructor; - -public class C { - public static Object tryNewInstance(Class<?> clazz) throws Exception { - Constructor<?> ctor = clazz.getDeclaredConstructor(); - return ctor.newInstance(); - } -}
--- a/test/java/lang/reflect/Module/addXXX/test/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -module test { - exports test to testng; - - requires m2; - requires m3; - requires m4; - requires testng; -}
--- a/test/java/lang/reflect/Module/addXXX/test/test/C.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package test; - -public class C { }
--- a/test/java/lang/reflect/Module/addXXX/test/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package test; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Constructor; -import java.lang.reflect.Module; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; - -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * Basic test case for Module::addXXXX methods - */ - -@Test -public class Main { - - /** - * Test Module::addReads - * - * module test { } - * - * module m1 { - * exports p1; - * } - */ - public void testAddReads() throws Throwable { - Module thisModule = Main.class.getModule(); - Class<?> clazz = Class.forName("p1.C"); - Module m1 = clazz.getModule(); - - // test does not read m1 - assertFalse(thisModule.canRead(m1)); - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodType mt = MethodType.methodType(void.class); - try { - lookup.findConstructor(clazz, mt); - assertTrue(false); - } catch (IllegalAccessException expected) { } - - // update test to read m1 - Module result = thisModule.addReads(m1); - assertTrue(result== thisModule); - assertTrue(thisModule.canRead(m1)); - MethodHandle mh = lookup.findConstructor(clazz, mt); - Object obj = mh.invoke(); - - // attempt to update m1 to read test - try { - m1.addReads(thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - } - - - /** - * Test Module::addExports - * - * module test { - * requires m2; - * } - * module m2 { - * exports p2; - * contains package p2.internal; - * } - */ - public void testAddExports() throws Exception { - Module thisModule = Main.class.getModule(); - Module m2 = p2.C.class.getModule(); - Class<?> targetClass = Class.forName("p2.internal.C"); - String p2Internal = targetClass.getPackageName(); - assertTrue(targetClass.getModule() == m2); - - // m2 does not export p2.internal to test - assertFalse(m2.isExported(p2Internal, thisModule)); - Constructor<?> ctor = targetClass.getDeclaredConstructor(); - try { - ctor.newInstance(); - assertTrue(false); - } catch (IllegalAccessException expected) { } - - // update m2 to export p2.internal to test - p2.C.export(p2Internal, thisModule); - assertTrue(m2.isExported(p2Internal, thisModule)); - ctor.newInstance(); // should succeed - - // attempt to update m2 to export a package to test - try { - m2.addExports("p2.other", thisModule); - assertTrue(false); - } catch (IllegalCallerException expected) { } - } - - /** - * Test Module::addOpens - * - * module test { - * requires m3; - * requires m4; - * } - * - * module m3 { - * exports p3 to test; - * opens p3 to test; - * } - * - * module m4 { - * exports p4; - * } - */ - public void testAddOpens() throws Exception { - Module thisModule = Main.class.getModule(); - Module m3 = p3.C.class.getModule(); - Module m4 = p4.C.class.getModule(); - - // test does not open package test to m4 - assertFalse(thisModule.isOpen("test", m4)); - try { - p4.C.tryNewInstance(test.C.class); - assertTrue(false); - } catch (IllegalAccessException expected) { } - - // open test to m4 - thisModule.addOpens("test", m4); - p4.C.tryNewInstance(test.C.class); // should succeed - - - // m3 does not open p3 to m4 - assertFalse(m3.isOpen("p3", m4)); - try { - p4.C.tryNewInstance(p3.C.class); - assertTrue(false); - } catch (IllegalAccessException expected) { } - - - // m3 opens p3 to test => test allowed to open m3/p3 to m4 - assertTrue(m3.isOpen("p3", thisModule)); - m3.addOpens("p3", m4); - assertTrue(m3.isOpen("p3", m4)); - p4.C.tryNewInstance(p3.C.class); // should succeed - - - // attempt to update m4 to open package to m3 - try { - m4.addOpens("p4", m3); - assertTrue(false); - } catch (IllegalCallerException expected) { } - } - - - /** - * Test Module::addUses - */ - public void testAddUses() { - Module thisModule = Main.class.getModule(); - - assertFalse(thisModule.canUse(Service.class)); - try { - ServiceLoader.load(Service.class); - assertTrue(false); - } catch (ServiceConfigurationError expected) { } - - Module result = thisModule.addUses(Service.class); - assertTrue(result== thisModule); - - assertTrue(thisModule.canUse(Service.class)); - ServiceLoader.load(Service.class); // no exception - } - -}
--- a/test/java/lang/reflect/Module/addXXX/test/test/Service.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package test; - -/** - * Simple service type - */ -public interface Service { }
--- a/test/java/lang/reflect/Module/allow.policy Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. - * 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. - */ - -grant { - permission java.lang.RuntimePermission "getClassLoader"; - permission java.lang.RuntimePermission "accessSystemModules"; - permission java.io.FilePermission "${java.home}/modules/-", "read"; // exploded build -};
--- a/test/java/lang/reflect/Module/annotation/Basic.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * 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)); - } -}
--- a/test/java/lang/reflect/Module/annotation/src/m/module-info.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * 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; -}
--- a/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * 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(); -}
--- a/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * 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(); -}
--- a/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * 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 {}
--- a/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ import java.lang.module.Configuration; import java.lang.module.ModuleFinder; -import java.lang.reflect.Layer; import java.lang.reflect.Proxy; import java.nio.file.Path; import java.nio.file.Paths; @@ -88,12 +87,12 @@ @Test public void testNoReadAccess() throws Exception { ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration cf = bootLayer .configuration() .resolveAndBind(ModuleFinder.of(), finder, modules); ClassLoader parentLoader = this.getClass().getClassLoader(); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader); ClassLoader loader = layer.findLoader("m1"); Class<?>[] interfaces = new Class<?>[] {
--- a/test/java/lang/reflect/Proxy/ProxyForMethodHandle.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/Proxy/ProxyForMethodHandle.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Module; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test;
--- a/test/java/lang/reflect/Proxy/ProxyLayerTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/Proxy/ProxyLayerTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ import java.lang.module.Configuration; import java.lang.module.ModuleFinder; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Layer; import java.lang.reflect.Proxy; import java.nio.file.Path; import java.nio.file.Paths; @@ -70,18 +69,18 @@ } /** - * Test proxy implementing interfaces in a Layer defined in + * Test proxy implementing interfaces in a layer defined in * an unnamed module */ @Test public void testProxyInUnnamed() throws Exception { ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration cf = bootLayer .configuration() .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl); ClassLoader loader = layer.findLoader("m1"); @@ -110,12 +109,12 @@ @Test public void testProxyInDynamicModule() throws Exception { ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration cf = bootLayer .configuration() .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl); ClassLoader loader = layer.findLoader("m1"); @@ -140,12 +139,12 @@ @Test public void testNoReadAccess() throws Exception { ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration cf = bootLayer .configuration() .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl); ClassLoader loader = layer.findLoader("m1");
--- a/test/java/lang/reflect/Proxy/ProxyModuleMapping.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/Proxy/ProxyModuleMapping.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Module; import java.lang.reflect.Proxy; /*
--- a/test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ import java.net.URL; import java.net.URLClassLoader; -import java.lang.reflect.Module; import static jdk.test.ProxyTest.*; public class Main {
--- a/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Module; import java.lang.reflect.Proxy; import java.util.Arrays;
--- a/test/java/lang/reflect/WeakPairMap/Driver.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * 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 - * @bug 8888888 - * @summary Functional test for WeakPairMap - * @build java.base/java.lang.reflect.WeakPairMapTest - * @run main Driver - */ -public class Driver { - public static void main(String[] args) { - java.lang.reflect.WeakPairMapTest.main(args); - } -}
--- a/test/java/lang/reflect/WeakPairMap/java.base/java/lang/reflect/WeakPairMapTest.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - * 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.reflect; - -import java.lang.ref.Reference; -import java.util.Objects; - -/** - * Functional test for WeakPairMap - * - * @author Peter Levart - */ -public class WeakPairMapTest { - public static void main(String[] args) { - WeakPairMap<Object, Object, String> pm = new WeakPairMap<>(); - Object key1 = new Object(); - Object key2 = new Object(); - - // check for emptiness - assertEquals(pm.containsKeyPair(key1, key2), false); - assertEquals(pm.get(key1, key2), null); - - // check for NPE(s) - for (Object k1 : new Object[]{null, key1}) { - for (Object k2 : new Object[]{null, key2}) { - for (String v : new String[]{null, "abc"}) { - - if (k1 != null && k2 != null && v != null) { - // skip non-null args - continue; - } - - try { - pm.put(k1, k2, v); - throw new AssertionError("Unexpected code path, k1=" + - k1 + ", k2=" + k2 + ", v=" + v); - } catch (NullPointerException e) { - // expected - } - - try { - pm.putIfAbsent(k1, k2, v); - throw new AssertionError("Unexpected code path, k1=" + - k1 + ", k2=" + k2 + ", v=" + v); - } catch (NullPointerException e) { - // expected - } - - if (k1 != null && k2 != null) { - // skip non-null args - continue; - } - - try { - pm.computeIfAbsent(k1, k2, (_k1, _k2) -> v); - throw new AssertionError("Unexpected code path, k1=" + - k1 + ", k2=" + k2 + ", v=" + v); - } catch (NullPointerException e) { - // expected - } - - try { - pm.containsKeyPair(k1, k2); - throw new AssertionError("Unexpected code path, k1=" + - k1 + ", k2=" + k2); - } catch (NullPointerException e) { - // expected - } - - try { - pm.get(k1, k2); - throw new AssertionError("Unexpected code path, k1=" + - k1 + ", k2=" + k2); - } catch (NullPointerException e) { - // expected - } - } - } - } - - // how much to wait when it is expected for entry to be retained - final long retentionTimeout = 500L; - // how much to wait when it is expected for entry to be removed - final long cleanupTimeout = 30_000L; - - // check insertion - assertEquals(pm.putIfAbsent(key1, key2, "abc"), null); - assertEquals(pm.get(key1, key2), "abc"); - - // check retention while both keys are still reachable - assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false); - assertEquals(pm.get(key1, key2), "abc"); - - // check cleanup when both keys are unreachable - key1 = null; - key2 = null; - assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true); - - // new insertion - key1 = new Object(); - key2 = new Object(); - assertEquals(pm.putIfAbsent(key1, key2, "abc"), null); - assertEquals(pm.get(key1, key2), "abc"); - - // check retention while both keys are still reachable - assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false); - assertEquals(pm.get(key1, key2), "abc"); - - // check cleanup when 1st key is unreachable - key1 = null; - assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true); - Reference.reachabilityFence(key2); - - // new insertion - key1 = new Object(); - key2 = new Object(); - assertEquals(pm.putIfAbsent(key1, key2, "abc"), null); - assertEquals(pm.get(key1, key2), "abc"); - - // check retention while both keys are still reachable - assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false); - assertEquals(pm.get(key1, key2), "abc"); - - // check cleanup when 2nd key is unreachable - key2 = null; - assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true); - Reference.reachabilityFence(key1); - } - - /** - * Trigger GC and wait for at most {@code millis} ms for given value to - * be removed from given WeakPairMap. - * - * @return true if element has been removed or false if not - */ - static <V> boolean gcAndWaitRemoved(WeakPairMap<?, ?, V> pm, V value, - long millis) { - System.gc(); - for (int i = 0; i < (millis + 99) / 100 && pm.values().contains(value); i++) { - try { - Thread.sleep(100L); - } catch (InterruptedException e) { - throw new AssertionError("Interrupted"); - } - } - return !pm.values().contains(value); - } - - static void assertEquals(Object actual, Object expected) { - if (!Objects.equals(actual, expected)) { - throw new AssertionError("Expected: " + expected + ", actual: " + actual); - } - } -}
--- a/test/java/security/Provider/DefaultProviderList.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/security/Provider/DefaultProviderList.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,7 +33,6 @@ import java.util.Arrays; import java.util.Iterator; import java.util.ServiceLoader; -import java.lang.reflect.Module; public class DefaultProviderList {
--- a/test/java/util/ResourceBundle/modules/cache/src/test/jdk/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/cache/src/test/jdk/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.test; -import java.lang.reflect.Module; import java.util.MissingResourceException; import java.util.ResourceBundle; @@ -56,4 +55,4 @@ jdk.test.util.Bundles.getBundle(); } } -} \ No newline at end of file +}
--- a/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ package jdk.test; import p1.Bundle; -import java.lang.reflect.Module; import java.util.ResourceBundle; public class Main {
--- a/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.embargo; -import java.lang.reflect.Module; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle;
--- a/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.embargo; -import java.lang.reflect.Module; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle;
--- a/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.pkg.test; -import java.lang.reflect.Module; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle;
--- a/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.test; -import java.lang.reflect.Module; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle;
--- a/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.test; -import java.lang.reflect.Module; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle;
--- a/test/java/util/ServiceLoader/modules/BadProvidersTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ServiceLoader/modules/BadProvidersTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -33,7 +33,6 @@ 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; @@ -87,14 +86,14 @@ private List<Provider> loadProviders(Path mp, String moduleName) throws Exception { ModuleFinder finder = ModuleFinder.of(mp); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration cf = bootLayer.configuration() .resolveAndBind(finder, ModuleFinder.of(), Set.of(moduleName)); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); + ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); Class<?> service = layer.findLoader(moduleName).loadClass(TEST_SERVICE);
--- a/test/java/util/ServiceLoader/modules/Basic.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/ServiceLoader/modules/Basic.java Fri Apr 07 08:05:54 2017 +0000 @@ -34,7 +34,6 @@ 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; @@ -229,7 +228,7 @@ */ @Test public void testWithCustomLayer1() { - Layer layer = createCustomLayer("bananascript"); + ModuleLayer layer = createCustomLayer("bananascript"); ClassLoader loader = layer.findLoader("bananascript"); List<ScriptEngineFactory> providers @@ -258,7 +257,7 @@ */ @Test public void testWithCustomLayer2() { - Layer layer = createCustomLayer("bananascript"); + ModuleLayer layer = createCustomLayer("bananascript"); List<ScriptEngineFactory> factories = collectAll(ServiceLoader.load(layer, ScriptEngineFactory.class)); @@ -293,7 +292,7 @@ */ @Test public void testWithCustomLayer3() { - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration cf0 = bootLayer.configuration(); // boot layer should contain "bananascript" @@ -313,12 +312,12 @@ // layer1 Configuration cf1 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of()); - Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl); + ModuleLayer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl); assertTrue(layer1.modules().size() == 1); // layer2 Configuration cf2 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of()); - Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl); + ModuleLayer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl); assertTrue(layer2.modules().size() == 1); // layer3 with layer1 and layer2 as parents @@ -326,7 +325,8 @@ List.of(cf1, cf2), ModuleFinder.of(), Set.of()); - Layer layer3 = Layer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer(); + ModuleLayer layer3 + = ModuleLayer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer(); assertTrue(layer3.modules().size() == 1); @@ -390,12 +390,12 @@ @Test(expectedExceptions = { NullPointerException.class }) public void testLoadNull3() { class S { } - ServiceLoader.load((Layer) null, S.class); + ServiceLoader.load((ModuleLayer) null, S.class); } @Test(expectedExceptions = { NullPointerException.class }) public void testLoadNull4() { - ServiceLoader.load(Layer.empty(), null); + ServiceLoader.load(ModuleLayer.empty(), null); } @Test(expectedExceptions = { NullPointerException.class }) @@ -404,19 +404,19 @@ } /** - * Create a custom Layer by resolving the given module names. The modules + * 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) { + private ModuleLayer createCustomLayer(String... modules) { Path dir = Paths.get(System.getProperty("test.classes", "."), "modules"); ModuleFinder finder = ModuleFinder.of(dir); Set<String> roots = new HashSet<>(); Collections.addAll(roots, modules); - Layer bootLayer = Layer.boot(); + ModuleLayer bootLayer = ModuleLayer.boot(); Configuration parent = bootLayer.configuration(); Configuration cf = parent.resolve(finder, ModuleFinder.of(), roots); ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl); assertTrue(layer.modules().size() == 1); return layer; }
--- a/test/java/util/logging/LocalizedLevelName.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/logging/LocalizedLevelName.java Fri Apr 07 08:05:54 2017 +0000 @@ -21,7 +21,6 @@ * questions. */ -import java.lang.reflect.Module; import java.util.*; import java.util.logging.*;
--- a/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package p3.test; -import java.lang.reflect.Module; import java.util.logging.Logger; import java.util.MissingResourceException; import java.util.PropertyResourceBundle;
--- a/test/java/util/spi/ResourceBundleControlProvider/test/jdk/test/ResourceBundleDelegate.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/java/util/spi/ResourceBundleControlProvider/test/jdk/test/ResourceBundleDelegate.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package jdk.test; -import java.lang.reflect.Module; import java.util.Locale; import java.util.ResourceBundle;
--- a/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java Fri Apr 07 08:05:54 2017 +0000 @@ -39,7 +39,6 @@ import com.sun.org.apache.xml.internal.serializer.EncodingInfo; import com.sun.org.apache.xml.internal.serializer.Encodings; import java.io.InputStreamReader; -import java.lang.reflect.Module; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.ArrayList;
--- a/test/jdk/internal/jimage/JImageOpenTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/internal/jimage/JImageOpenTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -21,7 +21,6 @@ * questions. */ -import java.lang.reflect.Layer; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -48,7 +47,7 @@ final List<String> names = Files.walk(root) .filter(p -> p.getNameCount() > 2) - .filter(p -> Layer.boot().findModule(p.getName(1).toString()).isPresent()) + .filter(p -> ModuleLayer.boot().findModule(p.getName(1).toString()).isPresent()) .map(p -> p.subpath(2, p.getNameCount())) .map(p -> p.toString()) .filter(s -> s.endsWith(".class") && !s.endsWith("module-info.class"))
--- a/test/jdk/modules/etc/JdkQualifiedExportTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/etc/JdkQualifiedExportTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -40,7 +40,6 @@ import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; -import java.lang.reflect.Module; import java.util.Collections; import java.util.Comparator; import java.util.HashMap;
--- a/test/jdk/modules/etc/VerifyModuleDelegation.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/etc/VerifyModuleDelegation.java Fri Apr 07 08:05:54 2017 +0000 @@ -31,8 +31,6 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.util.Set; import static java.util.stream.Collectors.toSet; @@ -49,7 +47,7 @@ = ModuleDescriptor.newModule(JAVA_BASE).build(); private static final Set<ModuleDescriptor> MREFS - = Layer.boot().modules().stream().map(Module::getDescriptor) + = ModuleLayer.boot().modules().stream().map(Module::getDescriptor) .collect(toSet()); private void check(ModuleDescriptor md, ModuleDescriptor ref) { @@ -69,7 +67,7 @@ @Test public void checkLoaderDelegation() { - Layer boot = Layer.boot(); + ModuleLayer boot = ModuleLayer.boot(); MREFS.stream() .forEach(md -> md.requires().stream().forEach(req -> {
--- a/test/jdk/modules/incubator/DefaultImage.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/incubator/DefaultImage.java Fri Apr 07 08:05:54 2017 +0000 @@ -34,6 +34,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -41,13 +44,13 @@ import java.util.stream.Stream; import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.nio.charset.StandardCharsets.UTF_8; import static jdk.testlibrary.ProcessTools.executeCommand; import static org.testng.Assert.*; +@Test public class DefaultImage { private static final String JAVA_HOME = System.getProperty("java.home"); private static final Path TEST_SRC = Paths.get(System.getProperty("test.src")); @@ -72,19 +75,13 @@ .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator")); } - @DataProvider(name = "tokens") - public Object[][] singleModuleValues() throws IOException { - return new Object[][]{ { "ALL-DEFAULT" }, { "ALL-SYSTEM"} }; - } - - @Test(dataProvider = "tokens") - public void testAddMods(String addModsToken) throws Throwable { + public void testAllDefault() throws Throwable { if (isExplodedBuild()) { System.out.println("Test cannot run on exploded build"); return; } - java("--add-modules", addModsToken, + java("--add-modules", "ALL-DEFAULT", "-cp", CP_DIR.toString(), "listmods.ListModules") .assertSuccess() @@ -92,6 +89,22 @@ .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator")); } + public void testAllSystem() throws Throwable { + if (isExplodedBuild()) { + System.out.println("Test cannot run on exploded build"); + return; + } + + if (containsAnyIncubatorModules()) { + java("--add-modules", "ALL-SYSTEM", + "-cp", CP_DIR.toString(), + "listmods.ListModules") + .assertSuccess() + .resultChecker(r -> r.assertOutputContains("java.base")) + .resultChecker(r -> r.assertOutputContains("jdk.incubator")); + } + } + static ToolResult java(String... opts) throws Throwable { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); @@ -155,4 +168,14 @@ Path modulesPath = Paths.get(JAVA_HOME).resolve("lib").resolve("modules"); return Files.notExists(modulesPath); } + + static boolean containsAnyIncubatorModules() { + return ModuleFinder.ofSystem().findAll().stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .filter(mn -> mn.startsWith("jdk.incubator")) + .map(mn -> true) + .findAny() + .orElse(false); + } }
--- a/test/jdk/modules/incubator/ImageModules.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/incubator/ImageModules.java Fri Apr 07 08:05:54 2017 +0000 @@ -98,7 +98,7 @@ List.of("hello world", "message.converter", "java.base"), List.of("WARNING") }, { "--do-not-resolve-by-default", - List.of("ALL-DEFAULT", "ALL-SYSTEM"), + List.of("ALL-DEFAULT"), ToolResult.ASSERT_FAILURE, List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"), List.of("WARNING", "message.converter") }, @@ -109,7 +109,7 @@ "WARNING: Using incubator modules: message.converter"), List.of() }, { "--do-not-resolve-by-default --warn-if-resolved=incubating", - List.of("ALL-DEFAULT", "ALL-SYSTEM"), + List.of("ALL-DEFAULT"), ToolResult.ASSERT_FAILURE, List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"), List.of("WARNING", "message.converter") }, @@ -215,13 +215,13 @@ List.of() }, { "--do-not-resolve-by-default", "", - List.of("ALL-DEFAULT", "ALL-SYSTEM"), + List.of("ALL-DEFAULT"), ToolResult.ASSERT_FAILURE, List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"), List.of("message.writer") }, { "--do-not-resolve-by-default", "--do-not-resolve-by-default", - List.of("ALL-DEFAULT", "ALL-SYSTEM"), + List.of("ALL-DEFAULT"), ToolResult.ASSERT_FAILURE, List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"), List.of("message.converter", "message.writer") }, @@ -239,7 +239,8 @@ ToolResult.ASSERT_SUCCESS, List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base", "WARNING: Using incubator modules: message.converter"), - List.of() } }; + List.of() } + }; return values; }
--- a/test/jdk/modules/incubator/src/cp/listmods/ListModules.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/incubator/src/cp/listmods/ListModules.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,13 +23,11 @@ package listmods; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import static java.util.stream.Collectors.joining; public class ListModules { public static void main(String[] args) throws Exception { - System.out.println(Layer.boot() + System.out.println(ModuleLayer.boot() .modules() .stream() .map(Module::getName)
--- a/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,13 +23,11 @@ package test; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import static java.util.stream.Collectors.joining; public class ConvertToLowerCase { public static void main(String[] args) { - System.out.println(Layer.boot() + System.out.println(ModuleLayer.boot() .modules() .stream() .map(Module::getName)
--- a/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,13 +23,11 @@ package test; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import static java.util.stream.Collectors.joining; public class WriteUpperCase { public static void main(String[] args) { - System.out.println(Layer.boot() + System.out.println(ModuleLayer.boot() .modules() .stream() .map(Module::getName)
--- a/test/jdk/modules/open/Basic.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/open/Basic.java Fri Apr 07 08:05:54 2017 +0000 @@ -36,7 +36,6 @@ 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;
--- a/test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,9 +23,6 @@ package test; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; - import http.HttpServer; /** @@ -47,8 +44,8 @@ cl = ClassLoader.getSystemClassLoader(); assertTrue(httpModule.canRead(cl.getUnnamedModule())); - // and read all modules in the boot Layer - Layer layer = Layer.boot(); + // and read all modules in the boot layer + ModuleLayer layer = ModuleLayer.boot(); layer.modules().forEach(m -> assertTrue(httpModule.canRead(m))); // run code in the automatic modue, ensures access is allowed
--- a/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,8 +26,6 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Provides; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; @@ -36,7 +34,7 @@ import javax.script.ScriptEngineFactory; /** - * Test that the automatic module "bananascript" is in the boot Layer and + * Test that the automatic module "bananascript" is in the boot layer and * it behaves as a service provider. */ @@ -44,7 +42,7 @@ public static void main(String[] args) throws Exception { - Optional<Module> om = Layer.boot().findModule("bananascript"); + Optional<Module> om = ModuleLayer.boot().findModule("bananascript"); assertTrue(om.isPresent()); ModuleDescriptor descriptor = om.get().getDescriptor();
--- a/test/jdk/modules/scenarios/container/src/container/container/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/jdk/modules/scenarios/container/src/container/container/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,9 +27,7 @@ import java.lang.module.Configuration; import java.lang.module.ModuleFinder; import java.lang.module.ResolvedModule; -import java.lang.reflect.Layer; import java.lang.reflect.Method; -import java.lang.reflect.Module; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Set; @@ -43,7 +41,7 @@ public static void main(String[] args) throws Exception { System.out.println("Boot layer"); - Layer.boot() + ModuleLayer.boot() .modules() .stream() .map(Module::getName) @@ -70,7 +68,7 @@ ModuleFinder finder = ModuleFinder.of(paths); - Configuration cf = Layer.boot().configuration() + Configuration cf = ModuleLayer.boot().configuration() .resolveAndBind(finder, ModuleFinder.of(), Set.of(appModuleName)); @@ -81,9 +79,9 @@ .sorted() .forEach(mn -> System.out.format(" %s%n", mn)); - // reify the configuration as a Layer + // reify the configuration as a module layer ClassLoader scl = ClassLoader.getSystemClassLoader(); - Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); // invoke application main method ClassLoader loader = layer.findLoader(appModuleName);
--- a/test/sun/management/LoggingTest/test.loggerfinder/test/loggerfinder/TestLoggerFinder.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/sun/management/LoggingTest/test.loggerfinder/test/loggerfinder/TestLoggerFinder.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ import java.lang.System.Logger; import java.lang.System.Logger.Level; import java.lang.System.LoggerFinder; -import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Optional;
--- a/test/sun/tools/jconsole/ResourceCheckTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/sun/tools/jconsole/ResourceCheckTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -34,7 +34,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.lang.reflect.Module; import java.util.ArrayList; import java.util.Collections; import java.util.List;
--- a/test/tools/jar/modularJar/Basic.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jar/modularJar/Basic.java Fri Apr 07 08:05:54 2017 +0000 @@ -869,8 +869,8 @@ return new Object[][] { // JAR file name module-name[@version] { "foo.jar", "foo" }, + { "foo1.jar", "foo1" }, { "foo4j.jar", "foo4j", }, - { "foo1.2.3.jar", "foo" }, { "foo-1.2.3.4.jar", "foo@1.2.3.4" }, { "foo-bar.jar", "foo.bar" }, { "foo-1.2-SNAPSHOT.jar", "foo@1.2-SNAPSHOT" },
--- a/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,7 +28,6 @@ import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; -import java.lang.reflect.Module; import java.util.Optional; import java.util.StringJoiner; import java.util.HashSet;
--- a/test/tools/jlink/JLink2Test.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/JLink2Test.java Fri Apr 07 08:05:54 2017 +0000 @@ -39,7 +39,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.reflect.Layer; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -88,7 +87,7 @@ private static void testOptions() throws Exception { List<Plugin> builtInPlugins = new ArrayList<>(); - builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); + builtInPlugins.addAll(PluginRepository.getPlugins(ModuleLayer.boot())); if(builtInPlugins.isEmpty()) { throw new Exception("No builtin plugins"); }
--- a/test/tools/jlink/JLinkTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/JLinkTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -25,7 +25,6 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.module.ModuleDescriptor; -import java.lang.reflect.Layer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -88,7 +87,7 @@ { // number of built-in plugins List<Plugin> builtInPlugins = new ArrayList<>(); - builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); + builtInPlugins.addAll(PluginRepository.getPlugins(ModuleLayer.boot())); totalPlugins = builtInPlugins.size(); // actual num. of plugins loaded from jdk.jlink module int actualJLinkPlugins = 0;
--- a/test/tools/jlink/basic/src/test/jdk/test/Test.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/basic/src/test/jdk/test/Test.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,9 +23,6 @@ package jdk.test; -import java.lang.reflect.Module; -import java.lang.reflect.Layer; - public class Test { public static void main(String[] args) { System.out.println(Test.class + " ..."); @@ -36,7 +33,7 @@ ClassLoader scl = ClassLoader.getSystemClassLoader(); ClassLoader cl1 = Test.class.getClassLoader(); Module testModule = Test.class.getModule(); - ClassLoader cl2 = Layer.boot().findLoader(testModule.getName()); + ClassLoader cl2 = ModuleLayer.boot().findLoader(testModule.getName()); if (cl1 != scl) throw new RuntimeException("Not loaded by system class loader");
--- a/test/tools/jlink/plugins/PluginsNegativeTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/PluginsNegativeTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -30,7 +30,6 @@ * jdk.jlink/jdk.tools.jlink.plugin * @run main/othervm PluginsNegativeTest */ -import java.lang.reflect.Layer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -63,7 +62,7 @@ private void testDuplicateBuiltInProviders() { List<Plugin> javaPlugins = new ArrayList<>(); - javaPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); + javaPlugins.addAll(PluginRepository.getPlugins(ModuleLayer.boot())); for (Plugin javaPlugin : javaPlugins) { System.out.println("Registered plugin: " + javaPlugin.getName()); } @@ -72,7 +71,7 @@ try { PluginRepository.registerPlugin(new CustomPlugin(pluginName)); try { - PluginRepository.getPlugin(pluginName, Layer.boot()); + PluginRepository.getPlugin(pluginName, ModuleLayer.boot()); throw new AssertionError("Exception is not thrown for duplicate plugin: " + pluginName); } catch (Exception ignored) { } @@ -83,7 +82,7 @@ } private void testUnknownProvider() { - if (PluginRepository.getPlugin("unknown", Layer.boot()) != null) { + if (PluginRepository.getPlugin("unknown", ModuleLayer.boot()) != null) { throw new AssertionError("Exception expected for unknown plugin name"); } }
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ import java.io.File; import java.io.IOException; import java.lang.module.ModuleDescriptor; -import java.lang.reflect.Layer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths;
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,8 +26,6 @@ import java.io.InputStream; import java.io.IOException; import java.lang.module.ModuleDescriptor; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems;
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -26,7 +26,6 @@ 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.*;
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -27,7 +27,6 @@ import java.io.InputStream; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; -import java.lang.reflect.Layer; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -100,7 +99,7 @@ private static void checkModule(String mn, String... packages) throws IOException { // verify ModuleDescriptor from the runtime module - ModuleDescriptor md = Layer.boot().findModule(mn).get() + ModuleDescriptor md = ModuleLayer.boot().findModule(mn).get() .getDescriptor(); checkModuleDescriptor(md, packages);
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/src/m5/p5/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/SystemModuleDescriptors/src/m5/p5/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -23,7 +23,6 @@ package p5; -import java.lang.reflect.Layer; import p3.Foo; import p3.Lib; @@ -32,7 +31,7 @@ */ public class Main { public static void main(String... args) { - boolean libPresent = Layer.boot().findModule("m3").isPresent(); + boolean libPresent = ModuleLayer.boot().findModule("m3").isPresent(); if (LibHelper.libClassFound != libPresent) { throw new RuntimeException("Expected module m3 not in the boot layer"); }
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,8 +24,6 @@ package jdk.test; import java.lang.module.ModuleDescriptor; -import java.lang.reflect.Layer; -import java.lang.reflect.Module; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -65,7 +63,7 @@ // check the module descriptor of a system module for (int i=0; i < modules.size(); i++) { String mn = modules.get(i); - Module module = Layer.boot().findModule(mn).orElseThrow( + Module module = ModuleLayer.boot().findModule(mn).orElseThrow( () -> new RuntimeException(mn + " not found") );
--- a/test/tools/launcher/modules/dryrun/DryRunTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/launcher/modules/dryrun/DryRunTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -167,22 +167,6 @@ // test main method with and without --add-modules mm int exitValue = exec("--module-path", LIBS_DIR.toString(), "-m", mid); - assertTrue(exitValue != 0); - - exitValue = exec("--module-path", LIBS_DIR.toString(), - "--add-modules", M_MODULE, - "-m", mid); - assertTrue(exitValue == 0); - - // test dry run with and without --add-modules m - // no resolution failure - exitValue = exec("--dry-run", "--module-path", LIBS_DIR.toString(), - "-m", mid); - assertTrue(exitValue == 0); - - exitValue = exec("--dry-run", "--module-path", LIBS_DIR.toString(), - "--add-modules", M_MODULE, - "-m", mid); assertTrue(exitValue == 0); }
--- a/test/tools/launcher/modules/listmods/ListModsTest.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/launcher/modules/listmods/ListModsTest.java Fri Apr 07 08:05:54 2017 +0000 @@ -115,7 +115,7 @@ .outputTo(System.out) .errorTo(System.out); output.shouldNotContain("java.base"); - output.shouldContain("java.rhubarb not observable"); + output.shouldContain("java.rhubarb not found"); assertTrue(output.getExitValue() == 0); }
--- a/test/tools/launcher/modules/patch/basic/src/test/jdk/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/launcher/modules/patch/basic/src/test/jdk/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -28,8 +28,6 @@ package jdk.test; -import java.lang.reflect.Module; - public class Main { public static void main(String[] args) throws Exception {
--- a/test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java Thu Apr 06 17:01:03 2017 +0000 +++ b/test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java Fri Apr 07 08:05:54 2017 +0000 @@ -24,7 +24,6 @@ package jdk.test; import java.lang.module.ModuleReference; -import java.lang.reflect.Layer; import java.net.URI; import javax.enterprise.context.Scope; @@ -53,7 +52,7 @@ // javax.transaction should be found in boot layer. ModuleReference ref = - Layer.boot().configuration().findModule(TRANSACTION_MODULE).get().reference(); + ModuleLayer.boot().configuration().findModule(TRANSACTION_MODULE).get().reference(); // check uri of java.transaction found on the upgrade module path. URI uri = ref.location().get(); System.out.println("uri: " + uri);