8150680: JarFile.Release enum needs reconsideration with respect to it's values
authorsdrach
Wed, 13 Jul 2016 11:43:45 -0700
changeset 39646 2bf99fe5023b
parent 39645 f71bb6a69b8d
child 39647 cd5deb6026dd
8150680: JarFile.Release enum needs reconsideration with respect to it's values Reviewed-by: alanb, psandoz Contributed-by: steve.drach@oracle.com
jdk/src/java.base/share/classes/java/lang/module/ModulePath.java
jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java
jdk/src/java.base/share/classes/java/util/jar/JarFile.java
jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java
jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java
jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java
jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java
jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java
jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java
jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java
jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java
jdk/test/tools/jar/multiRelease/Basic.java
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Wed Jul 13 11:43:45 2016 -0700
@@ -523,7 +523,7 @@
         try (JarFile jf = new JarFile(file.toFile(),
                                       true,               // verify
                                       ZipFile.OPEN_READ,
-                                      JarFile.Release.RUNTIME))
+                                      JarFile.runtimeVersion()))
         {
             ModuleDescriptor md;
             JarEntry entry = jf.getJarEntry(MODULE_INFO);
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Wed Jul 13 11:43:45 2016 -0700
@@ -201,7 +201,7 @@
                 return new JarFile(path.toFile(),
                                    true,               // verify
                                    ZipFile.OPEN_READ,
-                                   JarFile.Release.RUNTIME);
+                                   JarFile.runtimeVersion());
             } catch (IOException ioe) {
                 throw new UncheckedIOException(ioe);
             }
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Jul 13 11:43:45 2016 -0700
@@ -64,8 +64,8 @@
  * file, and as such an entry name is associated with at most one base entry.
  * The {@code JarFile} may be configured to process a multi-release jar file by
  * creating the {@code JarFile} with the
