changeset 14800:74b5562461a5

Update Layer API to make it easy to create layers without needing to provide class loaders
author alanb
date Thu, 17 Dec 2015 17:00:18 +0000
parents b20c9733ab0b
children 2cf87b107845
files src/java.base/share/classes/java/lang/ModuleClassLoader.java src/java.base/share/classes/java/lang/reflect/Layer.java src/java.base/share/classes/java/util/ServiceLoader.java src/java.base/share/classes/jdk/internal/misc/Loader.java src/java.base/share/classes/jdk/internal/misc/LoaderPool.java src/jdk.jlink/share/classes/jdk/tools/jlink/TaskHelper.java test/jdk/jigsaw/reflect/Layer/BasicLayerTest.java test/jdk/jigsaw/reflect/Layer/LayerAndLoadersTest.java test/jdk/jigsaw/reflect/Layer/LayerTest.java test/jdk/jigsaw/reflect/Layer/src/m1/module-info.java test/jdk/jigsaw/reflect/Layer/src/m1/p/Main.java test/jdk/jigsaw/reflect/Layer/src/m1/p/Service.java test/jdk/jigsaw/reflect/Layer/src/m2/module-info.java test/jdk/jigsaw/reflect/Layer/src/m2/q/Hello.java test/jdk/jigsaw/reflect/Layer/src/m3/impl/ServiceImpl.java test/jdk/jigsaw/reflect/Layer/src/m3/module-info.java test/jdk/jigsaw/reflect/Proxy/ProxyClassAccessTest.java test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java test/jdk/jigsaw/scenarios/container/src/container/container/Main.java test/jdk/jigsaw/util/ServiceLoader/ServicesTest.java
diffstat 20 files changed, 2471 insertions(+), 940 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/ModuleClassLoader.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/src/java.base/share/classes/java/lang/ModuleClassLoader.java	Thu Dec 17 17:00:18 2015 +0000
@@ -76,6 +76,7 @@
  * @since 1.9
  */
 
+@Deprecated
 public final class ModuleClassLoader
     extends SecureClassLoader
 {
--- a/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Dec 17 17:00:18 2015 +0000
@@ -36,6 +36,8 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import jdk.internal.misc.Loader;
+import jdk.internal.misc.LoaderPool;
 import jdk.internal.misc.SharedSecrets;
 import sun.security.util.SecurityConstants;
 
@@ -58,9 +60,10 @@
  *                                 ModuleFinder.empty(),
  *                                 "myapp");
  *
- *     ClassLoader loader = new ModuleClassLoader(cf);
- *
- *     Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+ *     Layer layer
+ *         = Layer.createWithOneLoader(cf,
+ *                                     Layer.boot(),
+ *                                     ClassLoader.getSystemClassLoader());
  *
  *     Class<?> c = layer.findLoader("myapp").loadClass("app.Main");
  * }</pre>
@@ -156,18 +159,13 @@
      *
      * </ul>
      *
-     * <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 loaders that the {@code ClassLoaderFinder} returns. </p>
-     *
      * @implNote Some of the failure reasons listed cannot be detected in
      * advance, hence it is possible for Layer.create to fail with some of the
      * modules in the configuration defined to the run-time.
      *
      * @param  cf
      *         The configuration to instantiate as a layer
-     * @param  parent
+     * @param  parentLayer
      *         The parent layer
      * @param  clf
      *         The {@code ClassLoaderFinder} to map modules to class loaders
@@ -181,27 +179,21 @@
      *         If creating the {@code Layer} fails for any of the reasons
      *         listed above
      * @throws SecurityException
-     *         If denied by the security manager
+     *         If {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
      */
-    public static Layer create(Configuration cf, Layer parent, ClassLoaderFinder clf) {
-        Objects.requireNonNull(cf);
-        Objects.requireNonNull(parent);
+    public static Layer create(Configuration cf,
+                               Layer parentLayer,
+                               ClassLoaderFinder clf)
+    {
+        checkConfiguration(cf, parentLayer);
         Objects.requireNonNull(clf);
 
-        // The configuration parent and the configuration for the parent layer
-        // must be the same
-        Optional<Configuration> oparent = cf.parent();
-        if (!oparent.isPresent() || oparent.get() != parent.configuration()) {
-            throw new IllegalArgumentException(
-                    "Parent of configuration != configuration of parent Layer");
-        }
-
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
         }
 
-
         // For now, no two modules in the boot Layer may contain the same
         // package so we use a simple check for the boot Layer to keep
         // the overhead at startup to a minimum
@@ -212,13 +204,137 @@
         }
 
         try {
-            return new Layer(cf, parent, clf);
+            return new Layer(cf, parentLayer, clf);
         } catch (IllegalArgumentException iae) {
             // IAE is thrown by VM when defining the module fails
             throw new LayerInstantiationException(iae.getMessage());
         }
     }
 
