JEP 223: New Version-String Scheme

AuthorsIris Clark, Mark Reinhold
OwnerIris Clark
Created2014/10/20 18:27
Updated2016/07/12 21:57
TypeFeature
StatusCompleted
ScopeSE
Discussionverona dash dev at openjdk dot java dot net
EffortM
DurationM
Priority1
Reviewed byBrian Goetz, Roger Riggs
Endorsed byBrian Goetz
Release9
Issue8061493
Relates to8156745: JEP 223 java.specification.version change from "1.8" to "9" (without "1." prefix) blocks jai_imageio-1.1
8085822: JEP 223: New Version-String Scheme (initial integration)

Summary

Revise the JDK's version-string scheme so that it is easier to distinguish major, minor, and security-update releases.

Goals

Non-Goals

Motivation

Which release contains all of the most recent security fixes: JDK 7 Update 55, or JDK 7 Update 60?

It looks like JDK 7 Update 60 is five releases later than Update 55, so therefore it must include more security fixes, right?

That conclusion is, sadly, incorrect: These two releases both contain exactly the same security fixes. To understand this answer, you first need to understand the current numbering scheme for JDK Update releases. Minor releases containing changes beyond security fixes are multiples of 20. Security releases based on the previous minor release are odd numbers incremented by five, or by six if necessary in order to keep the update number odd. To understand whether a minor release is actually more secure than an earlier release ultimately requires looking at the release notes or the source code.

What's the difference between releases named "JDK 7 Update 60", "1.7.0_60", and "JDK 7u60"?

These are just different names for the same release. These differences make it difficult to identify and verify equivalent releases. A simple pointwise comparison of sequences of parsed tokens does not suffice; instead, a fairly sophisticated algorithm is needed. The use of the lower-case 'u' is not an industry standard and is not language-neutral.

It's long past time for a simpler, more intuitive versioning scheme.

Description

Version numbers

A version number, $VNUM, is a non-empty sequence of elements separated by period characters (U+002E). An element is either zero, or an unsigned integer numeral without leading zeros. The final element in a version number must not be zero. The format is:

^[1-9][0-9]*(((\.0)*\.[1-9][0-9]*)*)*$

The sequence may be of arbitrary length but the first three elements are assigned specific meanings, as follows:

$MAJOR.$MINOR.$SECURITY

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., $SECURITY is omitted if it has the value zero, and $MINOR is omitted if both $MINOR and $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., 9.9.1 is less than 9.10.3. If one sequence is shorter than another then the missing elements of the shorter sequence are considered to be less than the corresponding elements of the longer sequence; e.g., 9.1.2 is less than 9.1.2.1.

Version strings

A version string, $VSTR, consists of a version number $VNUM, as described above, optionally followed by pre-release and build information, in the format

$VNUM(-$PRE)?(\+($BUILD)?(-$OPT)?)?

where:

A version number 10-ea matches $VNUM = "10" and $PRE = "ea". The version number 10+-ea matches $VNUM = "10" and $OPT = "ea".

The following table compares potential version strings for JDK 9, using the existing and proposed formats:

Existing                Proposed
Release Type    long           short    long           short
------------    --------------------    --------------------
Early Access    1.9.0-ea-b19    9-ea    9-ea+19        9-ea
Major           1.9.0-b100      9       9+100          9
Security #1     1.9.0_5-b20     9u5     9.0.1+20       9.0.1
Security #2     1.9.0_11-b12    9u11    9.0.2+12       9.0.2
Minor #1        1.9.0_20-b62    9u20    9.1.2+62       9.1.2
Security #3     1.9.0_25-b15    9u25    9.1.3+15       9.1.3
Security #4     1.9.0_31-b08    9u31    9.1.4+8        9.1.4
Minor #2        1.9.0_40-b45    9u40    9.2.4+45       9.2.4

For reference, this table shows version strings in the new format as they would have been used, hypothetically, for some JDK 7 update and security releases:

Actual               Hypothetical
Release Type        long           short    long          short
------------        --------------------    -------------------
Security 2013/04    1.7.0_21-b11    7u21    7.4.10+11    7.4.10
Security 2013/06    1.7.0_25-b15    7u25    7.4.11+15    7.4.11
Minor    2013/09    1.7.0_40-b43    7u40    7.5.11+43    7.5.11
Security 2013/10    1.7.0_45-b18    7u45    7.5.12+18    7.5.12
Security 2014/01    1.7.0_51-b13    7u51    7.5.13+13    7.5.13
Security 2014/04    1.7.0_55-b13    7u55    7.5.14+13    7.5.14
Minor    2014/05    1.7.0_60-b19    7u60    7.6.14+19    7.6.14
Security 2014/07    1.7.0_65-b20    7u65    7.6.15+20    7.6.15

Dropping the initial 1 element from version numbers

This proposal drops the initial 1 element from JDK version numbers. That is, it suggests that the first release of JDK 9 will have the version number 9.0.0 rather than 1.9.0.0.