- * {@link JarFile#JarFile(File, boolean, int, Release)} constructor.  The
- * {@code Release} object sets a maximum version used when searching for
+ * {@link JarFile#JarFile(File, boolean, int, Runtime.Version)} constructor.  The
+ * {@code Runtime.Version} object sets a maximum version used when searching for
  * versioned entries.  When so configured, an entry name
  * can correspond with at most one base entry and zero or more versioned
  * entries. A search is required to associate the entry name with the latest
@@ -74,8 +74,8 @@
  *
  * <p>Class loaders that utilize {@code JarFile} to load classes from the
  * contents of {@code JarFile} entries should construct the {@code JarFile}
- * by invoking the {@link JarFile#JarFile(File, boolean, int, Release)}
- * constructor with the value {@code Release.RUNTIME} assigned to the last
+ * by invoking the {@link JarFile#JarFile(File, boolean, int, Runtime.Version)}
+ * constructor with the value {@code Runtime.version()} assigned to the last
  * argument.  This assures that classes compatible with the major
  * version of the running JVM are loaded from multi-release jar files.
  *
@@ -99,12 +99,12 @@
  * <li>
  * {@code jdk.util.jar.version} can be assigned a value that is the
  * {@code String} representation of a non-negative integer
- * {@code <= Version.current().major()}.  The value is used to set the effective
+ * {@code <= Runtime.version().major()}.  The value is used to set the effective
  * runtime version to something other than the default value obtained by
- * evaluating {@code Version.current().major()}. The effective runtime version
- * is the version that the {@link JarFile#JarFile(File, boolean, int, Release)}
+ * evaluating {@code Runtime.version().major()}. The effective runtime version
+ * is the version that the {@link JarFile#JarFile(File, boolean, int, Runtime.Version)}
  * constructor uses when the value of the last argument is
- * {@code Release.RUNTIME}.
+ * {@code JarFile.runtimeVersion()}.
  * </li>
  * <li>
  * {@code jdk.util.jar.enableMultiRelease} can be assigned one of the three
@@ -116,7 +116,7 @@
  * the method {@link JarFile#isMultiRelease()} returns <em>false</em>. The value
  * <em>force</em> causes the {@code JarFile} to be initialized to runtime
  * versioning after construction.  It effectively does the same as this code:
- * {@code (new JarFile(File, boolean, int, Release.RUNTIME)}.
+ * {@code (new JarFile(File, boolean, int, JarFile.runtimeVersion())}.
  * </li>
  * </ul>
  * </div>
@@ -129,8 +129,9 @@
  */
 public
 class JarFile extends ZipFile {
-    private final static int BASE_VERSION;
-    private final static int RUNTIME_VERSION;
+    private final static Runtime.Version BASE_VERSION;
+    private final static int BASE_VERSION_MAJOR;
+    private final static Runtime.Version RUNTIME_VERSION;
     private final static boolean MULTI_RELEASE_ENABLED;
     private final static boolean MULTI_RELEASE_FORCED;
     private SoftReference<Manifest> manRef;
@@ -138,10 +139,10 @@
     private JarVerifier jv;
     private boolean jvInitialized;
     private boolean verify;
-    private final int version;
-    private boolean notVersioned;
-    private final boolean runtimeVersioned;
-    private boolean isMultiRelease;    // is jar multi-release?
+    private final Runtime.Version version;  // current version
+    private final int versionMajor;         // version.major()
+    private boolean notVersioned;           // legacy constructor called
+    private boolean isMultiRelease;         // is jar multi-release?
 
     // indicates if Class-Path attribute present
     private boolean hasClassPathAttribute;
@@ -151,17 +152,18 @@
     static {
         // Set up JavaUtilJarAccess in SharedSecrets
         SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
-
-        BASE_VERSION = 8;  // one less than lowest version for versioned entries
+        // multi-release jar file versions >= 9
+        BASE_VERSION = Runtime.Version.parse(Integer.toString(8));
+        BASE_VERSION_MAJOR = BASE_VERSION.major();
+        String jarVersion = GetPropertyAction.privilegedGetProperty("jdk.util.jar.version");
         int runtimeVersion = Runtime.version().major();
-        String jarVersion =
-                GetPropertyAction.privilegedGetProperty("jdk.util.jar.version");
         if (jarVersion != null) {
             int jarVer = Integer.parseInt(jarVersion);
             runtimeVersion = (jarVer > runtimeVersion)
-                    ? runtimeVersion : Math.max(jarVer, 0);
+                    ? runtimeVersion
+                    : Math.max(jarVer, BASE_VERSION_MAJOR);
         }
-        RUNTIME_VERSION = runtimeVersion;
+        RUNTIME_VERSION = Runtime.Version.parse(Integer.toString(runtimeVersion));
         String enableMultiRelease = GetPropertyAction
                 .privilegedGetProperty("jdk.util.jar.enableMultiRelease", "true");
         switch (enableMultiRelease) {
@@ -181,61 +183,6 @@
         }
     }
 
-    /**
-     * A set of constants that represent the entries in either the base directory
-     * or one of the versioned directories in a multi-release jar file.  It's
-     * possible for a multi-release jar file to contain versioned directories
-     * that are not represented by the constants of the {@code Release} enum.
-     * In those cases, the entries will not be located by this {@code JarFile}
-     * through the aliasing mechanism, but they can be directly accessed by
-     * specifying the full path name of the entry.
-     *
-     * @since 9
-     */
-    public enum Release {
-        /**
-         * Represents unversioned entries, or entries in "regular", as opposed
-         * to multi-release jar files.
-         */
-        BASE(BASE_VERSION),
-
-        /**
-         * Represents entries found in the META-INF/versions/9 directory of a
-         * multi-release jar file.
-         */
-        VERSION_9(9),
-
-        // fill in the "blanks" for future releases
-
-        /**
-         * Represents entries found in the META-INF/versions/{n} directory of a
-         * multi-release jar file, where {@code n} is the effective runtime
-         * version of the jar file.
-         *
-         * @implNote
-         * <div class="block">
-         * The effective runtime version is determined
-         * by evaluating {@code Version.current().major()} or by using the value
-         * of the {@code jdk.util.jar.version} System property if it exists.
-         * </div>
-         */
-        RUNTIME(RUNTIME_VERSION);
-
-        Release(int version) {
-            this.version = version;
-        }
-
-        private static Release valueOf(int version) {
-            return version <= BASE.value() ? BASE : valueOf("VERSION_" + version);
-        }
-
-        private final int version;
-
-        private int value() {
-            return this.version;
-        }
-    }
-
     private static final String META_INF = "META-INF/";
 
     private static final String META_INF_VERSIONS = META_INF + "versions/";
@@ -246,6 +193,32 @@
     public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF";
 
     /**
+     * The version that represents the unversioned configuration of a multi-release jar file.
+     *
+     * @return Runtime.Version that represents the unversioned configuration
+     *
+     * @since 9
+     */
+    public static Runtime.Version baseVersion() {
+        return BASE_VERSION;
+    }
+
+    /**
+     * The version that represents the effective runtime versioned configuration of a
+     * multi-release jar file.  In most cases, {@code runtimeVersion()} is equal to
+     * {@code Runtime.version()}.  However, if the {@code jdk.util.jar.version} property is set,
+     * {@code runtimeVersion()} is derived from that property and may not be equal to
+     * {@code Runtime.version()}.
+     *
+     * @return Runtime.Version that represents the runtime versioned configuration
+     *
+     * @since 9
+     */
+    public static Runtime.Version runtimeVersion() {
+        return RUNTIME_VERSION;
+    }
+
+    /**
      * Creates a new {@code JarFile} to read from the specified
      * file {@code name}. The {@code JarFile} will be verified if
      * it is signed.
@@ -316,7 +289,7 @@
      * @since 1.3
      */
     public JarFile(File file, boolean verify, int mode) throws IOException {
-        this(file, verify, mode, Release.BASE);
+        this(file, verify, mode, BASE_VERSION);
         this.notVersioned = true;
     }
 
@@ -324,8 +297,13 @@
      * Creates a new {@code JarFile} to read from the specified
      * {@code File} object in the specified mode.  The mode argument
      * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
-     * The version argument configures the {@code JarFile} for processing
+     * The version argument, after being converted to a canonical form, is
+     * used to configure the {@code JarFile} for processing
      * multi-release jar files.
+     * <p>
+     * The canonical form derived from the version parameter is
+     * {@code Runtime.Version.parse(Integer.toString(n))} where {@code n} is
+     * {@code Math.max(version.major(), JarFile.baseVersion().major())}.
      *
      * @param file the jar file to be opened for reading
      * @param verify whether or not to verify the jar file if
@@ -340,47 +318,31 @@
      * @throws NullPointerException if {@code version} is {@code null}
      * @since 9
      */
-    public JarFile(File file, boolean verify, int mode, Release version) throws IOException {
+    public JarFile(File file, boolean verify, int mode, Runtime.Version version) throws IOException {
         super(file, mode);
-        Objects.requireNonNull(version);
         this.verify = verify;
-        // version applies to multi-release jar files, ignored for regular jar files
-        if (MULTI_RELEASE_FORCED) {
+        Objects.requireNonNull(version);
+        if (MULTI_RELEASE_FORCED || version.major() == RUNTIME_VERSION.major()) {
+            // This deals with the common case where the value from JarFile.runtimeVersion() is passed
             this.version = RUNTIME_VERSION;
-            version = Release.RUNTIME;
+        } else if (version.major() <= BASE_VERSION_MAJOR) {
+            // This also deals with the common case where the value from JarFile.baseVersion() is passed
+            this.version = BASE_VERSION;
         } else {
-            this.version = version.value();
+            // Canonicalize
+            this.version = Runtime.Version.parse(Integer.toString(version.major()));
         }
-        this.runtimeVersioned = version == Release.RUNTIME;
-
-        assert runtimeVersionExists();
-    }
-
-    private boolean runtimeVersionExists() {
-        int version = Runtime.version().major();
-        try {
-            Release.valueOf(version);
-            return true;
-        } catch (IllegalArgumentException x) {
-            System.err.println("No JarFile.Release object for release " + version);
-            return false;
-        }
+        this.versionMajor = this.version.major();
     }
 
     /**
      * Returns the maximum version used when searching for versioned entries.
      *
-     * @return the maximum version, or {@code Release.BASE} if this jar file is
-     *         processed as if it is an unversioned jar file or is not a
-     *         multi-release jar file
+     * @return the maximum version
      * @since 9
      */
-    public final Release getVersion() {
-        if (isMultiRelease()) {
-            return runtimeVersioned ? Release.RUNTIME : Release.valueOf(version);
-        } else {
-            return Release.BASE;
-        }
+    public final Runtime.Version getVersion() {
+        return isMultiRelease() ? this.version : BASE_VERSION;
     }
 
     /**
@@ -393,7 +355,7 @@
         if (isMultiRelease) {
             return true;
         }
-        if (MULTI_RELEASE_ENABLED && version != BASE_VERSION) {
+        if (MULTI_RELEASE_ENABLED && versionMajor != BASE_VERSION_MAJOR) {
             try {
                 checkForSpecialAttributes();
             } catch (IOException io) {
@@ -639,7 +601,7 @@
         ZipEntry vze = null;
         String sname = "/" + name;
         int i = version;
-        while (i > BASE_VERSION) {
+        while (i > BASE_VERSION_MAJOR) {
             vze = super.getEntry(META_INF_VERSIONS + i + sname);
             if (vze != null) break;
             i--;
@@ -649,10 +611,10 @@
 
     private ZipEntry getVersionedEntry(ZipEntry ze) {
         ZipEntry vze = null;
-        if (version > BASE_VERSION && !ze.isDirectory()) {
+        if (BASE_VERSION_MAJOR < versionMajor && !ze.isDirectory()) {
             String name = ze.getName();
             if (!name.startsWith(META_INF)) {
-                vze = searchForVersionedEntry(version, name);
+                vze = searchForVersionedEntry(versionMajor, name);
             }
         }
         return vze == null ? ze : vze;
@@ -1038,7 +1000,7 @@
                 hasClassPathAttribute = match(CLASSPATH_CHARS, b,
                         CLASSPATH_LASTOCC) != -1;
                 // is this a multi-release jar file
-                if (MULTI_RELEASE_ENABLED && version != BASE_VERSION) {
+                if (MULTI_RELEASE_ENABLED && versionMajor != BASE_VERSION_MAJOR) {
                     int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC);
                     if (i != -1) {
                         i += MULTIRELEASE_CHARS.length;
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Wed Jul 13 11:43:45 2016 -0700
@@ -695,7 +695,7 @@
                     throw new FileNotFoundException(p.getPath());
                 }
                 return checkJar(new JarFile(new File(p.getPath()), true, ZipFile.OPEN_READ,
-                        JarFile.Release.RUNTIME));
+                        JarFile.runtimeVersion()));
             }
             URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection();
             uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java	Wed Jul 13 11:43:45 2016 -0700
@@ -66,7 +66,9 @@
 
     static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
         if (isFileURL(url)) {
-            Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE;
+            Runtime.Version version = "runtime".equals(url.getRef())
+                    ? JarFile.runtimeVersion()
+                    : JarFile.baseVersion();
             return new URLJarFile(url, closeController, version);
         } else {
             return retrieve(url, closeController);
@@ -90,12 +92,14 @@
         this.closeController = closeController;
     }
 
-    private URLJarFile(File file, URLJarFileCloseController closeController, Release version) throws IOException {
+    private URLJarFile(File file, URLJarFileCloseController closeController, Runtime.Version version)
+            throws IOException {
         super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE, version);
         this.closeController = closeController;
     }
 
-    private URLJarFile(URL url, URLJarFileCloseController closeController, Release version) throws IOException {
+    private URLJarFile(URL url, URLJarFileCloseController closeController, Runtime.Version version)
+            throws IOException {
         super(new File(ParseUtil.decode(url.getFile())), true, ZipFile.OPEN_READ, version);
         this.closeController = closeController;
     }
@@ -200,7 +204,9 @@
         {
 
             JarFile result = null;
-            Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE;
+            Runtime.Version version = "runtime".equals(url.getRef())
+                    ? JarFile.runtimeVersion()
+                    : JarFile.baseVersion();
 
             /* get the stream before asserting privileges */
             try (final InputStream in = url.openConnection().getInputStream()) {
--- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarAPI.java	Wed Jul 13 11:43:45 2016 -0700
@@ -40,25 +40,19 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import static java.util.jar.JarFile.Release;
-
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
-
 public class MultiReleaseJarAPI {
 
-    static final int MAJOR_VERSION = Runtime.version().major();
-
     String userdir = System.getProperty("user.dir",".");
     CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
     File unversioned = new File(userdir, "unversioned.jar");
     File multirelease = new File(userdir, "multi-release.jar");
     File signedmultirelease = new File(userdir, "signed-multi-release.jar");
-    Release[] values = JarFile.Release.values();
-
 
     @BeforeClass
     public void initialize() throws Exception {
@@ -81,7 +75,7 @@
             Assert.assertFalse(jf.isMultiRelease());
         }
 
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.version())) {
             Assert.assertFalse(jf.isMultiRelease());
         }
 
@@ -89,7 +83,7 @@
             Assert.assertFalse(jf.isMultiRelease());
         }
 
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.version())) {
             Assert.assertTrue(jf.isMultiRelease());
         }
 
@@ -110,68 +104,68 @@
     private void testCustomMultiReleaseValue(String value, boolean expected) throws Exception {
         creator.buildCustomMultiReleaseJar("custom-mr.jar", value);
         File custom = new File(userdir, "custom-mr.jar");
-        try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+        try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Runtime.version())) {
             Assert.assertEquals(jf.isMultiRelease(), expected);
         }
         Files.delete(custom.toPath());
     }
 
-    @Test
-    public void testVersioning() throws Exception {
-        // multi-release jar
-        JarFile jar = new JarFile(multirelease);
-        Assert.assertEquals(Release.BASE, jar.getVersion());
-        jar.close();
+    @DataProvider(name = "versions")
+    public Object[][] createVersionData() throws Exception {
+        return new Object[][]{
+                {JarFile.baseVersion(), 8},
+                {JarFile.runtimeVersion(), Runtime.version().major()},
+                {Runtime.version(), Runtime.version().major()},
+                {Runtime.Version.parse("7.1"), JarFile.baseVersion().major()},
+                {Runtime.Version.parse("9"), 9},
+                {Runtime.Version.parse("9.1.5-ea+200"), 9}
+        };
+    }
 
-        for (Release value : values) {
-            System.err.println("test versioning for Release " + value);
-            try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, value)) {
-                Assert.assertEquals(value, jf.getVersion());
-            }
+    @Test(dataProvider="versions")
+    public void testVersioning(Runtime.Version value, int xpected) throws Exception {
+        Runtime.Version expected = Runtime.Version.parse(String.valueOf(xpected));
+        Runtime.Version base = JarFile.baseVersion();
+
+        // multi-release jar, opened as unversioned
+        try (JarFile jar = new JarFile(multirelease)) {
+            Assert.assertEquals(jar.getVersion(), base);
+        }
+
+        System.err.println("test versioning for Release " + value);
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, value)) {
+            Assert.assertEquals(jf.getVersion(), expected);
         }
 
         // regular, unversioned, jar
-        for (Release value : values) {
-            try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, value)) {
-                Assert.assertEquals(Release.BASE, jf.getVersion());
-            }
-        }
-
-        // assure that we have a Release object corresponding to the actual runtime version
-        String version = "VERSION_" + MAJOR_VERSION;
-        boolean runtimeVersionExists = false;
-        for (Release value : values) {
-            if (version.equals(value.name())) runtimeVersionExists = true;
-        }
-        Assert.assertTrue(runtimeVersionExists);
-    }
-
-    @Test
-    public void testAliasing() throws Exception {
-        for (Release value : values) {
-            System.err.println("test aliasing for Release " + value);
-            String name = value.name();
-            String prefix;
-            if (name.equals("BASE")) {
-                prefix = "";
-            } else if (name.equals("RUNTIME")) {
-                prefix = "META-INF/versions/" + MAJOR_VERSION + "/";
-            } else {
-                prefix = "META-INF/versions/" + name.substring(8) + "/";
-            }
-            // test both multi-release jars
-            readAndCompare(multirelease, value, "README", prefix + "README");
-            readAndCompare(multirelease, value, "version/Version.class", prefix + "version/Version.class");
-            // and signed multi-release jars
-            readAndCompare(signedmultirelease, value, "README", prefix + "README");
-            readAndCompare(signedmultirelease, value, "version/Version.class", prefix + "version/Version.class");
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, value)) {
+            Assert.assertEquals(jf.getVersion(), base);
         }
     }
 
-    private void readAndCompare(File jar, Release version, String name, String realName) throws Exception {
+    @Test(dataProvider="versions")
+    public void testAliasing(Runtime.Version version, int xpected) throws Exception {
+        int n = Math.max(version.major(), JarFile.baseVersion().major());
+        Runtime.Version value = Runtime.Version.parse(String.valueOf(n));
+        System.err.println("test aliasing for Release " + version);
+        String prefix;
+        if (JarFile.baseVersion().equals(value)) {
+            prefix = "";
+        } else {
+            prefix = "META-INF/versions/" + value.major() + "/";
+        }
+        // test both multi-release jars
+        readAndCompare(multirelease, value, "README", prefix + "README");
+        readAndCompare(multirelease, value, "version/Version.class", prefix + "version/Version.class");
+        // and signed multi-release jars
+        readAndCompare(signedmultirelease, value, "README", prefix + "README");
+        readAndCompare(signedmultirelease, value, "version/Version.class", prefix + "version/Version.class");
+    }
+
+    private void readAndCompare(File jar, Runtime.Version version, String name, String realName) throws Exception {
         byte[] baseBytes;
         byte[] versionedBytes;
-        try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, Release.BASE)) {
+        try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, JarFile.baseVersion())) {
             ZipEntry ze = jf.getEntry(realName);
             try (InputStream is = jf.getInputStream(ze)) {
                 baseBytes = is.readAllBytes();
@@ -200,7 +194,7 @@
             ze1 = jf.getEntry(vname);
         }
         Assert.assertEquals(ze1.getName(), vname);
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) {
             ze2 = jf.getEntry(rname);
         }
         Assert.assertEquals(ze2.getName(), rname);
--- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarHttpProperties.java	Wed Jul 13 11:43:45 2016 -0700
@@ -47,14 +47,8 @@
  */
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
--- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarIterators.java	Wed Jul 13 11:43:45 2016 -0700
@@ -43,8 +43,6 @@
 import java.util.stream.Collectors;
 import java.util.zip.ZipFile;
 
-import static java.util.jar.JarFile.Release;
-
 import org.testng.Assert;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -111,17 +109,17 @@
             testStream(jf, mrEntries);
         }
 
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.BASE)) {
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, JarFile.baseVersion())) {
             testEnumeration(jf, baseEntries);
             testStream(jf, baseEntries);
         }
 
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) {
             testEnumeration(jf, v9Entries);
             testStream(jf, v9Entries);
         }
 