+
+    /**
+     * Creates a {@code 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> 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 to instantiate as a layer
+     * @param  parentLayer
+     *         The parent layer
+     * @param  parentLoader
+     *         The parent class loader for each of the class loaders created
+     *         by this method
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         of the parent {@code Layer}
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public static Layer createWithManyLoaders(Configuration cf,
+                                              Layer parentLayer,
+                                              ClassLoader parentLoader)
+    {
+        checkConfiguration(cf, parentLayer);
+        checkCreateClassLoaderPermission();
+
+        LoaderPool pool = new LoaderPool(cf, parentLayer, parentLoader);
+        return new Layer(cf, parentLayer, pool::loaderFor);
+    }
+
+
+    /**
+     * Creates a {@code 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> Attempting to define all modules to the same class loader may fail
+     * for the following reasons:
+     *
+     * <ul>
+     *
+     *     <li> Overlapping packages: Two or more modules in the configuration
+     *          have the same package (exported or concealed). </li>
+     *
+     *     <li> Split delegation: The resulting class loader would need to
+     *          delegate to more than one class loader in order to load types
+     *          in a specific package. </li>
+     *
+     * </ul>
+     *
+     * <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 to instantiate as a layer
+     * @param  parentLayer
+     *         The parent layer
+     * @param  parentLoader
+     *         The parent class loader for the class loader created by this
+     *         method
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         of the parent {@code Layer}
+     * @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")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public static Layer createWithOneLoader(Configuration cf,
+                                            Layer parentLayer,
+                                            ClassLoader parentLoader)
+    {
+        checkConfiguration(cf, parentLayer);
+        checkCreateClassLoaderPermission();
+
+        Loader loader;
+        try {
+            loader = new Loader(cf.modules(), parentLoader)
+                .initRemotePackageMap(cf, parentLayer);
+        } catch (IllegalArgumentException e) {
+            throw new LayerInstantiationException(e.getMessage());
+        }
+        return new Layer(cf, parentLayer, mn -> loader);
+    }
+
+
+    private static void checkConfiguration(Configuration cf, Layer parentLayer) {
+        Objects.requireNonNull(cf);
+        Objects.requireNonNull(parentLayer);
+
+        Optional<Configuration> oparent = cf.parent();
+        if (!oparent.isPresent() || oparent.get() != parentLayer.configuration()) {
+            throw new IllegalArgumentException(
+                    "Parent of configuration != configuration of parent Layer");
+        }
+    }
+
+    private static void checkCreateClassLoaderPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
+    }
+
+
     /**
      * Checks a configuration for the boot Layer to ensure that no two modules
      * have the same package.
--- a/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Dec 17 17:00:18 2015 +0000
@@ -43,11 +43,13 @@
 import java.security.AccessControlContext;
 import java.security.PrivilegedAction;
 
+import jdk.internal.misc.BootLoader;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.Loader;
+import jdk.internal.misc.LoaderPool;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ServicesCatalog;
 import jdk.internal.module.ServicesCatalog.ServiceProvider;
-import jdk.internal.misc.BootLoader;
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
 
 import sun.misc.VM;
 import sun.reflect.CallerSensitive;
@@ -672,6 +674,22 @@
          * service} in modules defined to the given class loader.
          */
         private Iterator<ServiceProvider> iteratorFor(ClassLoader loader) {
+
+            // if the class loader is in a loader pool then return an Iterator
+            // that iterates over all service providers in the pool that provide
+            // an implementation of the service
+            if (currentLoader instanceof Loader) {
+                LoaderPool pool = ((Loader) loader).pool();
+                if (pool != null) {
+                    return pool.loaders()
+                            .map(l -> langAccess.getServicesCatalog(l))
+                            .filter(sc -> sc != null)
+                            .map(sc -> sc.findServices(service.getName()))
+                            .flatMap(Set::stream)
+                            .iterator();
+                }
+            }
+
             ServicesCatalog catalog;
             if (currentLoader == null) {
                 catalog = BootLoader.getServicesCatalog();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/Loader.java	Thu Dec 17 17:00:18 2015 +0000
@@ -0,0 +1,545 @@
+/*
+ * 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.  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.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Layer;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * A class loader that loads classes and resources from a collection of
+ * modules, or from a single module where the class loader is a member
+ * of a pool of class loaders.
+ *
+ * <p> The delegation model used by this ClassLoader differs to the regular
+ * delegation model. When requested to load a class then this ClassLoader first
+ * maps the class name to its package name. If there a module defined to the
+ * Loader containing the package then the class loader attempts to load from
+ * that module. If the package is instead defined to a module in a "remote"
+ * ClassLoader then this class loader delegates directly to that class loader.
+ * The map of package name to remote class loader is created based on the
+ * modules read by modules defined to this class loader. If the package is not
+ * local or remote then this class loader will delegate to the parent class
+ * loader. This allows automatic modules (for example) to link to types in the
+ * unnamed module of the parent class loader.
+ *
+ * @see Layer#createWithOneLoader
+ * @see Layer#createWithManyLoaders
+ */
+
+public final class Loader extends SecureClassLoader {
+
+    static {
+        ClassLoader.registerAsParallelCapable();
+    }
+
+    // the loader pool is in a pool, can be null
+    private final LoaderPool pool;
+
+    // parent ClassLoader, can be null
+    private final ClassLoader parent;
+
+    // maps a module name to a module reference
+    private final Map<String, ModuleReference> nameToModule;
+
+    // maps package name to a module loaded by this class loader
+    private final Map<String, LoadedModule> localPackageToModule;
+
+    // maps package name to a remote class loader, populated post initialization
+    private final Map<String, ClassLoader> remotePackageToLoader
+        = new ConcurrentHashMap<>();
+
+    // maps a module reference to a module reader, populated lazily
+    private final Map<ModuleReference, ModuleReader> moduleToReader
+        = new ConcurrentHashMap<>();
+
+    // ACC used when loading classes and resources */
+    private final AccessControlContext acc;
+
+    /**
+     * A module defined/loaded to a {@code Loader}.
+     */
+    private static class LoadedModule {
+        private final ModuleReference mref;
+        private final URL url;          // may be null
+        private final CodeSource cs;
+
+        LoadedModule( ModuleReference mref) {
+            URL url = null;
+            if (mref.location().isPresent()) {
+                try {
+                    url = mref.location().get().toURL();
+                } catch (MalformedURLException e) { }
+            }
+            this.mref = mref;
+            this.url = url;
+            this.cs = new CodeSource(url, (CodeSigner[]) null);
+        }
+
+        ModuleReference mref() { return mref; }
+        String name() { return mref.descriptor().name(); }
+        URL location() { return url; }
+        CodeSource codeSource() { return cs; }
+    }
+
+
+    /**
+     * Creates a {@code Loader} in a loader pool that loads classes/resources
+     * from one module.
+     */
+    public Loader(ModuleReference mref, LoaderPool pool, ClassLoader parent) {
+        super(parent);
+
+        this.pool = pool;
+        this.parent = parent;
+
+        ModuleDescriptor descriptor = mref.descriptor();
+        String name = descriptor.name();
+        this.nameToModule = Collections.singletonMap(name, mref);
+
+        Map<String, LoadedModule> localPackageToModule = new HashMap<>();
+        LoadedModule lm = new LoadedModule(mref);
+        descriptor.packages().forEach(pn -> localPackageToModule.put(pn, lm));
+        this.localPackageToModule = localPackageToModule;
+
+        this.acc = AccessController.getContext();
+    }
+
+    /**
+     * Creates a {@code Loader} that loads classes/resources from a collection
+     * of modules.
+     *
+     * @throws IllegalArgumentException
+     *         If two or more modules have the same package
+     */
+    public Loader(Collection<ModuleReference> mrefs, ClassLoader parent) {
+        super(parent);
+
+        this.pool = null;
+        this.parent = parent;
+
+        Map<String, ModuleReference> nameToModule = new HashMap<>();
+        Map<String, LoadedModule> localPackageToModule = new HashMap<>();
+        for (ModuleReference mref : mrefs) {
+            ModuleDescriptor descriptor = mref.descriptor();
+            nameToModule.put(descriptor.name(), mref);
+            descriptor.packages().forEach(pn -> {
+                LoadedModule lm = new LoadedModule(mref);
+                if (localPackageToModule.put(pn, lm) != null)
+                    throw new IllegalArgumentException("Package "
+                        + pn + " in more than one module");
+            });
+        }
+        this.nameToModule = nameToModule;
+        this.localPackageToModule = localPackageToModule;
+
+        this.acc = AccessController.getContext();
+    }
+
+
+    /**
+     * Completes initialization of this Loader. This method populates
+     * remotePackageToLoader with the packages of the remote modules, where
+     * "remote modules" are the modules read by modules defined to this loader.
+     *
+     * @param cf the Configuration containing the modules to be defined to
+     *           this class loader
+     *
+     * @param parentLayer the parent Layer
+     */
+    public Loader initRemotePackageMap(Configuration cf, Layer parentLayer) {
+
+        for (ModuleReference mref : nameToModule.values()) {
+
+            for (Configuration.ReadDependence rd : cf.reads(mref.descriptor())) {
+                String mn = rd.descriptor().name();
+                ClassLoader loader;
+
+                if (rd.configuration() == cf) {
+
+                    // The module reads another module in the newly created
+                    // layer. If all modules are defined to the same class
+                    // loader then the packages are local.
+                    if (pool == null) {
+                        assert nameToModule.containsKey(mn);
+                        continue;
+                    }
+
+                    loader = pool.loaderFor(mn);
+                    assert loader != null;
+
+                } else {
+
+                    // find the layer contains the module that is read
+                    Layer layer = parentLayer;
+                    while (layer != null) {
+                        if (layer.configuration() == rd.configuration()) {
+                            break;
+                        }
+                        layer = layer.parent().orElse(null);
+                    }
+                    assert layer != null;
+
+                    // find the class loader for the module in the layer
+                    // For now we use the ext loader for modules defined to the
+                    // boot loader
+                    assert layer.findModule(mn).isPresent();
+                    loader = layer.findLoader(mn);
+                    if (loader == null)
+                        loader = ClassLoaders.extClassLoader();
+                }
+
+                // find the packages that are exported to the target module
+                String target = mref.descriptor().name();
+                for (ModuleDescriptor.Exports e : rd.descriptor().exports()) {
+                    Optional<Set<String>> targets = e.targets();
+                    if (!targets.isPresent() || targets.get().contains(target)) {
+                        String pn = e.source();
+                        ClassLoader l = remotePackageToLoader.putIfAbsent(pn, loader);
+                        if (l != null && l != loader) {
+                            throw new IllegalArgumentException("Package "
+                                + pn + " cannot be imported from multiple loaders");
+                        }
+
+                    }
+                }
+            }
+
+        }
+
+        return this;
+    }
+
+    /**
+     * Returns the loader pool that this loader is in or {@code null} if this
+     * loader is not in a loader pool.
+     */
+    public LoaderPool pool() {
+        return pool;
+    }
+
+
+    // -- resources --
+
+
+    /**
+     * Returns a URL to a resource of the given name in a module defined to
+     * this class loader.
+     */
+    @Override
+    protected URL findResource(String mn, String name) throws IOException {
+        ModuleReference mref = nameToModule.get(mn);
+        if (mref == null)
+            return null;   // not defined to this class loader
+
+        try {
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<URL>() {
+                    @Override
+                    public URL run() throws IOException {
+                        Optional<URI> ouri = moduleReaderFor(mref).find(name);
+                        if (ouri.isPresent()) {
+                            try {
+                                return ouri.get().toURL();
+                            } catch (MalformedURLException e) { }
+                        }
+                        return null;
+                    }
+                }, acc);
+        } catch (PrivilegedActionException pae) {
+            throw (IOException) pae.getCause();
+        }
+    }
+
+
+    // -- finding/loading classes
+
+    /**
+     * Finds the class with the specified binary name.
+     */
+    @Override
+    protected Class<?> findClass(String cn) throws ClassNotFoundException {
+        Class<?> c = null;
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule != null)
+            c = findClassInModuleOrNull(loadedModule, cn);
+        if (c == null)
+            throw new ClassNotFoundException(cn);
+        return c;
+    }
+
+    /**
+     * Finds the class with the specified binary name in a given module.
+     * This method returns {@code null} if the class cannot be found.
+     */
+    @Override
+    protected Class<?> findClass(String mn, String cn) {
+        Class<?> c = null;
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule != null && loadedModule.name().equals(mn))
+            c = findClassInModuleOrNull(loadedModule, cn);
+        return c;
+    }
+
+    /**
+     * Loads the class with the specified binary name.
+     */
+    @Override
+    protected Class<?> loadClass(String cn, boolean resolve)
+        throws ClassNotFoundException
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            String pn = packageName(cn);
+            if (!pn.isEmpty()) {
+                sm.checkPackageAccess(pn);
+            }
+        }
+
+        synchronized (getClassLoadingLock(cn)) {
+            // check if already loaded
+            Class<?> c = findLoadedClass(cn);
+
+            if (c == null) {
+
+                LoadedModule loadedModule = findLoadedModule(cn);
+
+                if (loadedModule != null) {
+
+                    // class is in module defined to this class loader
+                    c = findClassInModuleOrNull(loadedModule, cn);
+
+                } else {
+
+                    // type in another module or visible via the parent loader
+                    String pn = packageName(cn);
+                    ClassLoader loader = remotePackageToLoader.get(pn);
+                    if (loader == null) {
+                        // type not in a module read by any of the modules
+                        // defined to this loader, so delegate to parent
+                        // class loader
+                        loader = parent;
+                    }
+                    if (loader == null) {
+                        c = BootLoader.loadClassOrNull(cn);
+                    } else {
+                        c = loader.loadClass(cn);
+                    }
+
+                }
+            }
+
+            if (c == null)
+                throw new ClassNotFoundException(cn);
+
+            if (resolve)
+                resolveClass(c);
+
+            return c;
+        }
+    }
+
+
+    /**
+     * Finds the class with the specified binary name if in a module
+     * defined to this ClassLoader.
+     *
+     * @return the resulting Class or {@code null} if not found
+     */
+    private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
+        PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
+        return AccessController.doPrivileged(pa, acc);
+    }
+
+    /**
+     * Defines the given binary class name to the VM, loading the class
+     * bytes from the given module.
+     *
+     * @return the resulting Class or {@code null} if an I/O error occurs
+     */
+    private Class<?> defineClass(String cn, LoadedModule loadedModule) {
+        ModuleReader reader = moduleReaderFor(loadedModule.mref());
+
+        try {
+            // read class file
+            String rn = cn.replace('.', '/').concat(".class");
+            ByteBuffer bb = reader.read(rn).orElse(null);
+            if (bb == null) {
+                // class not found
+                return null;
+            }
+
+            try {
+
+                // define the package if not already defined
+                String pn = packageName(cn);
+                if (getDefinedPackage(pn) == null) {
+                    definePackage(pn, loadedModule);
+                }
+
+                return defineClass(cn, bb, loadedModule.codeSource());
+
+            } finally {
+                reader.release(bb);
+            }
+
+        } catch (IOException ioe) {
+            // TBD on how I/O errors should be propagated
+            return null;
+        }
+    }
+
+
+    // -- packages
+
+    /**
+     * Define a Package this to this class loader. The resulting Package
+     * is sealed with the code source that is the module location.
+     */
+    private Package definePackage(String pn, LoadedModule loadedModule) {
+        URL url = loadedModule.location();
+
+        // can this throw IAE?
+        return definePackage(pn, null, null, null, null, null, null, url);
+    }
+
+
+    // -- permissions
+
+    /**
+     * Returns the permissions for the given CodeSource.
+     */
+    @Override
+    protected PermissionCollection getPermissions(CodeSource cs) {
+        PermissionCollection perms = super.getPermissions(cs);
+
+        URL url = cs.getLocation();
+        if (url == null)
+            return perms;
+
+        // add the permission to access the resource
+        try {
+            Permission p = url.openConnection().getPermission();
+            if (p != null) {
+                // for directories then need recursive access
+                if (p instanceof FilePermission) {
+                    String path = p.getName();
+                    if (path.endsWith(File.separator)) {
+                        path += "-";
+                        p = new FilePermission(path, "read");
+                    }
+                }
+                perms.add(p);
+            }
+        } catch (IOException ioe) { }
+
+        return perms;
+    }
+
+
+    // -- miscellaneous supporting methods
+
+    /**
+     * Find the candidate module for the given class name.
+     * Returns {@code null} if none of the modules defined to this
+     * class loader contain the API package for the class.
+     */
+    private LoadedModule findLoadedModule(String cn) {
+        String pn = packageName(cn);
+        return pn.isEmpty() ? null : localPackageToModule.get(pn);
+    }
+
+    /**
+     * Returns the package name for the given class name
+     */
+    private String packageName(String cn) {
+        int pos = cn.lastIndexOf('.');
+        return (pos < 0) ? "" : cn.substring(0, pos);
+    }
+
+
+    /**
+     * Returns the ModuleReader for the given module.
+     */
+    private ModuleReader moduleReaderFor(ModuleReference mref) {
+        return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref));
+    }
+
+    /**
+     * Creates a ModuleReader for the given module.
+     */
+    private ModuleReader createModuleReader(ModuleReference mref) {
+        try {
+            return mref.open();
+        } catch (IOException e) {
+            // Return a null module reader to avoid a future class load
+            // attempting to open the module again.
+            return new NullModuleReader();
+        }
+    }
+
+    /**
+     * A ModuleReader that doesn't read any resources.
+     */
+    private static class NullModuleReader implements ModuleReader {
+        @Override
+        public Optional<URI> find(String name) {
+            return Optional.empty();
+        }
+        @Override
+        public void close() {
+            throw new InternalError("Should not get here");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/LoaderPool.java	Thu Dec 17 17:00:18 2015 +0000
@@ -0,0 +1,85 @@
+/*
+ * 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.  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.Configuration;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Layer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+/**
+ * A pool of class loaders.
+ *
+ * @see Layer#createWithManyLoaders
+ */
+
+public final class LoaderPool {
+
+    // maps module names to class loaders
+    private final Map<String, Loader> loaders;
+
+
+    /**
+     * Creates a pool of class loaders. Each module in the given configuration
+     * will be loaded its own class loader in the pool. The class loader is
+     * created with the given parent class loader as its parent.
+     */
+    public LoaderPool(Configuration cf,
+                      Layer parentLayer,
+                      ClassLoader parentLoader)
+    {
+        Map<String, Loader> loaders = new HashMap<>();
+        for (ModuleReference mref : cf.modules()) {
+            Loader loader = new Loader(mref, this, parentLoader);
+            loaders.put(mref.descriptor().name(), loader);
+        }
+        this.loaders = loaders;
+
+        // complete the initialization
+        loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer));
+    }
+
+
+    /**
+     * Returns the class loader for the named module
+     */
+    public Loader loaderFor(String name) {
+        Loader loader = loaders.get(name);
+        assert loader != null;
+        return loader;
+    }
+
+    /**
+     * Returns a stream of the loaders in this pool.
+     */
+    public Stream<Loader> loaders() {
+        return loaders.values().stream();
+    }
+
+}
+
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/TaskHelper.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/TaskHelper.java	Thu Dec 17 17:00:18 2015 +0000
@@ -901,11 +901,8 @@
 
         cf = cf.bind();
 