After nearly twenty years it's clear that the second element of the current version-number scheme is the JDK's de facto $MAJOR version number. We increment that element when we add significant new features, and also when we make incompatible changes.

We could start treating the initial element of the current scheme as the $MAJOR version number, but then JDK 9 would have the version number 2.0.0 even though everyone already refers to it as "JDK 9". This would help no one.

If we retain the initial 1 then JDK version numbers will continue to violate the principles of Semantic Versioning and developers new to Java will continue to be confused about the difference between, e.g., 1.9 and 9.

There is some risk in dropping the initial 1. There are many ways to compare version numbers; some will work correctly, while some will not.

Anecdotal evidence suggests that existing code in the third category is not very common, but we would welcome data to the contrary.

API

A simple Java API to parse, validate, and compare version strings will be defined (8072379, 8144062):

package java.lang;

import java.util.Optional;

public class Runtime {

    public static Version version();

    public static class Version
        implements Comparable<Version>
    {

        public static Version parse(String);

        public int major();
        public int minor();
        public int security();

        public List<Integer> version();
        public Optional<String> pre();
        public Optional<Integer> build();
        public Optional<String> optional();

        public int compareTo(Version o);
        public int compareToIgnoreOpt(Version o);

        public boolean equals(Object o);
        public boolean equalsIgnoreOpt(Object o);

        public String toString();
        public int hashCode();
    }
}

An equivalent C API will be defined, most likely in terms of a revised jvm_version_info struct.

All code in the JDK that inspects and compares JDK version strings will be updated to use these APIs. Developers whose libraries or applications inspect and compare JDK version strings will be encouraged to use these APIs.

System properties

The values returned by the following system properties are modified by this JEP. The general syntax is as follows:

Name                            Syntax
------------------------------  --------------
java.version                    $VNUM(\-$PRE)?  
java.runtime.version            $VSTR
java.vm.version                 $VSTR
java.specification.version      $VNUM
java.vm.specification.version   $VNUM

The system property java.class.version is not affected.

The following table shows the existing and proposed values for different release types:

System Property                   Existing      Proposed
-------------------------------   ------------  --------
Early Access 
  java.version                    1.9.0-ea      9-ea
  java.runtime.version            1.9.0-ea-b73  9-ea+73
  java.vm.version                 1.9.0-ea-b73  9-ea+73
  java.specification.version      1.9           9
  java.vm.specification.version   1.9           9

Major (GA)
  java.version                    1.9.0         9
  java.runtime.version            1.9.0-b100    9+100
  java.vm.version                 1.9.0-b100    9+100
  java.specification.version      1.9           9
  java.vm.specification.version   1.9           9

Minor #1 (GA)
  java.version                    1.9.0_20      9.1.2
  java.runtime.version            1.9.0_20-b62  9.1.2+62
  java.vm.version                 1.9.0_20-b62  9.1.2+62
  java.specification.version      1.9           9
  java.vm.specification.version   1.9           9

Security #1 (GA)
  java.version                    1.9.0_5       9.0.1
  java.runtime.version            1.9.0_5-b20   9.0.1+20
  java.vm.version                 1.9.0_5-b20   9.0.1+20
  java.specification.version      1.9           9
  java.vm.specification.version   1.9           9

Note that all code which has historically detected . in any of these system properties as part of version identification will need to be examined and potentially modified. For example, System.getProperty("java.version").indexof('.') will return -1 for major releases.

Launcher

In the OpenJDK java launcher implementation, system properties are used when reporting version information, e.g. java -version, java -fullversion, and java -showversion.

The launcher output continues to depend on the system properties as follows:

$ java -version
openjdk version \"${java.version}\"
${java.runtime.name} (build ${java.runtime.version})
${java.vm.name} (build ${java.vm.version}, ${java.vm.info})

$ java -showversion < ... >
openjdk version \"${java.version}\"
${java.runtime.name} (build ${java.runtime.version})
${java.vm.name} (build ${java.vm.version}, ${java.vm.info})
[ ... ]

$ java -fullversion
openjdk full version \"${java.runtime.version}\"

Implementation details may be found in the source.

@since JavaDoc tag

The value for the @since JavaDoc tag will continue to be aligned with the system property java.specification.version; hence, new JDK 9 APIs will be indicated by @since 9.

Mercurial changeset tags

Mercurial tags are used to identify a promotion's changesets. Tools such as Code Tool's jcheck, which is used to validate all changesets pushed to JDK release forests, will be enhanced to support tags using the new version scheme.

The general syntax for Mercurial tags is jdk\-$VNUM\+$BUILD. The following table shows the proposed values for different release types:

Release Type      Proposed
----------------  -----------
Major (GA)        jdk-9+100
Minor #1 (GA)     jdk-9.1.2+27
Security #1 (GA)  jdk-9.0.1+3

Some tools may need to support both existing and proposed tag formats.

Testing

Changing the syntax and semantics of version strings will require extensive testing of all component areas. Existing tests that are independent of the JDK version string should continue to pass.