--- /dev/null Fri Dec 18 12:22:01 2015 +++ new/src/java.base/share/classes/jdk/Version.java Fri Dec 18 12:22:01 2015 @@ -0,0 +1,592 @@ +/* + * 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; + +import java.math.BigInteger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * A representation of the JDK version-string which contains a version + * number optionally followed by pre-release and build information. + * + *
+ * + *+ * $MAJOR.$MINOR.$SECURITY + *
{@code $MAJOR} --- The major version number, + * incremented for a major release that contains significant new features as + * specified in a new edition of the Java SE Platform Specification, + * e.g., JSR 337 + * for Java SE 8. Features may be removed in a major release, given + * advance notice at least one major release ahead of time, and incompatible + * changes may be made when justified. The {@code $MAJOR} version number of + * JDK 8 was {@code 8}; the {@code $MAJOR} version number of JDK 9 + * is {@code 9}.
{@code $MINOR} --- The minor version number, + * incremented for a minor update release that may contain compatible bug + * fixes, revisions to standard APIs mandated by a Maintenance Release of + * the relevant Platform Specification, and implementation features outside + * the scope of that Specification such as new JDK-specific APIs, additional + * service providers, new garbage collectors, and ports to new hardware + * architectures. {@code $MINOR} is reset to zero when {@code $MAJOR} is + * incremented.
{@code $SECURITY} --- The security level, + * incremented for a security-update release that contains critical fixes + * including those necessary to improve security. {@code $SECURITY} is reset + * to zero only when {@code $MAJOR} is incremented. A higher + * value of {@code $SECURITY} for a given {@code $MAJOR} value, therefore, + * always indicates a more secure release, regardless of the value of {@code + * $MINOR}.
The fourth and later elements of a version number are free for use by + * downstream consumers of the JDK code base. Such a consumer may, + * e.g., use the fourth element to identify patch releases which + * contain a small number of critical non-security fixes in addition to the + * security fixes in the corresponding security release.
+ * + *The version number does not include trailing zero elements; + * i.e., {@code $SECURITY} is omitted if it has the value zero, and + * {@code $MINOR} is omitted if both {@code $MINOR} and {@code $SECURITY} have + * the value zero.
+ * + *The sequence of numerals in a version number is compared to another + * such sequence in numerical, pointwise fashion; e.g., {@code 9.9.1} + * is less than {@code 9.10.0}. If one sequence is shorter than another then + * the missing elements of the shorter sequence are considered to be zero; + * e.g., {@code 9.1.2} is equal to {@code 9.1.2.0} but less than + * {@code 9.1.2.1}.
+ * + *A version string {@code $VSTR} consists of a version number + * {@code $VNUM}, as described above, optionally followed by pre-release and + * build information, in the format
+ * + *+ * + *+ * $VNUM(-$PRE)?(\+($BUILD)?(-$OPT)?)? + *
where:
+ * + *{@code $PRE}, matching {@code ([a-zA-Z0-9]+)} --- + * A pre-release identifier. Typically {@code ea}, for an early-access + * release that's under active development and potentially unstable, or {@code + * internal}, for an internal developer build. + * + *
When comparing two version strings, a string with a pre-release + * identifier is always less than one with an equal {@code $VNUM} but no such + * identifier. Pre-release identifiers are compared numerically when they + * consist only of digits, and lexicographically otherwise. Numeric + * identifiers are less than than non-numeric identifiers.
{@code $BUILD}, matching {@code + * (0|[1-9][0-9]*)} --- The build number, incremented for each promoted build. + * {@code $BUILD} is reset to {@code 1} when any portion of {@code $VNUM} is + * incremented.
+ * + *When comparing two version strings with equal {@code $VNUM} and + * {@code $PRE} components, a string without a {@code $BUILD} + * component is always less than one with a {@code $BUILD} component; + * otherwise, {@code $BUILD} numbers are compared numerically.
{@code $OPT}, matching {@code ([-a-zA-Z0-9\.]+)} + * --- Additional build information, if desired. In the case of an {@code + * internal} build this will often contain the date and time of the + * build.
+ * + *When comparing two version strings the value of {@code $OPT}, if + * present, may or may not be significant depending on the chosen comparsion + * method.
A short version string ({@code $SVSTR}), often useful in less + * formal contexts, is simply {@code $VNUM} optionally ended with {@code + * -$PRE}.
+ * + * @see JEP 223: New Version-String Scheme + * + * @since 9 + */ +public final class Version + implements ComparableTwo versions are compared by examining the sequence of version + * numbers. If one sequence is shorter than another, then the missing + * elements of the shorter sequence are considered to be zero. If the + * version numbers are equal, then a version with a pre-release identifier + * is always considered to be less than a version without one. + * Pre-release identifiers are compared numerically when they consist only + * of digits, and lexiographically otherwise. Numeric identifiers are + * considered to be less than non-numeric identifiers. A version without + * a build value is always less than one with a build value; otherwise + * build numbers are compared numerically. The optional build information + * is compared lexiographically. During this comparision, a version with + * optional build information is considered to be greater than a version + * without one. + * + *
A version is not comparable to any other type of object. + * + * @param ob + * The object to be compared + * + * @return A negative integer, zero, or a positive integer if this + * {@code Version} is less than, equal to, or greater than the + * given {@code Version} + * + * @throws NullPointerException + * If the given object is {@code null} + */ + @Override + public int compareTo(Version ob) { + return compare(ob, false); + } + + /** + * Compares this version to another disregarding optional build + * information. + * + *
Two versions are compared by examining the version string as + * described in {@link #compareTo(Version)} with the exception that the + * optional build information is always ignored. + * + *
A version is not comparable to any other type of object.
+ *
+ * @param ob
+ * The object to be compared
+ *
+ * @return A negative integer, zero, or a positive integer if this
+ * {@code Version} is less than, equal to, or greater than the
+ * given {@code Version}
+ *
+ * @throws NullPointerException
+ * If the given object is {@code null}
+ */
+ public int compareToIgnoreOpt(Version ob) {
+ return compare(ob, true);
+ }
+
+ private int compare(Version ob, boolean ignoreOpt) {
+ if (ob == null)
+ throw new NullPointerException("Invalid argument");
+
+ int ret = compareVersion(ob);
+ if (ret != 0)
+ return ret;
+
+ ret = comparePre(ob);
+ if (ret != 0)
+ return ret;
+
+ ret = compareBuild(ob);
+ if (ret != 0)
+ return ret;
+
+ if (!ignoreOpt)
+ return compareOpt(ob);
+
+ return 0;
+ }
+
+ private int compareVersion(Version ob) {
+ int size = version.size();
+ int oSize = ob.version().size();
+ int min = Math.min(size, oSize);
+ for (int i = 0; i < min; i++) {
+ Integer val = version.get(i);
+ Integer oVal = ob.version().get(i);
+ if (val != oVal)
+ return val - oVal;
+ }
+ if (size != oSize)
+ return size - oSize;
+ return 0;
+ }
+
+ private int comparePre(Version ob) {
+ Optional Two {@code Version}s are equal if and only if they represent the
+ * same version string.
+ *
+ * This method satisfies the general contract of the {@link
+ * Object#equals(Object) Object.equals} method. Two {@code Version}s are equal if and only if they represent the
+ * same version string disregarding the optional build information.
+ *
+ * This method satisfies the general contract of the {@link
+ * Object#equals(Object) Object.equals} method. This method satisfies the general contract of the {@link
+ * Object#hashCode Object.hashCode} method.
+ *
+ * @return The hashcode of this version
+ */
+ @Override
+ public int hashCode() {
+ int h = 1;
+ int p = 17;
+
+ h = p * h + version.hashCode();
+ h = p * h + pre.hashCode();
+ h = p * h + build.hashCode();
+ h = p * h + optional.hashCode();
+
+ return h;
+ }
+}
--- /dev/null Fri Dec 18 12:22:02 2015
+++ new/test/jdk/Version/Basic.java Fri Dec 18 12:22:02 2015
@@ -0,0 +1,397 @@
+/*
+ * 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
+ * @summary Unit test for jdk.Version.
+ * @bug 8072379
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.util.stream.Collectors;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import jdk.Version;
+import static java.lang.System.out;
+
+public class Basic {
+ private static final Class extends Throwable> IAE
+ = IllegalArgumentException.class;
+ private static final Class extends Throwable> NPE
+ = NullPointerException.class;
+ private static final Class extends Throwable> NFE
+ = NumberFormatException.class;
+ private static final Class> VERSION = Version.class;
+
+ private static final BigInteger TOO_BIG
+ = (BigInteger.valueOf(Integer.MAX_VALUE)).add(BigInteger.ONE);
+ private static final String TOO_BIG_STR = TOO_BIG.toString();
+
+ public static void main(String ... args) {
+
+ //// Tests for parse(), major(), minor(), security(), pre(),
+ //// build(), opt(), version(), toString()
+ // v M m sec pre bld opt
+
+ // $VNUM
+ test("9", 9, 0, 0, "", 0, "");
+ test("9.1", 9, 1, 0, "", 0, "");
+ test("9.0.1", 9, 0, 1, "", 0, "");
+ test("404.1.2", 404, 1, 2, "", 0, "");
+ test("9.1.2.3", 9, 1, 2, "", 0, "");
+ test("1000.0.0.0.0.0.99999999", 1000, 0, 0, "", 0, "");
+
+ tryCatch(null, NPE);
+ tryCatch("", IAE);
+ tryCatch("foo", IAE);
+ tryCatch("7a", IAE);
+ tryCatch("0", IAE);
+ tryCatch("09", IAE);
+ tryCatch("9.0", IAE);
+ tryCatch("9.0.", IAE);
+ tryCatch("1.9,1", IAE);
+ tryCatch(TOO_BIG_STR, NFE);
+
+ // $PRE
+ test("9-ea", 9, 0, 0, "ea", 0, "");
+ test("9-internal", 9, 0, 0, "internal", 0, "");
+ test("9-0", 9, 0, 0, "0", 0, "");
+ test("9.2.7-8", 9, 2, 7, "8", 0, "");
+ test("1-ALL", 1, 0, 0, "ALL", 0, "");
+ test("2.3.4.5-1a", 2, 3, 4, "1a", 0, "");
+ test("1-" + TOO_BIG_STR, 1, 0, 0, TOO_BIG_STR, 0, "");
+
+ tryCatch("3.14159-", IAE);
+ tryCatch("3.14159-%", IAE);
+
+ // $BUILD
+ test("9+0", 9, 0, 0, "", 0, "");
+ test("3.14+9999900", 3, 14, 0, "", 9999900, "");
+ test("9-pre+105", 9, 0, 0, "pre", 105, "");
+ test("6.0.42-8beta+4", 6, 0, 42, "8beta", 4, "");
+
+ tryCatch("9+", IAE);
+ tryCatch("7+a", IAE);
+ tryCatch("9+00", IAE);
+ tryCatch("4.2+01", IAE);
+ tryCatch("4.2+1a", IAE);
+ tryCatch("1+" + TOO_BIG_STR, NFE);
+
+ // $OPT
+ test("9+-foo", 9, 0, 0, "", 0, "foo");
+ test("42+---bar", 42, 0, 0, "", 0, "--bar");
+ test("2.91+-8061493-", 2, 91, 0, "", 0, "8061493-");
+ test("24+-foo.bar", 24, 0, 0, "", 0, "foo.bar");
+ test("9-ribbit+17-...", 9, 0, 0, "ribbit", 17, "...");
+ test("7+1-" + TOO_BIG_STR, 7,0, 0, "", 1, TOO_BIG_STR);
+
+ tryCatch("1.4142+-", IAE);
+ tryCatch("2.9979+-%", IAE);
+
+ //// Test for current()
+ testCurrent();
+
+ //// Test for equals{IgnoreOpt}?(), hashCode(), compareTo{IgnoreOpt}?()
+ // compare: after "<" == -1, equal == 0, before ">" == 1
+ // v0 v1 eq eqNO cmp cmpNO
+ testEHC("9", "9", true, true, 0, 0);
+
+ testEHC("8", "9", false, false, -1, -1);
+ testEHC("9", "10", false, false, -1, -1);
+ testEHC("9", "8", false, false, 1, 1);
+
+ // $OPT comparison
+ testEHC("9", "9+-oink", false, true, -1, 0);
+ testEHC("9+-ribbit", "9+-moo", false, true, 1, 0);
+ testEHC("9-quack+-ribbit",
+ "9-quack+-moo", false, true, 1, 0);
+ testEHC("9.1+7", "9.1+7-moo-baa-la", false, true, -1, 0);
+
+ // numeric vs. non-numeric $PRE
+ testEHC("9.1.1.2-2a", "9.1.1.2-12", false, false, 1, 1);
+ testEHC("9.1.1.2-12", "9.1.1.2-4", false, false, 1, 1);
+
+ testEHC("27.16", "27.16+120", false, false, 1, 1);
+ testEHC("10", "10-ea", false, false, 1, 1);
+ testEHC("10.1+1", "10.1-ea+1", false, false, 1, 1);
+ testEHC("10.0.1+22", "10.0.1+21", false, false, 1, 1);
+
+ // numeric vs. non-numeric $PRE
+ testEHC("9.1.1.2-12", "9.1.1.2-a2", false, false, -1, -1);
+ testEHC("9.1.1.2-1", "9.1.1.2-4", false, false, -1, -1);
+
+ testEHC("9-internal", "9", false, false, -1, -1);
+ testEHC("9-ea+120", "9+120", false, false, -1, -1);
+ testEHC("9-ea+120", "9+120", false, false, -1, -1);
+ testEHC("9+101", "9", false, false, -1, -1);
+ testEHC("9+101", "9+102", false, false, -1, -1);
+ testEHC("1.9-ea", "9-ea", false, false, -1, -1);
+
+ if (fail != 0)
+ throw new RuntimeException((fail + pass) + " tests: "
+ + fail + " failure(s), first", first);
+ else
+ out.println("all " + (fail + pass) + " tests passed");
+
+ }
+
+ private static void test(String s, Integer major, Integer minor,
+ Integer sec, String pre, Integer build,
+ String opt)
+ {
+ Version v = testParse(s);
+
+ testStr(v.toString(), s);
+
+ testInt(v.major(), major);
+ testInt(v.minor(), minor);
+ testInt(v.security(), sec);
+ testStr((v.pre().isPresent() ? v.pre().get() : ""), pre);
+ testInt((v.build().isPresent() ? v.build().get() : 0), build);
+ testStr((v.optional().isPresent() ? v.optional().get() : ""), opt);
+
+ testVersion(v.version(), s);
+ }
+
+ private static Version testParse(String s) {
+ Version v = Version.parse(s);
+ pass();
+ return v;
+ }
+
+ private static void testInt(int got, int exp) {
+ if (got != exp) {
+ fail("testInt()", Integer.toString(exp), Integer.toString(got));
+ } else {
+ pass();
+ }
+ }
+
+ private static void testStr(String got, String exp) {
+ if (!got.equals(exp)) {
+ fail("testStr()", exp, got);
+ } else {
+ pass();
+ }
+ }
+
+ private static void tryCatch(String s, Class extends Throwable> ex) {
+ Throwable t = null;
+ try {
+ Version.parse(s);
+ } catch (Throwable x) {
+ if (ex.isAssignableFrom(x.getClass())) {
+ t = x;
+ } else
+ x.printStackTrace();
+ }
+ if ((t == null) && (ex != null))
+ fail(s, ex);
+ else
+ pass();
+ }
+
+ private static void testCurrent() {
+ Version current = Version.current();
+ String javaVer = System.getProperty("java.version");
+
+ // java.version == $VNUM(\-$PRE)
+ String [] ver = javaVer.split("-");
+ List