-        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Runtime.version())) {
             Map<String,JarEntry> expectedEntries;
             switch (MAJOR_VERSION) {
                 case 9:
@@ -147,17 +145,17 @@
             testStream(jf, uvEntries);
         }
 
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.BASE)) {
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, JarFile.baseVersion())) {
             testEnumeration(jf, uvEntries);
             testStream(jf, uvEntries);
         }
 
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.Version.parse("9"))) {
             testEnumeration(jf, uvEntries);
             testStream(jf, uvEntries);
         }
 
-        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Runtime.version())) {
             testEnumeration(jf, uvEntries);
             testStream(jf, uvEntries);
         }
--- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarProperties.java	Wed Jul 13 11:43:45 2016 -0700
@@ -60,11 +60,10 @@
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
-public class MultiReleaseJarProperties {
 
-    static final int MAJOR_VERSION = Runtime.version().major();
+public class MultiReleaseJarProperties {
+    final static int BASE_VERSION = JarFile.baseVersion().major();
 
-    final static int ROOTVERSION = 8; // magic number from knowledge of internals
     final static String userdir = System.getProperty("user.dir", ".");
     final static File multirelease = new File(userdir, "multi-release.jar");
     protected int rtVersion;
@@ -77,15 +76,15 @@
         CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
         creator.compileEntries();
         creator.buildMultiReleaseJar();
-
-        rtVersion = Integer.getInteger("jdk.util.jar.version", MAJOR_VERSION);
+        int RUNTIME_VERSION = Runtime.version().major();
+        rtVersion = Integer.getInteger("jdk.util.jar.version", RUNTIME_VERSION);
         String mrprop = System.getProperty("jdk.util.jar.enableMultiRelease", "");
         if (mrprop.equals("false")) {
-            rtVersion = ROOTVERSION;
-        } else if (rtVersion < ROOTVERSION) {
-            rtVersion = ROOTVERSION;
-        } else if (rtVersion > MAJOR_VERSION) {
-            rtVersion = MAJOR_VERSION;
+            rtVersion = BASE_VERSION;
+        } else if (rtVersion < BASE_VERSION) {
+            rtVersion = BASE_VERSION;
+        } else if (rtVersion > RUNTIME_VERSION) {
+            rtVersion = RUNTIME_VERSION;
         }
         force = mrprop.equals("force");
 
@@ -135,7 +134,7 @@
                     if (force) throw x;
                 }
             }
