changeset 14513:a3683eec0092

ModuleReference does not need to be abstract class
author alanb
date Sun, 29 Nov 2015 07:55:25 +0000
parents 23fa3594a1d4
children ab5b6e7e9db6
files src/java.base/share/classes/java/lang/module/InstalledModuleFinder.java src/java.base/share/classes/java/lang/module/ModuleReference.java src/java.base/share/classes/java/lang/module/ModuleReferences.java test/jdk/jigsaw/lib/ModuleUtils.java test/jdk/jigsaw/module/ModuleReferenceTest.java test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java
diffstat 6 files changed, 393 insertions(+), 370 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/module/InstalledModuleFinder.java	Fri Nov 27 16:27:28 2015 +0000
+++ b/src/java.base/share/classes/java/lang/module/InstalledModuleFinder.java	Sun Nov 29 07:55:25 2015 +0000
@@ -25,7 +25,12 @@
 
 package java.lang.module;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.net.URI;
+import java.net.URLConnection;
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.HashMap;
@@ -34,6 +39,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import jdk.internal.jimage.ImageLocation;
 import jdk.internal.jimage.ImageModuleData;
@@ -62,12 +68,16 @@
         = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
     private static final String MODULE_INFO = "module-info.class";
 
+    // ImageReader used to access all modules in the image
+    static final ImageReader imageReader;
+
     // the set of modules in the run-time image
     private static final Set<ModuleReference> modules;
 
     // maps module name to module reference
     private static final Map<String, ModuleReference> nameToModule;
 
+
     /**
      * For now, the module references are created eagerly on the assumption
      * that service binding will require all modules to be located.
@@ -75,9 +85,9 @@
     static {
         long t0 = System.nanoTime();
 
-        ImageReader imageReader = ImageReaderFactory.getImageReader();
-        String[] moduleNames = null;
-        boolean fastpath = false;;
+        imageReader = ImageReaderFactory.getImageReader();
+        String[] moduleNames;
+        boolean haveModuleDescriptors;
         Map<String, ModuleDescriptor> descriptors = InstalledModules.modules();
         if (descriptors.isEmpty()) {
             // InstalledModules.MODULE_NAMES is generated at link time and
@@ -85,9 +95,10 @@
             // when building jdk image.
             ImageModuleData mdata = new ImageModuleData(imageReader);
             moduleNames = mdata.allModuleNames().toArray(new String[0]);
+            haveModuleDescriptors = false;
         } else {
             moduleNames = InstalledModules.MODULE_NAMES;
-            fastpath = true;
+            haveModuleDescriptors = true;
         }
 
         int n = moduleNames.length;
@@ -101,20 +112,33 @@
             try {
                 // parse the module-info.class file
                 final ModuleDescriptor md;
-                if (fastpath) {
+                if (haveModuleDescriptors) {
                     md = descriptors.get(mn);
                 } else {
                     ImageLocation loc = imageReader.findLocation(mn, MODULE_INFO);
                     bb = imageReader.getResourceBuffer(loc);
                     md = ModuleInfo.readIgnoringHashes(bb, null);
                 }
-
                 if (!md.name().equals(mn))
                     throw new InternalError();
 
+                // replace ModuleDescriptor if new packages added by -Xpatch
+                ModuleDescriptor descriptor = ModulePatcher.patchIfNeeded(md);
+
+                // create the ModuleReference
+
                 URI uri = URI.create("jrt:/" + mn);
+
+                Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+                    @Override
+                    public ModuleReader get() {
+                        return new ImageModuleReader(mn, uri);
+                    }
+                };
+
                 ModuleReference mref
-                    = ModuleReferences.newModuleReference(md, uri, null);
+                    = new ModuleReference(descriptor, uri, readerSupplier);
+
                 mods.add(mref);
                 map.put(mn, mref);
 
@@ -147,4 +171,100 @@
         return modules;
     }
 
+
+    /**
+     * A ModuleReader for reading resources from a module linked into the
+     * run-time image.
+     */
+    static class ImageModuleReader implements ModuleReader {
+
+        private final String module;
+        private volatile boolean closed;
+
+        /**
+         * If there is a security manager set then check permission to
+         * connect to the run-time image.
+         */
+        private static void checkPermissionToConnect(URI uri) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                try {
+                    URLConnection uc = uri.toURL().openConnection();
+                    sm.checkPermission(uc.getPermission());
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+            }
+        }
+
+        ImageModuleReader(String module, URI uri) {
+            checkPermissionToConnect(uri);
+            this.module = module;
+        }
+
+        /**
+         * Returns the ImageLocation for the given resource, {@code null}
+         * if not found.
+         */
+        private ImageLocation findImageLocation(String name) throws IOException {
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+
+            if (imageReader != null) {
+                return imageReader.findLocation(module, name);
+            } else {
+                // not an images build
+                return null;
+            }
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                URI u = URI.create("jrt:/" + module + "/" + name);
+                return Optional.of(u);
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            return read(name).map(this::toInputStream);
+        }
+
+        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
+            try {
+                int rem = bb.remaining();
+                byte[] bytes = new byte[rem];
+                bb.get(bytes);
+                return new ByteArrayInputStream(bytes);
+            } finally {
+                release(bb);
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                return Optional.of(imageReader.getResourceBuffer(location));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public void release(ByteBuffer bb) {
+            ImageReader.releaseByteBuffer(bb);
+        }
+
+        @Override
+        public void close() {
+            // nothing else to do
+            closed = true;
+        }
+    }
+
 }
