Author: rwhitcomb Date: Wed Apr 28 05:59:50 2021 New Revision: 1889254 URL: http://svn.apache.org/viewvc?rev=1889254&view=rev Log: Add "safelyDecode" into Version itself (from ApplicationContext).
Modified: pivot/trunk/core/src/org/apache/pivot/util/Version.java pivot/trunk/core/test/org/apache/pivot/util/test/VersionTest.java Modified: pivot/trunk/core/src/org/apache/pivot/util/Version.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/util/Version.java?rev=1889254&r1=1889253&r2=1889254&view=diff ============================================================================== --- pivot/trunk/core/src/org/apache/pivot/util/Version.java (original) +++ pivot/trunk/core/src/org/apache/pivot/util/Version.java Wed Apr 28 05:59:50 2021 @@ -18,6 +18,7 @@ package org.apache.pivot.util; import java.io.Serializable; + /** * Represents a version number. Version numbers are defined as: <p> * <i>major</i>.<i>minor</i>.<i>maintenance</i>_<i>update</i> <p> for example, @@ -26,50 +27,102 @@ import java.io.Serializable; public class Version implements Comparable<Version>, Serializable { private static final long serialVersionUID = -3677773163272115116L; - private short majorRevision = 0; - private short minorRevision = 0; - private short maintenanceRevision = 0; + /** + * The default version object (0, 0, 0, 0). + */ + public static final Version ZERO_VERSION = new Version(0, 0, 0, 0L); + + /** + * The real major version number. + */ + private short majorVersion = 0; + /** + * The real minor version number. + */ + private short minorVersion = 0; + /** + * The real maintenance version number. + */ + private short maintenanceVersion = 0; + /** + * The real update version number. + */ private long updateRevision = 0; + /** + * The build string. + */ private String build = null; - public Version(final int majorRevision, final int minorRevision, final int maintenanceRevision, - final long updateRevision) { - this(majorRevision, minorRevision, maintenanceRevision, updateRevision, null); - } - - public Version(final int majorRevision, final int minorRevision, final int maintenanceRevision, - final long updateRevision, final String build) { - Utils.checkInRangeOfShort(majorRevision, "majorRevision"); - Utils.checkInRangeOfShort(minorRevision, "minorRevision"); - Utils.checkInRangeOfShort(maintenanceRevision, "maintenanceRevision"); - - this.majorRevision = (short) majorRevision; - this.minorRevision = (short) minorRevision; - this.maintenanceRevision = (short) maintenanceRevision; - this.updateRevision = updateRevision; - this.build = build; + /** + * Construct a version given all the numeric values. + * + * @param major The new major version. + * @param minor The new minor version. + * @param maintenance The new maintenance version. + * @param update The new update version. + */ + public Version(final int major, final int minor, final int maintenance, final long update) { + this(major, minor, maintenance, update, null); + } + + /** + * Construct a version given all the information. + * + * @param major The new major version. + * @param minor The new minor version. + * @param maintenance The new maintenance version. + * @param update The new update version. + * @param buildString The new build string. + */ + public Version(final int major, final int minor, final int maintenance, final long update, + final String buildString) { + Utils.checkInRangeOfShort(major, "majorVersion"); + Utils.checkInRangeOfShort(minor, "minorVersion"); + Utils.checkInRangeOfShort(maintenance, "maintenanceVersion"); + + majorVersion = (short) major; + minorVersion = (short) minor; + maintenanceVersion = (short) maintenance; + updateRevision = update; + build = buildString; } + /** + * @return The major version number. + */ public short getMajorRevision() { - return majorRevision; + return majorVersion; } + /** + * @return The minor version number. + */ public short getMinorRevision() { - return minorRevision; + return minorVersion; } + /** + * @return The maintenance version number. + */ public short getMaintenanceRevision() { - return maintenanceRevision; + return maintenanceVersion; } + /** + * @return The update revision number. + */ public long getUpdateRevision() { return updateRevision; } + /** + * @return A composite value, consisting of all the numeric components + * shifted into parts of a long. + */ public long getNumber() { - long number = ((long) ((majorRevision) & 0xffff) << (16 * 3) - | (long) ((minorRevision) & 0xffff) << (16 * 2) - | (long) ((maintenanceRevision) & 0xffff) << (16 * 1)) + long number = ((long) ((majorVersion) & 0xffff) << (16 * 3) + | (long) ((minorVersion) & 0xffff) << (16 * 2) + | (long) ((maintenanceVersion) & 0xffff) << (16 * 1)) + updateRevision; return number; @@ -92,13 +145,13 @@ public class Version implements Comparab @Override public String toString() { - String string = this.majorRevision - + "." + this.minorRevision - + "." + this.maintenanceRevision - + "_" + String.format("%02d", this.updateRevision); + String string = majorVersion + + "." + minorVersion + + "." + maintenanceVersion + + "_" + String.format("%02d", updateRevision); - if (this.build != null) { - string += "-" + this.build; + if (build != null) { + string += "-" + build; } return string; @@ -109,21 +162,28 @@ public class Version implements Comparab */ public String simpleToString() { return String.format("%1$d.%2$d.%3$d", - this.majorRevision, - this.minorRevision, - this.maintenanceRevision); + majorVersion, + minorVersion, + maintenanceVersion); } + /** + * Decode a string into the version parts. + * + * @param string The input string in a format recognizable as a version string. + * @return The new version object constructed from the string information. + */ public static Version decode(final String string) { Version version = null; - short majorRevision = 0; - short minorRevision = 0; - short maintenanceRevision = 0; - long updateRevision = 0; - String build = null; + short major = 0; + short minor = 0; + short maintenance = 0; + long update = 0; + String buildString = null; String revision; + // Some "version" strings separate fields with a space // While Java 9 uses a new scheme where "build" uses a "+" String[] parts = string.split("[ +\\-]"); @@ -132,38 +192,58 @@ public class Version implements Comparab } else { int len = parts[0].length(); revision = string.substring(0, len); - build = string.substring(len + 1); + buildString = string.substring(len + 1); } String[] revisionNumbers = revision.split("\\."); if (revisionNumbers.length > 0) { - majorRevision = Short.parseShort(revisionNumbers[0]); + major = Short.parseShort(revisionNumbers[0]); if (revisionNumbers.length > 1) { - minorRevision = Short.parseShort(revisionNumbers[1]); + minor = Short.parseShort(revisionNumbers[1]); if (revisionNumbers.length > 2) { - String[] maintenanceRevisionNumbers = revisionNumbers[2].split("[_\\-]"); + String[] maintenanceVersionNumbers = revisionNumbers[2].split("[_\\-]"); - if (maintenanceRevisionNumbers.length > 0) { - maintenanceRevision = Short.parseShort(maintenanceRevisionNumbers[0]); + if (maintenanceVersionNumbers.length > 0) { + maintenance = Short.parseShort(maintenanceVersionNumbers[0]); - if (maintenanceRevisionNumbers.length > 1) { - updateRevision = Long.parseLong(maintenanceRevisionNumbers[1]); + if (maintenanceVersionNumbers.length > 1) { + update = Long.parseLong(maintenanceVersionNumbers[1]); } } } } - version = new Version(majorRevision, minorRevision, maintenanceRevision, - updateRevision, build); + version = new Version(major, minor, maintenance, update, buildString); } return version; } /** + * Added so that any unexpected version string formats that might cause an error + * will not also cause the application to fail to start. + * + * @param versionString A potential version string to parse/decode. + * @return The parsed version information (if possible), or an empty version + * (that will look like: "0.0.0_00") if there was a parsing problem of any kind. + */ + public static Version safelyDecode(final String versionString) { + if (!Utils.isNullOrEmpty(versionString)) { + try { + return decode(versionString); + } catch (Throwable ex) { + String exMsg = ExceptionUtils.toString(ex); + System.err.println("Error decoding version string \"" + versionString + "\": " + exMsg); + } + } + return ZERO_VERSION; + } + + + /** * Decode the implementation version found in our jar file manifest into * a {@link Version} object. * Modified: pivot/trunk/core/test/org/apache/pivot/util/test/VersionTest.java URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/util/test/VersionTest.java?rev=1889254&r1=1889253&r2=1889254&view=diff ============================================================================== --- pivot/trunk/core/test/org/apache/pivot/util/test/VersionTest.java (original) +++ pivot/trunk/core/test/org/apache/pivot/util/test/VersionTest.java Wed Apr 28 05:59:50 2021 @@ -19,6 +19,7 @@ package org.apache.pivot.util.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,7 +28,13 @@ import org.junit.Test; import org.apache.pivot.util.Version; +/** + * Tests of the {@link Version} class. + */ public class VersionTest { + /** + * Test version decode that happens at application startup. + */ @Test public void testApplicationStartup() { // These are the things that happen right away for ApplicationContext @@ -54,34 +61,48 @@ public class VersionTest { } } + /** The Java version string that broke the old code (build overflows a byte). */ private static final String S1_8_131 = "1.8.0_131"; + /** Decoding that breaking version string. */ private static final Version V1 = Version.decode(S1_8_131); + /** The version object that should match that decoded value. */ private static final Version V8_131 = new Version(1, 8, 0, 131); + /** A version 1.0 string. */ private static final String S1_0_0 = "1.0.0_00"; + /** Decoding version 1. */ private static final Version V0 = Version.decode(S1_0_0); + /** The version object that should match version 1. */ private static final Version V1_0 = new Version(1, 0, 0, 0); + /** The null/empty version object. */ + private static final Version EMPTY = new Version(0, 0, 0, 0); + /** + * Test basic parsing (including our overflow fail case). + */ @Test public void testVersionParsing() { - assertEquals("version decode", V1, V8_131); - assertEquals("version to string", S1_8_131, V8_131.toString()); + assertEquals("version decode", V8_131, V1); + assertEquals("version to string", V8_131.toString(), S1_8_131); - assertEquals("version 0 decode", V0, V1_0); - assertEquals("version 0 to string", V1_0.toString(), S1_0_0); + assertEquals("version 0 decode", V1_0, V0); + assertEquals("version 0 to string", S1_0_0, V1_0.toString()); // New Java 9 version number scheme String j9 = "9.0.1+11"; Version vj9 = Version.decode(j9); Version vj90 = new Version(9, 0, 1, 0); - assertEquals("Java version 9 decode", vj9, vj90); - assertEquals("Java version 9 to string", vj9.toString(), "9.0.1_00-11"); + assertEquals("Java version 9 decode", vj90, vj9); + assertEquals("Java version 9 to string", "9.0.1_00-11", vj9.toString()); } + /** + * Test overflows of the new short values. + */ @Test public void testLimits() { Version vMax = new Version(32767, 32767, 32767, 32767); String sMax = "32767.32767.32767_32767"; - assertEquals("max versions", vMax.toString(), sMax); + assertEquals("max versions", sMax, vMax.toString()); IllegalArgumentException argFailure = null; try { Version vOverflow = new Version(32768, 0, 1, 0); @@ -89,23 +110,32 @@ public class VersionTest { argFailure = iae; } assertNotNull("illegal argument exception", argFailure); - assertEquals("exception message", argFailure.getMessage(), - "majorRevision must be less than or equal 32767."); + assertEquals("exception message", + "majorVersion must be less than or equal 32767.", + argFailure.getMessage()); } + /** + * Test {@link Version#getNumber}. + */ @Test public void testNumber() { Version vNum = new Version(2, 1, 1, 100); long num = vNum.getNumber(); - System.out.format("test getNumber(): %1$s -> %2$d%n", vNum, num); - assertEquals("long number", num, 562954248454244L); + System.out.format("test getNumber(): %1$s -> %2$d (0x%2$016x)%n", vNum, num); + assertEquals("long number", 0x0002000100010064L, num); } - // Taken from PIVOT-996 test case + /** Taken from PIVOT-996 test case -- the build suffix ... */ private static final String PIVOT_996_SUFFIX = "25.51-b14"; + /** PIVOT-996 complete input string. */ private static final String PIVOT_996_INPUT = "8.1.028 " + PIVOT_996_SUFFIX; + /** What we expect from PIVOT-996 test case on output. */ private static final String PIVOT_996_OUTPUT = "8.1.28_00-" + PIVOT_996_SUFFIX; + /** + * Other test cases (from issues, or other sources). + */ @Test public void testOtherVersions() { Version jvmVersionParsed = Version.decode(PIVOT_996_INPUT); @@ -114,10 +144,10 @@ public class VersionTest { System.out.println("Information only: our version = " + Version.implementationVersion()); - assertEquals("PIVOT-996 test case", jvmVersionParsed, jvmVersionExplicit); + assertEquals("PIVOT-996 test case", jvmVersionExplicit, jvmVersionParsed); System.out.format("PIVOT-996 parsed/toString: %1$s, expected: %2$s%n", parsedToString, PIVOT_996_OUTPUT); - assertEquals("PIVOT-996 toString", parsedToString, PIVOT_996_OUTPUT); + assertEquals("PIVOT-996 toString", PIVOT_996_OUTPUT, parsedToString); Pattern versionPattern = Pattern.compile("(\\d+(\\.\\d+\\.\\d+)?).*"); String sysJavaVersion = System.getProperty("java.runtime.version"); @@ -136,19 +166,22 @@ public class VersionTest { String newJava9Formatted = newJava9.toString(); System.out.format("Potential new Java version: %1$s, parsed and formatted: %2$s%n", newJava9Version, newJava9Formatted); - assertEquals(newJava9Formatted, "9.0.0_00-ea+19"); + assertEquals("new Java 9 version", "9.0.0_00-ea+19", newJava9Formatted); String newJava10Version = "10+-ea"; Version newJava10 = Version.decode(newJava10Version); String newJava10Formatted = newJava10.toString(); System.out.format("Potential new Java 10 version: %1$s, parsed and formatted: %2$s%n", newJava10Version, newJava10Formatted); - assertEquals(newJava10Formatted, "10.0.0_00--ea"); + assertEquals("new Java 10 version", "10.0.0_00--ea", newJava10Formatted); } + /** + * Complete test of the new version strings possible with Java 9 + * (taken from <a href="http://openjdk.java.net/jeps/223">http://openjdk.java.net/jeps/223</a>). + */ @Test public void testJava9Versions() { - // All the other suggested versions from "http://openjdk.java.net/jeps/223" String[] versions = { "9-ea+19", "9+100", @@ -182,4 +215,18 @@ public class VersionTest { System.out.format("Raw %1$s -> %2$s%n", version, v.toString()); } } + + /** + * Test the new {@link Version#safelyDecode}. + */ + @Test + public void testSafelyDecode() { + try { + Version junk = Version.safelyDecode("this is junk"); + assertEquals("safely decode default", EMPTY, junk); + } catch (Exception ex) { + fail("safelyDecode threw an exception: " + ex.getMessage()); + } + } } +