-            invokeMethod(vcls, force ? rtVersion : ROOTVERSION);
+            invokeMethod(vcls, force ? rtVersion : BASE_VERSION);
         }
     }
 
--- a/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/java/util/jar/JarFile/mrjar/MultiReleaseJarSecurity.java	Wed Jul 13 11:43:45 2016 -0700
@@ -70,7 +70,7 @@
 
     @Test
     public void testCertsAndSigners() throws IOException {
-        try (JarFile jf = new JarFile(signedmultirelease, true, ZipFile.OPEN_READ, JarFile.Release.RUNTIME)) {
+        try (JarFile jf = new JarFile(signedmultirelease, true, ZipFile.OPEN_READ, Runtime.version())) {
             CertsAndSigners vcas = new CertsAndSigners(jf, jf.getJarEntry("version/Version.class"));
             CertsAndSigners rcas = new CertsAndSigners(jf, jf.getJarEntry("META-INF/versions/" + MAJOR_VERSION + "/version/Version.class"));
             Assert.assertTrue(Arrays.equals(rcas.getCertificates(), vcas.getCertificates()));
--- a/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java	Wed Jul 13 11:43:45 2016 -0700
@@ -132,12 +132,12 @@
         URL rootUrl = new URL(urlFile);
         JarURLConnection juc = (JarURLConnection)rootUrl.openConnection();
         JarFile rootJar = juc.getJarFile();
-        JarFile.Release root = rootJar.getVersion();
+        Runtime.Version root = rootJar.getVersion();
 
         URL runtimeUrl = new URL(urlFile + "#runtime");
         juc = (JarURLConnection)runtimeUrl.openConnection();
         JarFile runtimeJar = juc.getJarFile();
-        JarFile.Release runtime = runtimeJar.getVersion();
+        Runtime.Version runtime = runtimeJar.getVersion();
         if (style.equals("unversioned")) {
             Assert.assertEquals(root, runtime);
         } else {
--- a/jdk/test/tools/jar/multiRelease/Basic.java	Thu Jul 14 10:37:36 2016 +0800
+++ b/jdk/test/tools/jar/multiRelease/Basic.java	Wed Jul 13 11:43:45 2016 -0700
@@ -220,7 +220,7 @@
 
     private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
         try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
-                JarFile.Release.RUNTIME)) {
+                JarFile.runtimeVersion())) {
             assertEquals(jf.isMultiRelease(), expected);
         }
     }