-        // The creation of this classloader is done outside privileged block in purpose
-        // If a security manager is set, then permission must be granted to jlink
-        // codebase to create a classloader. This is the expected behavior.
-        ClassLoader cl = new ModuleClassLoader(cf);
-        return Layer.create(cf, Layer.boot(), mn -> cl);
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        return Layer.createWithOneLoader(cf, Layer.boot(), scl);
     }
 
     // Display all plugins or resource only.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jigsaw/reflect/Layer/BasicLayerTest.java	Thu Dec 17 17:00:18 2015 +0000
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @library ../../lib
+ * @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.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.Set;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class BasicLayerTest {
+
+    /**
+     * Exercise Layer.empty()
+     */
+    public void testEmpty() {
+        Layer emptyLayer = Layer.empty();
+
+        assertFalse(emptyLayer.parent().isPresent());
+
+        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.findDescriptor("java.base").get().exports()
+                   .stream().anyMatch(e -> (e.source().equals("java.lang")
+                                            && !e.targets().isPresent())));
+
+        // 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);
+
+        // parent
+        assertTrue(bootLayer.parent().get() == Layer.empty());
+    }
+
+
+    /**
+     * Exercise Layer.create, created on an empty layer
+     */
+    public void testLayerOnEmpty() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .exports("p1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m3")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "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.create(cf, Layer.empty(), map::get);
+
+        // configuration
+        assertTrue(layer.configuration() == cf);
+        assertTrue(layer.configuration().descriptors().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) { }
+
+        // parent
+        assertTrue(layer.parent().get() == Layer.empty());
+    }
+
+
+    /**
+     * Exercise Layer.create, created over the boot layer
+     */
+    public void testLayerOnBoot() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .requires("java.base")
+                .exports("p1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Layer.boot().configuration(),
+                                    ModuleFinder.empty(),
+                                    "m1");
+
+        ClassLoader loader = new ClassLoader() { };
+
+        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+
+        // configuration
+        assertTrue(layer.configuration() == cf);
+        assertTrue(layer.configuration().descriptors().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);
+
+        // parent
+        assertTrue(layer.parent().get() == Layer.boot());
+    }
+
+
+    /**
+     * Layer.create with a configuration of two modules that have the same
+     * module-private package.
+     */
+    public void testSameConcealedPackage() {
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .conceals("p")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m1");
+        assertTrue(cf.descriptors().size() == 2);
+
+        // one loader per module, should be okay
+        Layer.create(cf, Layer.empty(), mn -> new ClassLoader() { });
+
+        // same class loader
+        try {
+            ClassLoader loader = new ClassLoader() { };
+            Layer.create(cf, Layer.empty(), mn -> loader);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+    }
+
+
+    /**
+     * Layer.create with a configuration with a partitioned graph. The same
+     * package is exported in both partitions.
+     */
+    public void testSameExportInPartitionedGraph() {
+
+        // m1 reads m2, m2 exports p to m1
+        ModuleDescriptor descriptor1
+            =  new ModuleDescriptor.Builder("m1")
+                .requires("m2")
+                .build();
+        ModuleDescriptor descriptor2
+            =  new ModuleDescriptor.Builder("m2")
+                .exports("p", "m1")
+                .build();
+
+        // m3 reads m4, m4 exports p to m3
+        ModuleDescriptor descriptor3
+            =  new ModuleDescriptor.Builder("m3")
+                .requires("m4")
+                .build();
+        ModuleDescriptor descriptor4
+            =  new ModuleDescriptor.Builder("m4")
+                .exports("p", "m3")
+                .build();
+
+        ModuleFinder finder
+            = ModuleUtils.finderOf(descriptor1,
+                                   descriptor2,
+                                   descriptor3,
+                                   descriptor4);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m1", "m3");
+        assertTrue(cf.descriptors().size() == 4);
+
+        // one loader per module
+        Layer.create(cf, Layer.empty(), 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("m3", loader2);
+        Layer.create(cf, Layer.empty(), map::get);
+
+        // same loader
+        try {
+            ClassLoader loader = new ClassLoader() { };
+            Layer.create(cf, Layer.empty(), mn -> loader);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+    }
+
+
+    /**
+     * Layer.create with a configuration that contains a module that has a
+     * concealed package that is the same name as a non-exported package
+     * in a parent layer.
+     */
+    public void testConcealSamePackageAsBootLayer() {
+
+        // check assumption that java.base contains sun.launcher
+        ModuleDescriptor base = Object.class.getModule().getDescriptor();
+        assertTrue(base.conceals().contains("sun.launcher"));
+
+
+        ModuleDescriptor descriptor
+            = new ModuleDescriptor.Builder("m1")
+               .requires("java.base")
+               .conceals("sun.launcher")
+               .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration parent = Layer.boot().configuration();
+
+        Configuration cf
+            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m1");
+        assertTrue(cf.descriptors().size() == 1);
+
+        ClassLoader loader = new ClassLoader() { };
+        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        assertTrue(layer.modules().size() == 1);
+   }
+
+
+    /**
+     * Test layers with implied readability.
+     *
+     * The test consists of three configurations:
+     * - Configuration/layer1: m1, m2 requires public m1
+     * - Configuration/layer2: m3 requires m1
+     */
+    public void testImpliedReadabilityWithLayers1() {
+
+        // cf1: m1 and m2, m2 requires public m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1
+            = Configuration.resolve(finder1,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m2");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
+
+
+        // cf2: m3, m3 requires m2
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2
+            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m3");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == 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 public m3, m3 requires m2
+     */
+    public void testImpliedReadabilityWithLayers2() {
+
+        // cf1: m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1
+            = Configuration.resolve(finder1,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m1");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
+
+
+        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3);
+
+        Configuration cf2
+            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m3");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == 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 public m1
+     * - Configuration/layer3: m3 requires m1
+     */
+    public void testImpliedReadabilityWithLayers3() {
+
+        // cf1: m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1
+            = Configuration.resolve(finder1,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m1");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
+
+
+        // cf2: m2 requires public m1
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf2
+            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m2");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
+
+
+        // cf3: m3 requires m2
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf3
+            = Configuration.resolve(finder3, cf2, ModuleFinder.empty(), "m3");
+
+        ClassLoader cl3 = new ClassLoader() { };
+        Layer layer3 = Layer.create(cf3, layer2, mn -> cl3);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer3.parent().get() == 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 public m1
+     * - Configuration/layer2: m3 requires public m2, m4 requires m3
+     */
+    public void testImpliedReadabilityWithLayers4() {
+
+        // cf1: m1, m2 requires public m1
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1
+            = Configuration.resolve(finder1,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m2");
+
+        ClassLoader cl1 = new ClassLoader() { };
+        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
+
+
+        // cf2: m3 requires public m2, m4 requires m3
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3")
+                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2")
+                .build();
+
+        ModuleDescriptor descriptor4
+            = new ModuleDescriptor.Builder("m4")
+                .requires("m3")
+                .build();
+
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
+
+        Configuration cf2
+            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(),  "m3", "m4");
+
+        ClassLoader cl2 = new ClassLoader() { };
+        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
+
+        assertTrue(layer1.parent().get() == Layer.empty());
+        assertTrue(layer2.parent().get() == 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));
+    }
+
+
+    /**
+     * Attempt to use Layer.create 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
+            = new ModuleDescriptor.Builder("m")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(md);
+
+        Configuration parent = Layer.boot().configuration();
+
+        Configuration cf
+            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m");
+
+        ClassLoader loader = new ClassLoader() { };
+
+        Layer.create(cf, Layer.boot(), mn -> loader);
+
+        // should throw LayerInstantiationException as m1 already defined to loader
+        Layer.create(cf, Layer.boot(), mn -> loader);
+
+    }
+
+
+    /**
+     * Attempt to use Layer.create 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
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .requires("java.base")
+                .build();
+
+        ModuleDescriptor md2
+            = new ModuleDescriptor.Builder("m2")
+                .conceals("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
+            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m1");
+
+        Layer layer1 = Layer.create(cf1, Layer.boot(), mn -> loader);
+
+        // attempt to define m2 containing package p to class loader
+
+        Configuration cf2
+            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m2");
+
+        // should throw exception because p already in m1
+        Layer layer2 = Layer.create(cf2, Layer.boot(), mn -> loader);
+
+    }
+
+
+    /**
+     * Attempt to use Layer.create 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
+            = new ModuleDescriptor.Builder("m")
+                .conceals(c.getPackageName())
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(md);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Layer.boot().configuration(),
+                                    ModuleFinder.empty(),
+                                    "m");
+
+        Layer.create(cf, Layer.boot(), mn -> c.getClassLoader());
+    }
+
+
+    /**
+     * Parent of configuration != configuration of parent Layer
+     */
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testIncorrectParent1() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .requires("java.base")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Layer.boot().configuration(),
+                                    ModuleFinder.empty(),
+                                    "m1");
+
+        ClassLoader loader = new ClassLoader() { };
+        Layer.create(cf, Layer.empty(), mn -> loader);
+    }
+
+
+    /**
+     * Parent of configuration != configuration of parent Layer
+     */
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testIncorrectParent2() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                                    Configuration.empty(),
+                                    ModuleFinder.empty(),
+                                    "m1");
+
+        ClassLoader loader = new ClassLoader() { };
+        Layer.create(cf, Layer.boot(), mn -> loader);
+    }
+
+
+    // null handling
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull1() {
+        ClassLoader loader = new ClassLoader() { };
+        Layer.create(null, Layer.empty(), mn -> loader);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull2() {
+        ClassLoader loader = new ClassLoader() { };
+        Layer.create(Configuration.empty(), null, mn -> loader);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull3() {
+        Configuration cf
+            = Configuration.resolve(ModuleFinder.empty(),
+                                    Layer.boot().configuration(),
+                                    ModuleFinder.empty());
+        Layer.create(cf, Layer.boot(), null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull4() {
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer.createWithOneLoader(null, Layer.empty(), scl);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull5() {
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer.createWithOneLoader(Configuration.empty(), null, scl);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull6() {
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer.createWithManyLoaders(null, Layer.empty(), scl);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testCreateWithNull7() {
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer.createWithManyLoaders(Configuration.empty(), 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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jigsaw/reflect/Layer/LayerAndLoadersTest.java	Thu Dec 17 17:00:18 2015 +0000
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @library ../../lib
+ * @build LayerAndLoadersTest CompilerUtils ModuleUtils
+ * @run testng LayerAndLoadersTest
+ * @summary Tests for java.lang.reflect.Layer@createWithXXX methods
+ */
+
+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.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Iterator;
+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 -modulesourcepath src src/**
+        assertTrue(CompilerUtils.compile(SRC_DIR, MODS_DIR,
+                "-modulesourcepath", SRC_DIR.toString()));
+    }
+
+
+    /**
+     * Basic test of Layer.createWithOneLoader
+     */
+    public void testWithOneLoader() throws Exception {
+
+        Configuration cf = resolve("m1");
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), scl);
+
+        checkLayer(layer, "m1", "m2");
+
+        ClassLoader cl1 = layer.findLoader("m1");
+        ClassLoader cl2 = layer.findLoader("m2");
+
+        assertTrue(cl1.getParent() == scl);
+        assertTrue(cl2 == cl1);
+
+        invoke(layer, "m1", "p.Main");
+
+    }
+
+
+    /**
+     * Basic test of Layer.createWithManyLoaders
+     */
+    public void testWithManyLoaders() throws Exception {
+
+        Configuration cf = resolve("m1");
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.createWithManyLoaders(cf, Layer.boot(), scl);
+
+        checkLayer(layer, "m1", "m2");
+
+        ClassLoader cl1 = layer.findLoader("m1");
+        ClassLoader cl2 = layer.findLoader("m2");
+
+        assertTrue(cl1.getParent() == scl);
+        assertTrue(cl2.getParent() == scl);
+        assertTrue(cl2 != cl1);
+
+        invoke(layer, "m1", "p.Main");
+
+    }
+
+
+    /**
+     * Basic test of Layer.createWithOneLoader where one of the modules
+     * is a service provider module.
+     */
+    public void testServicesWithOneLoader() throws Exception {
+
+        Configuration cf = resolve("m1").bind();
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), 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);
+
+        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.createWithManyLoaders where one of the modules
+     * is a service provider module.
+     */
+    public void testServicesWithManyLoaders() throws Exception {
+
+        Configuration cf = resolve("m1").bind();
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.createWithManyLoaders(cf, Layer.boot(), 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);
+
+        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() == cl3);
+            assertFalse(iter.hasNext());
+        }
+
+    }
+
+    /**
+     * Tests that the class loaders created by Layer.createWithXXX 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.createWithOneLoader(cf, Layer.boot(), parent);
+        testLoad(layer, cn);
+
+         // one loader with boot loader as parent
+        layer = Layer.createWithOneLoader(cf, Layer.boot(), null);
+        testLoadFail(layer, cn);
+
+        // many loaders
+        layer = Layer.createWithManyLoaders(cf, Layer.boot(), parent);
+        testLoad(layer, cn);
+
+        // many loader with boot loader as parent
+        layer = Layer.createWithManyLoaders(cf, Layer.boot(), null);
+        testLoadFail(layer, cn);
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when modules that have overlapping packages.
+     */
+    public void testOverlappingPackages() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").exports("p").build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2").exports("p").build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf
+            = Configuration.resolve(finder,
+                Layer.boot().configuration(),
+                ModuleFinder.empty(),
+                "m1", "m2");
+
+        // cannot define both module m1 and m2 to the same class loader
+        try {
+            Layer.createWithOneLoader(cf, Layer.boot(), null);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+
+        // should be okay to have one module per class loader
+        Layer layer = Layer.createWithManyLoaders(cf, Layer.boot(), null);
+        checkLayer(layer, "m1", "m2");
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX with split delegation.
+     *
+     * layer1: m1 exports p, m2 exports p
+     * layer2: m3 reads m1, m4 reads m2
+     */
+    public void testSplitDelegation() {
+
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1").exports("p").build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2").exports("p").build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1
+            = Configuration.resolve(finder1,
+                Layer.boot().configuration(),
+                ModuleFinder.empty(),
+                "m1", "m2");
+
+        Layer layer1 = Layer.createWithManyLoaders(cf1, Layer.boot(), null);
+        checkLayer(layer1, "m1", "m2");
+
+
+        ModuleDescriptor descriptor3
+            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+
+        ModuleDescriptor descriptor4
+            = new ModuleDescriptor.Builder("m4").requires("m2").build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
+
+        Configuration cf2
+            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m3", "m4");
+
+        // package p cannot be supplied by two class loaders
+        try {
+            Layer.createWithOneLoader(cf2, layer1, null);
+            assertTrue(false);
+        } catch (LayerInstantiationException expected) { }
+
+        // no split delegation when modules have their own class loader
+        Layer layer2 = Layer.createWithManyLoaders(cf2, layer1, null);
+        checkLayer(layer2, "m3", "m4");
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * layer1: m1, m2 => same loader
+     * layer2: m1, m2 => same loader
+     */
+    public void testOverriding1() throws Exception {
+
+        Configuration cf1 = resolve("m1");
+
+        Layer layer1 = Layer.createWithOneLoader(cf1, Layer.boot(), null);
+        checkLayer(layer1, "m1", "m2");
+
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Configuration cf2 = Configuration.resolve(finder, cf1, ModuleFinder.empty(), "m1");
+
+        Layer layer2 = Layer.createWithOneLoader(cf2, layer1, null);
+        checkLayer(layer2, "m1", "m2");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer1.findLoader("m2");
+        ClassLoader loader3 = layer2.findLoader("m1");
+        ClassLoader loader4 = layer2.findLoader("m2");
+
+        assertTrue(loader1 == loader2);
+        assertTrue(loader3 == loader4);
+        assertTrue(loader3 != loader1);
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1);
+
+        assertTrue(loader3.loadClass("p.Main").getClassLoader() == loader3);
+        assertTrue(loader3.loadClass("q.Hello").getClassLoader() == loader3);
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * layer1: m1, m2 => loader pool
+     * layer2: m1, m2 => loader pool
+     */
+    public void testOverriding2() throws Exception {
+
+        Configuration cf1 = resolve("m1");
+
+        Layer layer1 = Layer.createWithManyLoaders(cf1, Layer.boot(), null);
+        checkLayer(layer1, "m1", "m2");
+
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+        Configuration cf2
+            = Configuration.resolve(finder, cf1, ModuleFinder.empty(), "m1");
+
+        Layer layer2 = Layer.createWithManyLoaders(cf2, layer1, null);
+        checkLayer(layer2, "m1", "m2");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer1.findLoader("m2");
+        ClassLoader loader3 = layer2.findLoader("m1");
+        ClassLoader loader4 = layer2.findLoader("m2");
+
+        assertTrue(loader1 != loader2);
+        assertTrue(loader1 != loader3);
+        assertTrue(loader1 != loader4);
+        assertTrue(loader2 != loader3);
+        assertTrue(loader2 != loader4);
+        assertTrue(loader3 != loader4);
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2);
+        assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader2);
+
+        // p.Main is not visible via loader2
+        try {
+            loader2.loadClass("p.Main");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+
+        assertTrue(loader3.loadClass("p.Main").getClassLoader() == loader3);
+        assertTrue(loader3.loadClass("q.Hello").getClassLoader() == loader4);
+        assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader4);
+
+        // p.Main is not visible via loader4
+        try {
+            loader2.loadClass("p.Main");
+            assertTrue(false);
+        } catch (ClassNotFoundException expected) { }
+
+    }
+
+
+    /**
+     * Test Layer.createWithXXX when the modules that override same named
+     * modules in the parent layer.
+     *
+     * layer1: m1, m2 => same loader
+     * layer2: m1 => one loader
+     */
+    public void testOverriding3() throws Exception {
+
+        Configuration cf1 = resolve("m1");
+
+        Layer layer1 = Layer.createWithOneLoader(cf1, Layer.boot(), null);
+        checkLayer(layer1, "m1", "m2");
+
+
+        // ModuleFinder that only finds m1
+        ModuleFinder finder = new ModuleFinder() {
+            ModuleReference mref = ModuleFinder.of(MODS_DIR).find("m1").get();
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                if (name.equals("m1")) {
+                    return Optional.of(mref);
+                } else {
+                    return Optional.empty();
+                }
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                return Collections.singleton(mref);
+            }
+        };
+
+        Configuration cf2
+            = Configuration.resolve(finder, cf1, ModuleFinder.empty(), "m1");
+
+        Layer layer2 = Layer.createWithOneLoader(cf2, layer1, null);
+        checkLayer(layer2, "m1");
+        invoke(layer1, "m1", "p.Main");
+
+        ClassLoader loader1 = layer1.findLoader("m1");
+        ClassLoader loader2 = layer1.findLoader("m2");
+        ClassLoader loader3 = layer2.findLoader("m1");
+
+        assertTrue(loader1 == loader2);
+        assertTrue(loader3 != loader1);
+
+        assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1);
+        assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1);
+
+        assertTrue(loader3.loadClass("p.Main").getClassLoader() == loader3);
+        assertTrue(loader3.loadClass("q.Hello").getClassLoader() == loader1);
+
+    }
+
+
+    // test qualified exports?
+
+
+    // -- supporting methods --
+
+
+    /**
+     * Resolve the given modules, by name, and return the resulting
+     * Configuration.
+     */
+    private static Configuration resolve(String... roots) {
+        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
+
+        return Configuration.resolve(finder,
+                Layer.boot().configuration(),
+                ModuleFinder.empty(),
+                "m1");
+    }
+
+
+    /**
+     * 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) { }
+        }
+    }
+
+}
--- a/test/jdk/jigsaw/reflect/Layer/LayerTest.java	Thu Dec 17 11:02:49 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,894 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @library ../../lib
- * @build LayerTest ModuleUtils
- * @compile layertest/Test.java
- * @run testng LayerTest
- * @summary Basic tests for java.lang.reflect.Layer
- */
-
-import java.lang.module.Configuration;
-import java.lang.module.ModuleDescriptor;
-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.Set;
-import java.util.stream.Collectors;
-
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-@Test
-public class LayerTest {
-
-    /**
-     * Exercise Layer.empty()
-     */
-    public void testEmpty() {
-        Layer emptyLayer = Layer.empty();
-
-        assertFalse(emptyLayer.parent().isPresent());
-
-        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.findDescriptor("java.base").get().exports()
-                   .stream().anyMatch(e -> (e.source().equals("java.lang")
-                                            && !e.targets().isPresent())));
-
-        // 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);
-
-        // parent
-        assertTrue(bootLayer.parent().get() == Layer.empty());
-    }
-
-
-    /**
-     * Exercise Layer.create, created on an empty layer
-     */
-    public void testLayerOnEmpty() {
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .exports("p1")
-                .build();
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires("m3")
-                .build();
-
-        ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .build();
-
-        ModuleFinder finder
-            = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "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.create(cf, Layer.empty(), map::get);
-
-        // configuration
-        assertTrue(layer.configuration() == cf);
-        assertTrue(layer.configuration().descriptors().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) { }
-
-        // parent
-        assertTrue(layer.parent().get() == Layer.empty());
-    }
-
-
-    /**
-     * Exercise Layer.create, created over the boot layer
-     */
-    public void testLayerOnBoot() {
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .requires("java.base")
-                .exports("p1")
-                .build();
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires("java.base")
-                .build();
-
-        ModuleFinder finder
-            = ModuleUtils.finderOf(descriptor1, descriptor2);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Layer.boot().configuration(),
-                                    ModuleFinder.empty(),
-                                    "m1");
-
-        ClassLoader loader = new ClassLoader() { };
-
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
-
-        // configuration
-        assertTrue(layer.configuration() == cf);
-        assertTrue(layer.configuration().descriptors().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);
-
-        // parent
-        assertTrue(layer.parent().get() == Layer.boot());
-    }
-
-
-    /**
-     * Layer.create with a configuration of two modules that have the same
-     * module-private package.
-     */
-    public void testSameConcealedPackage() {
-        ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .conceals("p")
-                .build();
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .conceals("p")
-                .build();
-
-        ModuleFinder finder
-            = ModuleUtils.finderOf(descriptor1, descriptor2);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m1");
-        assertTrue(cf.descriptors().size() == 2);
-
-        // one loader per module, should be okay
-        Layer.create(cf, Layer.empty(), mn -> new ClassLoader() { });
-
-        // same class loader
-        try {
-            ClassLoader loader = new ClassLoader() { };
-            Layer.create(cf, Layer.empty(), mn -> loader);
-            assertTrue(false);
-        } catch (LayerInstantiationException expected) { }
-    }
-
-
-    /**
-     * Layer.create with a configuration with a partitioned graph. The same
-     * package is exported in both partitions.
-     */
-    public void testSameExportInPartitionedGraph() {
-
-        // m1 reads m2, m2 exports p to m1
-        ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .build();
-        ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .exports("p", "m1")
-                .build();
-
-        // m3 reads m4, m4 exports p to m3
-        ModuleDescriptor descriptor3
-            =  new ModuleDescriptor.Builder("m3")
-                .requires("m4")
-                .build();
-        ModuleDescriptor descriptor4
-            =  new ModuleDescriptor.Builder("m4")
-                .exports("p", "m3")
-                .build();
-
-        ModuleFinder finder
-            = ModuleUtils.finderOf(descriptor1,
-                                   descriptor2,
-                                   descriptor3,
-                                   descriptor4);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m1", "m3");
-        assertTrue(cf.descriptors().size() == 4);
-
-        // one loader per module
-        Layer.create(cf, Layer.empty(), 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("m3", loader2);
-        Layer.create(cf, Layer.empty(), map::get);
-
-        // same loader
-        try {
-            ClassLoader loader = new ClassLoader() { };
-            Layer.create(cf, Layer.empty(), mn -> loader);
-            assertTrue(false);
-        } catch (LayerInstantiationException expected) { }
-    }
-
-
-    /**
-     * Layer.create with a configuration that contains a module that has a
-     * concealed package that is the same name as a non-exported package
-     * in a parent layer.
-     */
-    public void testConcealSamePackageAsBootLayer() {
-
-        // check assumption that java.base contains sun.launcher
-        ModuleDescriptor base = Object.class.getModule().getDescriptor();
-        assertTrue(base.conceals().contains("sun.launcher"));
-
-
-        ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m1")
-               .requires("java.base")
-               .conceals("sun.launcher")
-               .build();
-
-        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
-
-        Configuration parent = Layer.boot().configuration();
-
-        Configuration cf
-            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m1");
-        assertTrue(cf.descriptors().size() == 1);
-
-        ClassLoader loader = new ClassLoader() { };
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
-        assertTrue(layer.modules().size() == 1);
-   }
-
-
-    /**
-     * Test layers with implied readability.
-     *
-     * The test consists of three configurations:
-     * - Configuration/layer1: m1, m2 requires public m1
-     * - Configuration/layer2: m3 requires m1
-     */
-    public void testImpliedReadabilityWithLayers1() {
-
-        // cf1: m1 and m2, m2 requires public m1
-
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .build();
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
-                .build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
-
-        Configuration cf1
-            = Configuration.resolve(finder1,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m2");
-
-        ClassLoader cl1 = new ClassLoader() { };
-        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
-
-
-        // cf2: m3, m3 requires m2
-
-        ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires("m2")
-                .build();
-
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
-
-        Configuration cf2
-            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m3");
-
-        ClassLoader cl2 = new ClassLoader() { };
-        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
-
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == 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 public m3, m3 requires m2
-     */
-    public void testImpliedReadabilityWithLayers2() {
-
-        // cf1: m1
-
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
-
-        Configuration cf1
-            = Configuration.resolve(finder1,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m1");
-
-        ClassLoader cl1 = new ClassLoader() { };
-        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
-
-
-        // cf2: m2, m3: m2 requires public m1, m3 requires m2
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
-                .build();
-
-        ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires("m2")
-                .build();
-
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3);
-
-        Configuration cf2
-            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m3");
-
-        ClassLoader cl2 = new ClassLoader() { };
-        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
-
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == 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 public m1
-     * - Configuration/layer3: m3 requires m1
-     */
-    public void testImpliedReadabilityWithLayers3() {
-
-        // cf1: m1
-
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
-
-        Configuration cf1
-            = Configuration.resolve(finder1,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m1");
-
-        ClassLoader cl1 = new ClassLoader() { };
-        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
-
-
-        // cf2: m2 requires public m1
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
-                .build();
-
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
-
-        Configuration cf2
-            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(), "m2");
-
-        ClassLoader cl2 = new ClassLoader() { };
-        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
-
-
-        // cf3: m3 requires m2
-
-        ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires("m2")
-                .build();
-
-        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3);
-
-        Configuration cf3
-            = Configuration.resolve(finder3, cf2, ModuleFinder.empty(), "m3");
-
-        ClassLoader cl3 = new ClassLoader() { };
-        Layer layer3 = Layer.create(cf3, layer2, mn -> cl3);
-
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
-        assertTrue(layer3.parent().get() == 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 public m1
-     * - Configuration/layer2: m3 requires public m2, m4 requires m3
-     */
-    public void testImpliedReadabilityWithLayers4() {
-
-        // cf1: m1, m2 requires public m1
-
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .build();
-
-        ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
-                .build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
-
-        Configuration cf1
-            = Configuration.resolve(finder1,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m2");
-
-        ClassLoader cl1 = new ClassLoader() { };
-        Layer layer1 = Layer.create(cf1, Layer.empty(), mn -> cl1);
-
-
-        // cf2: m3 requires public m2, m4 requires m3
-
-        ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2")
-                .build();
-
-        ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
-                .requires("m3")
-                .build();
-
-
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
-
-        Configuration cf2
-            = Configuration.resolve(finder2, cf1, ModuleFinder.empty(),  "m3", "m4");
-
-        ClassLoader cl2 = new ClassLoader() { };
-        Layer layer2 = Layer.create(cf2, layer1, mn -> cl2);
-
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == 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));
-    }
-
-
-    /**
-     * Attempt to use Layer.create 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
-            = new ModuleDescriptor.Builder("m")
-                .requires("java.base")
-                .build();
-
-        ModuleFinder finder = ModuleUtils.finderOf(md);
-
-        Configuration parent = Layer.boot().configuration();
-
-        Configuration cf
-            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m");
-
-        ClassLoader loader = new ClassLoader() { };
-
-        Layer.create(cf, Layer.boot(), mn -> loader);
-
-        // should throw LayerInstantiationException as m1 already defined to loader
-        Layer.create(cf, Layer.boot(), mn -> loader);
-
-    }
-
-
-    /**
-     * Attempt to use Layer.create 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
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
-                .requires("java.base")
-                .build();
-
-        ModuleDescriptor md2
-            = new ModuleDescriptor.Builder("m2")
-                .conceals("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
-            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m1");
-
-        Layer layer1 = Layer.create(cf1, Layer.boot(), mn -> loader);
-
-        // attempt to define m2 containing package p to class loader
-
-        Configuration cf2
-            = Configuration.resolve(finder, parent, ModuleFinder.empty(), "m2");
-
-        // should throw exception because p already in m1
-        Layer layer2 = Layer.create(cf2, Layer.boot(), mn -> loader);
-
-    }
-
-
-    /**
-     * Attempt to use Layer.create 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
-            = new ModuleDescriptor.Builder("m")
-                .conceals(c.getPackageName())
-                .requires("java.base")
-                .build();
-
-        ModuleFinder finder = ModuleUtils.finderOf(md);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Layer.boot().configuration(),
-                                    ModuleFinder.empty(),
-                                    "m");
-
-        Layer.create(cf, Layer.boot(), mn -> c.getClassLoader());
-    }
-
-
-    /**
-     * Parent of configuration != configuration of parent Layer
-     */
-    @Test(expectedExceptions = { IllegalArgumentException.class })
-    public void testIncorrectParent1() {
-
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .requires("java.base")
-                .build();
-
-        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Layer.boot().configuration(),
-                                    ModuleFinder.empty(),
-                                    "m1");
-
-        ClassLoader loader = new ClassLoader() { };
-        Layer.create(cf, Layer.empty(), mn -> loader);
-    }
-
-
-    /**
-     * Parent of configuration != configuration of parent Layer
-     */
-    @Test(expectedExceptions = { IllegalArgumentException.class })
-    public void testIncorrectParent2() {
-
-        ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .build();
-
-        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
-
-        Configuration cf
-            = Configuration.resolve(finder,
-                                    Configuration.empty(),
-                                    ModuleFinder.empty(),
-                                    "m1");
-
-        ClassLoader loader = new ClassLoader() { };
-        Layer.create(cf, Layer.boot(), mn -> loader);
-    }
-
-
-    // null handling
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testCreateWithNull1() {
-        ClassLoader loader = new ClassLoader() { };
-        Layer.create(null, Layer.empty(), mn -> loader);
-
-    }
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testCreateWithNull2() {
-        ClassLoader loader = new ClassLoader() { };
-        Layer.create(Configuration.empty(), null, mn -> loader);
-
-    }
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testCreateWithNull3() {
-        Layer.create(Configuration.empty(), Layer.empty(), null);
-    }
-
-    @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);
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jigsaw/reflect/Layer/src/m1/module-info.java	Thu Dec 17 17:00:18 2015 +0000
@@ -0,0 +1,28 @@
+/*
+ * 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 m1 {
+    requires m2;
+    exports p;
+    uses p.Service;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jigsaw/reflect/Layer/src/m1/p/Main.java	Thu Dec 17 17:00:18 2015 +0000
@@ -0,0 +1,38 @@
+/*
+ * 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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jigsaw/reflect/Layer/src/m1/p/Service.java	Thu Dec 17 17:00:18 2015 +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/jdk/jigsaw/reflect/Layer/src/m2/module-info.java	Thu Dec 17 17:00:18 2015 +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/jdk/jigsaw/reflect/Layer/src/m2/q/Hello.java	Thu Dec 17 17:00:18 2015 +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/jdk/jigsaw/reflect/Layer/src/m3/impl/ServiceImpl.java	Thu Dec 17 17:00:18 2015 +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/jdk/jigsaw/reflect/Layer/src/m3/module-info.java	Thu Dec 17 17:00:18 2015 +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 {
+    requires m1;
+    provides p.Service with impl.ServiceImpl;
+}
--- a/test/jdk/jigsaw/reflect/Proxy/ProxyClassAccessTest.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/test/jdk/jigsaw/reflect/Proxy/ProxyClassAccessTest.java	Thu Dec 17 17:00:18 2015 +0000
@@ -94,8 +94,8 @@
                 .resolve(ModuleFinder.empty(), Layer.boot().configuration(), finder, modules).bind();
 
         ClassLoader parent = this.getClass().getClassLoader();
-        ClassLoader loader = new ModuleClassLoader(parent, cf);
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), parent);
+        ClassLoader loader = layer.findLoader("m1");
         Class<?>[] interfaces = new Class<?>[] {
                 Class.forName("p.one.I", false, loader),
                 Class.forName("q.NP", false, loader)     // non-public interface in unnamed module
--- a/test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java	Thu Dec 17 17:00:18 2015 +0000
@@ -84,8 +84,9 @@
                 .resolve(ModuleFinder.empty(), BOOT_CONFIGURATION, finder, modules)
                 .bind();
 
-        ClassLoader loader = new ModuleClassLoader(cf);
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), ClassLoader.getSystemClassLoader());
+
+        ClassLoader loader = layer.findLoader("m1");
 
         assertTrue(layer.findModule("m1").isPresent());
         assertTrue(layer.findModule("m2").isPresent());
@@ -115,8 +116,9 @@
         Configuration cf = Configuration
                 .resolve(ModuleFinder.empty(), BOOT_CONFIGURATION, finder, modules).bind();
 
-        ClassLoader loader = new ModuleClassLoader(cf);
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), ClassLoader.getSystemClassLoader());
+
+        ClassLoader loader = layer.findLoader("m1");
 
         assertTrue(layer.findModule("m1").isPresent());
         assertTrue(layer.findModule("m2").isPresent());
@@ -142,8 +144,9 @@
         Configuration cf = Configuration
                 .resolve(ModuleFinder.empty(), BOOT_CONFIGURATION, finder, modules).bind();
 
-        ClassLoader loader = new ModuleClassLoader(cf);
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), ClassLoader.getSystemClassLoader());
+
+        ClassLoader loader = layer.findLoader("m1");
 
         assertTrue(layer.findModule("m1").isPresent());
         assertTrue(layer.findModule("m2").isPresent());
--- a/test/jdk/jigsaw/scenarios/container/src/container/container/Main.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/test/jdk/jigsaw/scenarios/container/src/container/container/Main.java	Thu Dec 17 17:00:18 2015 +0000
@@ -78,14 +78,13 @@
         cf.descriptors()
           .forEach(md -> System.out.format("  %s%n", md.name()));
 
-        // choose a class loader
-        ModuleClassLoader loader = new ModuleClassLoader(cf);
-
         // reify the configuration as a Layer
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        Layer layer = Layer.createWithManyLoaders(cf, Layer.boot(),
+                ClassLoader.getSystemClassLoader());
 
         // invoke application main method
-        Class<?> c = layer.findLoader(appModuleName).loadClass(appMainClass);
+        ClassLoader loader = layer.findLoader(appModuleName);
+        Class<?> c = loader.loadClass(appMainClass);
         Main.class.getModule().addReads(c.getModule());
         Method mainMethod = c.getMethod("main", String[].class);
 
--- a/test/jdk/jigsaw/util/ServiceLoader/ServicesTest.java	Thu Dec 17 11:02:49 2015 +0100
+++ b/test/jdk/jigsaw/util/ServiceLoader/ServicesTest.java	Thu Dec 17 17:00:18 2015 +0000
@@ -155,9 +155,9 @@
         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
         Configuration cf = Configuration
             .resolve(finder, Layer.boot().configuration(), ModuleFinder.empty()).bind();
-        ClassLoader loader = new ModuleClassLoader(cf);
-        Layer layer = Layer.create(cf, Layer.boot(), mn -> loader);
+        Layer layer = Layer.createWithOneLoader(cf, Layer.boot(), ClassLoader.getSystemClassLoader());
         assertTrue(layer.findModule("bananascript").isPresent());
+        ClassLoader loader = layer.findLoader("bananascript");
 
         sl = ServiceLoader.load(layer, ScriptEngineFactory.class);
         ScriptEngineFactory factory = find("BananaScriptEngine", sl);