\ No newline at end of file
--- a/src/java.base/share/classes/java/lang/module/ModuleReference.java	Fri Nov 27 16:27:28 2015 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReference.java	Sun Nov 29 07:55:25 2015 +0000
@@ -26,9 +26,11 @@
 package java.lang.module;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.URI;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.Supplier;
 
 import jdk.internal.module.Hasher.HashSupplier;
 
@@ -46,10 +48,11 @@
  * @since 1.9
  */
 
-public abstract class ModuleReference {
+public final class ModuleReference {
 
     private final ModuleDescriptor descriptor;
     private final Optional<URI> location;
+    private final Supplier<ModuleReader> readerSupplier;
 
     // the function that computes the hash of this module reference
     private final HashSupplier hasher;
@@ -62,36 +65,51 @@
      */
     ModuleReference(ModuleDescriptor descriptor,
                     URI location,
+                    Supplier<ModuleReader> readerSupplier,
                     HashSupplier hasher)
     {
         this.descriptor = Objects.requireNonNull(descriptor);
         this.location = Optional.ofNullable(location);
+        this.readerSupplier = Objects.requireNonNull(readerSupplier);
         this.hasher = hasher;
     }
 
+
     /**
      * Constructs a new instance of this class.
      *
+     * <p> The {@code readSupplier} parameter is the supplier of the {@link
+     * ModuleReader} that may be used to read the module content. Its {@link
+     * Supplier#get() get()} method throws {@link UncheckedIOException} if an
+     * I/O error occurs opening the module content. The {@code get()} method
+     * throws {@link SecurityException} if opening the module is denied by the
+     * security manager.
+     *
      * @param descriptor
      *        The module descriptor
      * @param location
      *        The module location or {@code null} if not known
+     * @param readerSupplier
+     *        The {@code Supplier} of the {@code ModuleReader}
      */
-    protected ModuleReference(ModuleDescriptor descriptor,
-                              URI location)
+    public ModuleReference(ModuleDescriptor descriptor,
+                           URI location,
+                           Supplier<ModuleReader> readerSupplier)
     {
-        this(descriptor, location, null);
+        this(descriptor, location, readerSupplier, null);
     }
 
+
     /**
      * Returns the module descriptor.
      *
      * @return The module descriptor
      */
-    public final ModuleDescriptor descriptor() {
+    public ModuleDescriptor descriptor() {
         return descriptor;
     }
 
+
     /**
      * Returns the location of this module's content, if known.
      *
@@ -103,14 +121,19 @@
      *
      * @return The location or an empty {@code Optional} if not known
      */
-    public final Optional<URI> location() {
+    public Optional<URI> location() {
         return location;
     }
 
+
     /**
-     * Opens the modules reference for reading, returning a {@code ModuleReader}
+     * Opens the module content for reading, returning a {@code ModuleReader}
      * that may be used to locate or read classes and resources.
      *
+     * <p> </p>This method opens the module content by invoking the {@link
+     * Supplier#get() get()} method of the {@code readSupplier} specified at
+     * construction time. </p>
+     *
      * @return A {@code ModuleReader} to read the module
      *
      * @throws IOException
@@ -118,7 +141,15 @@
      * @throws SecurityException
      *         If denied by the security manager
      */
-    public abstract ModuleReader open() throws IOException;
+    public ModuleReader open() throws IOException {
+        try {
+            return readerSupplier.get();
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+
+    }
+
 
     /**
      * Computes the MD5 hash of this module, returning it as a hex string.
@@ -138,26 +169,28 @@
 
     private int hash;
 
+    @Override
     public int hashCode() {
         int hc = hash;
         if (hc == 0) {
-            hc = descriptor.hashCode() ^ location.hashCode();
-            hash = hc;
+            hc = Objects.hash(descriptor, location, readerSupplier, hasher);
         }
         return hc;
     }
 
+    @Override
     public boolean equals(Object obj) {
         if (!(obj instanceof ModuleReference))
             return false;
         ModuleReference that = (ModuleReference)obj;
-        if (!this.descriptor.equals(that.descriptor))
-            return false;
-        if (!this.location.equals(that.location))
-            return false;
-        return true;
+
+        return Objects.equals(this.descriptor, that.descriptor)
+                && Objects.equals(this.location, that.location)
+                && Objects.equals(this.readerSupplier, that.readerSupplier)
+                && Objects.equals(this.hasher, that.hasher);
     }
 
+    @Override
     public String toString() {
         return ("[module " + descriptor().name()
                 + ", location=" + location.orElse(null) + "]");
--- a/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Fri Nov 27 16:27:28 2015 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Sun Nov 29 07:55:25 2015 +0000
@@ -25,13 +25,12 @@
 
 package java.lang.module;
 
-import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOError;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.net.URI;
-import java.net.URLConnection;
 import java.nio.ByteBuffer;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -41,22 +40,20 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Supplier;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
-import jdk.internal.jimage.ImageReaderFactory;
 import jdk.internal.module.Hasher;
 import sun.net.www.ParseUtil;
 
 
 /**
  * A factory for creating ModuleReference implementations where the modules are
- * located in the run-time image, packaged as jmod or modular JAR files, or
- * where the modules are exploded on the file system.
+ * packaged as modular JAR file, JMOD files or where the modules are exploded
+ * on the file system.
  */
 
 class ModuleReferences {
@@ -64,187 +61,217 @@
     private ModuleReferences() { }
 
     /**
-     * Creates a ModuleReference.
+     * Creates the ModuleReference.
      */
     static ModuleReference newModuleReference(ModuleDescriptor md,
                                               URI location,
                                               Hasher.HashSupplier hasher)
     {
         // use new ModuleDescriptor if new packages added by -Xpatch
-        md = ModulePatcher.patchIfNeeded(md);
+        ModuleDescriptor descriptor = ModulePatcher.patchIfNeeded(md);
 
         String scheme = location.getScheme();
-        if (scheme.equalsIgnoreCase("jrt"))
-            return new JrtModuleReference(md, location, hasher);
-        if (scheme.equalsIgnoreCase("jmod"))
-            return new JModModuleReference(md, location, hasher);
-        if (scheme.equalsIgnoreCase("jar"))
-            return new JarModuleReference(md, location, hasher);
-        if (scheme.equalsIgnoreCase("file"))
-            return new ExplodedModuleReference(md, location, hasher);
 
-        throw new InternalError("Should not get here");
+        Supplier<ModuleReader> readerSupplier;
+        if (scheme.equalsIgnoreCase("jar")) {
+            readerSupplier = () -> new JarModuleReader(location);
+        } else if (scheme.equalsIgnoreCase("jmod")) {
+            readerSupplier = () -> new JModModuleReader(location);
+        } else if (scheme.equalsIgnoreCase("file")) {
+            readerSupplier = () -> new ExplodedModuleReader(location);
+        } else {
+            throw new InternalError("Should not get here");
+        }
+
+        return new ModuleReference(descriptor, location, readerSupplier, hasher);
     }
 
-    /**
-     * A ModuleReference for a module that is linked into the run-time image.
-     */
-    static class JrtModuleReference extends ModuleReference {
-        JrtModuleReference(ModuleDescriptor descriptor,
-                          URI location,
-                          Hasher.HashSupplier hasher) {
-            super(descriptor, location, hasher);
-        }
-
-        public ModuleReader open() throws IOException {
-            return new JrtModuleReader(this);
-        }
-    }
 
     /**
-     * A ModuleReference for a module that is exploded on the file system.
+     * A base module reader that encapsulates machinery required to close the
+     * module reader safely.
      */
-    static class ExplodedModuleReference extends ModuleReference {
-        ExplodedModuleReference(ModuleDescriptor descriptor,
-                               URI location,
-                               Hasher.HashSupplier hasher) {
-            super(descriptor, location, hasher);
-        }
+    static abstract class SafeCloseModuleReader implements ModuleReader {
 
-        public ModuleReader open() throws IOException {
-            return new ExplodedModuleReader(this);
-        }
-    }
+        // RW lock to support safe close
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+        private final Lock readLock = lock.readLock();
+        private final Lock writeLock = lock.writeLock();
+        private volatile boolean closed;
 
-    /**
-     * A ModuleReference for a module that is packaged as jmod file.
-     */
-    static class JModModuleReference extends ModuleReference {
-        JModModuleReference(ModuleDescriptor descriptor,
-                            URI location,
-                            Hasher.HashSupplier hasher) {
-            super(descriptor, location, hasher);
-        }
+        SafeCloseModuleReader() { }
 
-        public ModuleReader open() throws IOException {
-            return new JModModuleReader(this);
-        }
-    }
+        /**
+         * Returns a URL to  resource. This method is invoked by the find
+         * method to do the actual work of finding the resource.
+         */
+        abstract Optional<URI> implFind(String name) throws IOException;
 
-    /**
-     * A ModuleReference for a module that is packaged as a modular JAR file.
-     */
-    static class JarModuleReference extends ModuleReference {
-        JarModuleReference(ModuleDescriptor descriptor,
-                          URI location,
-                          Hasher.HashSupplier hasher) {
-            super(descriptor, location, hasher);
-        }
+        /**
+         * Returns an input stream for reading a resource. This method is
+         * invoked by the open method to do the actual work of opening
+         * an input stream to the resource.
+         */
+        abstract Optional<InputStream> implOpen(String name) throws IOException;
+
+        /**
+         * Closes the module reader. This method is invoked by close to do the
+         * actual work of closing the module reader.
+         */
+        abstract void implClose() throws IOException;
 
         @Override
-        public ModuleReader open() throws IOException {
-            return new JarModuleReader(this);
-        }
-    }
-
-    /**
-     * A ModuleReader for reading resources from a module linked into the
-     * run-time image.
-     */
-    static class JrtModuleReader implements ModuleReader {
-        // ImageReader, shared between instances of this module reader
-        private static ImageReader imageReader;
-        static {
-            // detect image or exploded build
-            String home = System.getProperty("java.home");
-            Path libModules = Paths.get(home, "lib", "modules");
-            if (Files.isDirectory(libModules)) {
-                // this can throw UncheckedIOException
-                imageReader = ImageReaderFactory.getImageReader();
-            } else {
-                imageReader = null;
+        public final Optional<URI> find(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implFind(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
             }
         }
 
-        private final String module;
-        private volatile boolean closed;
 
-        JrtModuleReader(ModuleReference mref) throws IOException {
-            assert mref.location().isPresent();
-            // when running with a security manager then check that the caller
-            // has access to the run-time image
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                URLConnection uc = mref.location().get().toURL().openConnection();
-                sm.checkPermission(uc.getPermission());
-            }
-            this.module = mref.descriptor().name();
-        }
-
-        /**
-         * Returns the ImageLocation for the given resource, {@code null}
-         * if not found.
-         */
-        private ImageLocation findImageLocation(String name) throws IOException {
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-
-            if (imageReader != null) {
-                return imageReader.findLocation(module, name);
-            } else {
-                // not an images build
-                return null;
+        @Override
+        public final Optional<InputStream> open(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implOpen(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
             }
         }
 
         @Override
-        public Optional<URI> find(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                URI u = URI.create("jrt:/" + module + "/" + name);
-                return Optional.of(u);
+        public void close() throws IOException {
+            writeLock.lock();
+            try {
+                if (!closed) {
+                    closed = true;
+                    implClose();
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a modular JAR file.
+     */
+    static class JarModuleReader extends SafeCloseModuleReader {
+        private final URI uri;
+        private final JarFile jf;
+
+        static JarFile newJarFile(String name) {
+            try {
+                return new JarFile(name);
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JarModuleReader(URI uri) {
+            String s = uri.toString();
+            URI fileURI = URI.create(s.substring(4, s.length()-2));
+            this.uri = uri;
+            this.jf = newJarFile(Paths.get(fileURI).toString());
+        }
+
+        private JarEntry getEntry(String name) {
+            return jf.getJarEntry(Objects.requireNonNull(name));
+        }
+
+        @Override
+        Optional<URI> implFind(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                String encodedPath = ParseUtil.encodePath(name, false);
+                return Optional.of(URI.create(uri + encodedPath));
             } else {
                 return Optional.empty();
             }
         }
 
         @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            return read(name).map(this::toInputStream);
-        }
-
-        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
-            try {
-                int rem = bb.remaining();
-                byte[] bytes = new byte[rem];
-                bb.get(bytes);
-                return new ByteArrayInputStream(bytes);
-            } finally {
-                release(bb);
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                return Optional.of(imageReader.getResourceBuffer(location));
+        Optional<InputStream> implOpen(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                return Optional.of(jf.getInputStream(je));
             } else {
                 return Optional.empty();
             }
         }
 
         @Override
-        public void release(ByteBuffer bb) {
-            ImageReader.releaseByteBuffer(bb);
+        void implClose() throws IOException {
+            jf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a JMOD file.
+     */
+    static class JModModuleReader extends SafeCloseModuleReader {
+        private final URI uri;
+        private final ZipFile zf;
+
+        static ZipFile newZipFile(String name) {
+            try {
+                return new ZipFile(name);
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JModModuleReader(URI uri) {
+            String s = uri.toString();
+            URI fileURI = URI.create(s.substring(5, s.length() - 2));
+            this.uri = uri;
+            this.zf = newZipFile(Paths.get(fileURI).toString());
+        }
+
+        private ZipEntry getEntry(String name) {
+            return zf.getEntry("classes/" + Objects.requireNonNull(name));
         }
 
         @Override
-        public void close() {
-            closed = true;
+        Optional<URI> implFind(String name) {
+            ZipEntry ze = getEntry(name);
+            if (ze != null) {
+                String encodedPath = ParseUtil.encodePath(name, false);
+                return Optional.of(URI.create(uri + encodedPath));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            ZipEntry ze = getEntry(name);
+            if (ze != null) {
+                return Optional.of(zf.getInputStream(ze));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        void implClose() throws IOException {
+            zf.close();
         }
     }
 
+
     /**
      * A ModuleReader for an exploded module.
      */
@@ -252,8 +279,8 @@
         private final Path dir;
         private volatile boolean closed;
 
-        ExplodedModuleReader(ModuleReference mref) {
-            dir = Paths.get(mref.location().get());
+        ExplodedModuleReader(URI location) {
+            dir = Paths.get(location);
 
             // when running with a security manager then check that the caller
             // has access to the directory.
@@ -328,172 +355,4 @@
         }
     }
 
-    /**
-     * A base module reader that encapsulates machinery required to close the
-     * module reader safely.
-     */
-    static abstract class SafeCloseModuleReader implements ModuleReader {
-
-        // RW lock to support safe close
-        private final ReadWriteLock lock = new ReentrantReadWriteLock();
-        private final Lock readLock = lock.readLock();
-        private final Lock writeLock = lock.writeLock();
-        private volatile boolean closed;
-
-        SafeCloseModuleReader() { }
-
-        /**
-         * Returns a URL to  resource. This method is invoked by the find
-         * method to do the actual work of finding the resource.
-         */
-        abstract Optional<URI> implFind(String name) throws IOException;
-
-        /**
-         * Returns an input stream for reading a resource. This method is
-         * invoked by the open method to do the actual work of opening
-         * an input stream to the resource.
-         */
-        abstract Optional<InputStream> implOpen(String name) throws IOException;
-
-        /**
-         * Closes the module reader. This method is invoked by close to do the
-         * actual work of closing the module reader.
-         */
-        abstract void implClose() throws IOException;
-
-        @Override
-        public final Optional<URI> find(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implFind(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-
-        @Override
-        public final Optional<InputStream> open(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implOpen(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public void close() throws IOException {
-            writeLock.lock();
-            try {
-                if (!closed) {
-                    closed = true;
-                    implClose();
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        }
-    }
-
-    /**
-     * A ModuleReader for a jmod file.
-     */
-    static class JModModuleReader extends SafeCloseModuleReader {
-        private final URI uri;
-        private final ZipFile zf;
-
-        JModModuleReader(ModuleReference mref) throws IOException {
-            URI uri = mref.location().get();
-            String s = uri.toString();
-            URI fileURI = URI.create(s.substring(5, s.length() - 2));
-            this.uri = uri;
-            this.zf = new ZipFile(Paths.get(fileURI).toString());
-        }
-
-        private ZipEntry getEntry(String name) {
-            return zf.getEntry("classes/" + Objects.requireNonNull(name));
-        }
-
-        @Override
-        Optional<URI> implFind(String name) {
-            ZipEntry ze = getEntry(name);
-            if (ze != null) {
-                String encodedPath = ParseUtil.encodePath(name, false);
-                return Optional.of(URI.create(uri + encodedPath));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            ZipEntry ze = getEntry(name);
-            if (ze != null) {
-                return Optional.of(zf.getInputStream(ze));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        void implClose() throws IOException {
-            zf.close();
-        }
-    }
-
-    /**
-     * A ModuleReader for a modular JAR file.
-     */
-    static class JarModuleReader extends SafeCloseModuleReader {
-        private final URI uri;
-        private final JarFile jf;
-
-        JarModuleReader(ModuleReference mref) throws IOException {
-            URI uri = mref.location().get();
-            String s = uri.toString();
-            URI fileURI = URI.create(s.substring(4, s.length()-2));
-            this.uri = uri;
-            this.jf = new JarFile(Paths.get(fileURI).toString());
-        }
-
-        private JarEntry getEntry(String name) {
-            return jf.getJarEntry(Objects.requireNonNull(name));
-        }
-
-        @Override
-        Optional<URI> implFind(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                String encodedPath = ParseUtil.encodePath(name, false);
-                return Optional.of(URI.create(uri + encodedPath));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
 }
--- a/test/jdk/jigsaw/lib/ModuleUtils.java	Fri Nov 27 16:27:28 2015 +0000
+++ b/test/jdk/jigsaw/lib/ModuleUtils.java	Sun Nov 29 07:55:25 2015 +0000
@@ -21,7 +21,6 @@
  * questions.
  */
 
-import java.io.IOException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReader;
@@ -33,6 +32,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.Supplier;
 
 
 /**
@@ -52,15 +52,18 @@
 
         // Create a ModuleReference for each module
         Map<String, ModuleReference> namesToReference = new HashMap<>();
-        for (ModuleDescriptor descriptor: descriptors) {
+
+        for (ModuleDescriptor descriptor : descriptors) {
             String name = descriptor.name();
-            URI uri = URI.create("module:/" + descriptor.name());
-            ModuleReference mref = new ModuleReference(descriptor, uri) {
-                @Override
-                public ModuleReader open() throws IOException {
-                    throw new IOException("No module reader for: " + uri);
-                }
+
+            URI uri = URI.create("module:/" + name);
+
+            Supplier<ModuleReader> supplier = () -> {
+                throw new UnsupportedOperationException();
             };
+
+            ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+
             namesToReference.put(name, mref);
         }
 
--- a/test/jdk/jigsaw/module/ModuleReferenceTest.java	Fri Nov 27 16:27:28 2015 +0000
+++ b/test/jdk/jigsaw/module/ModuleReferenceTest.java	Sun Nov 29 07:55:25 2015 +0000
@@ -27,11 +27,11 @@
  * @summary Basic tests for java.lang.module.ModuleReference
  */
 
-import java.io.IOException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.net.URI;
+import java.util.function.Supplier;
 
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
@@ -39,19 +39,10 @@
 @Test
 public class ModuleReferenceTest {
 
-    private ModuleReference newModuleReference(ModuleDescriptor descriptor,
-                                               URI location)
-    {
-        return new ModuleReference(descriptor, location) {
-            @Override
-            public ModuleReader open() throws IOException {
-                throw new IOException("No reader for module "
-                                      + descriptor().toNameAndVersion());
-            }
-        };
+    private Supplier<ModuleReader> makeSupplier() {
+        return () -> { throw new UnsupportedOperationException(); };
     }
 
-
     public void testBasic() throws Exception {
         ModuleDescriptor descriptor
             = new ModuleDescriptor.Builder("m")
@@ -60,31 +51,46 @@
                 .conceals("p.internal")
                 .build();
 
-        URI location = URI.create("module:/m");
+        URI uri = URI.create("module:/m");
 
-        ModuleReference mref = newModuleReference(descriptor, location);
+        Supplier<ModuleReader> supplier = makeSupplier();
+
+        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
 
         assertTrue(mref.descriptor().equals(descriptor));
-        assertTrue(mref.location().get().equals(location));
+        assertTrue(mref.location().get().equals(uri));
+
+        // check that the supplier is called
+        try {
+            mref.open();
+            assertTrue(false);
+        } catch (UnsupportedOperationException expected) { }
     }
 
 
     @Test(expectedExceptions = { NullPointerException.class })
     public void testNullDescriptor() throws Exception {
         URI location = URI.create("module:/m");
-        newModuleReference(null, location);
+        new ModuleReference(null, location, makeSupplier());
     }
 
-
     public void testNullLocation() {
         ModuleDescriptor descriptor
             = new ModuleDescriptor.Builder("m")
-                    .exports("p")
-                    .build();
-        ModuleReference mref = newModuleReference(descriptor, null);
+                .exports("p")
+                .build();
+        Supplier<ModuleReader> supplier = makeSupplier();
+        ModuleReference mref = new ModuleReference(descriptor, null, supplier);
         assertTrue(!mref.location().isPresent());
     }
 
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testNullSupplier() throws Exception {
+        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m").build();
+        URI location = URI.create("module:/m");
+        new ModuleReference(descriptor, location, null);
+    }
+
 
     public void testEqualsAndHashCode() {
         ModuleDescriptor descriptor1
@@ -96,10 +102,12 @@
                 .exports("p")
                 .build();
 
-        URI location = URI.create("module:/m1");
-        ModuleReference mref1 = newModuleReference(descriptor1, location);
-        ModuleReference mref2 = newModuleReference(descriptor2, location);
-        ModuleReference mref3 = newModuleReference(descriptor1, null);
+        URI uri = URI.create("module:/m1");
+        Supplier<ModuleReader> supplier = makeSupplier();
+
+        ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier);
+        ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier);
+        ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier);
 
         assertTrue(mref1.equals(mref1));
         assertTrue(mref1.equals(mref1));
@@ -114,11 +122,12 @@
 
     public void testToString() {
         ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build();
-        URI location = URI.create("module:/m1");
-        ModuleReference mref = newModuleReference(descriptor, location);
+        URI uri = URI.create("module:/m1");
+        Supplier<ModuleReader> supplier = makeSupplier();
+        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
         String s = mref.toString();
         assertTrue(s.contains("m1"));
-        assertTrue(s.contains(location.toString()));
+        assertTrue(s.contains(uri.toString()));
     }
 
 }
--- a/test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java	Fri Nov 27 16:27:28 2015 +0000
+++ b/test/jdk/jigsaw/reflect/Proxy/ProxyLayerTest.java	Sun Nov 29 07:55:25 2015 +0000
@@ -23,7 +23,6 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReference;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;