JEP 223: New Version-String Scheme
Новая схема строк версий
| Authors | Iris Clark, Mark Reinhold |
| Ответственный | Iris Clark |
| Тип | Feature |
| Область | SE |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Обсуждение | verona dash dev at openjdk dot java dot net |
| Трудоёмкость | M |
| Длительность | M |
| Связан с | 8085822: JEP 223: New Version-String Scheme (initial integration) |
| Рецензенты | Brian Goetz, Roger Riggs |
| Одобрен | Brian Goetz |
| Создан | 2014/10/20 18:27 |
| Обновлён | 2021/10/03 12:50 |
| Задача | 8061493 |
Аннотация
Определить схему строк версий, в которой легко различать основные и промежуточные выпуски и выпуски с обновлениями безопасности, и применить её к JDK.
Цели
-
Схема должна быть легко понятна людям и легко разбираться программами.
-
Соответствовать современной отраслевой практике, в частности Semantic Versioning (семантическому версионированию).
-
Схема должна подходить для существующих систем пакетов и механизмов развёртывания на платформах, включая RPM, dpkg, IPS и Java Network Launching Protocol (JNLP).
-
Отказаться от нынешней практики кодировать в одном элементе строки версии два вида информации, т. е. номер промежуточного выпуска и уровень безопасности: такую запись трудно расшифровать, и из-за неё пропускается много номеров версий.
-
Предоставить простой API для разбора, проверки и сравнения строк версий.
Что не является целью
- Изменять формат строки версии, который используется в любом выпуске, предшествующем выпуску, в который запланирован этот JEP.
Мотивация
Какой выпуск содержит все самые последние исправления безопасности: JDK 7 Update 55 или JDK 7 Update 60?
Похоже, что JDK 7 Update 60 вышел на пять выпусков позже Update 55, а значит, он должен содержать больше исправлений безопасности, верно?
Этот вывод, к сожалению, неверен: оба выпуска содержат ровно одни и те же исправления безопасности. Чтобы понять этот ответ, сначала нужно разобраться в текущей схеме нумерации выпусков JDK Update. Промежуточные выпуски, в которых есть изменения помимо исправлений безопасности, имеют номера, кратные 20. Выпуски безопасности, основанные на предыдущем промежуточном выпуске, имеют нечётные номера, увеличенные на пять или, если нужно, чтобы номер обновления остался нечётным, на шесть. Чтобы понять, действительно ли промежуточный выпуск безопаснее более раннего, в конечном счёте приходится смотреть примечания к выпуску или исходный код.
Чем отличаются выпуски с названиями «JDK 7 Update 60», «1.7.0_60» и «JDK 7u60»?
Это просто разные названия одного и того же выпуска. Из-за этих различий трудно определять и проверять эквивалентные выпуски. Простого поэлементного сравнения последовательностей разобранных токенов недостаточно: нужен довольно сложный алгоритм. Использование строчной буквы «u» не является отраслевым стандартом и не нейтрально по отношению к языку.
Давно пора перейти на более простую и интуитивно понятную схему версий.
Описание
Номера версий
Номер версии, $VNUM, — это непустая последовательность элементов, разделённых точками (U+002E). Элемент — это либо ноль, либо беззнаковое целое число без ведущих нулей. Последний элемент номера версии не должен быть нулём. Формат:
[1-9][0-9]*((\.0)*\.[1-9][0-9]*)*
Последовательность может быть произвольной длины, но первым трём элементам присвоены определённые значения:
$MAJOR.$MINOR.$SECURITY
-
$MAJOR— номер основной версии. Увеличивается при основном выпуске, который содержит значительные новые возможности, описанные в новой редакции спецификации платформы Java SE, например JSR 337 для Java SE 8. В основном выпуске возможности могут быть удалены при условии предупреждения не менее чем за один основной выпуск, а несовместимые изменения могут вноситься, если это обосновано. Номер версии$MAJORу JDK 8 —8, номер версии$MAJORу JDK 9 —9. При увеличении$MAJORвсе последующие элементы удаляются. -
$MINOR— номер промежуточной версии. Увеличивается при промежуточном выпуске обновления, который может содержать совместимые исправления ошибок, изменения стандартных API, предписанные Maintenance Release соответствующей спецификации платформы, и возможности реализации за пределами этой спецификации, например новые API, специфичные для JDK, дополнительные поставщики служб, новые сборщики мусора и порты на новые аппаратные архитектуры. -
$SECURITY— уровень безопасности. Увеличивается при выпуске обновления безопасности, который содержит критические исправления, в том числе необходимые для повышения безопасности.$SECURITYне сбрасывается в ноль при увеличении$MINOR. Поэтому более высокое значение$SECURITYпри заданном значении$MAJORвсегда означает более безопасный выпуск, независимо от значения$MINOR.
Четвёртый и последующие элементы номера версии свободны для использования потребителями кодовой базы JDK ниже по цепочке. Такой потребитель может, например, использовать четвёртый элемент для обозначения выпусков-патчей, которые содержат небольшое число критических исправлений, не связанных с безопасностью, в дополнение к исправлениям безопасности из соответствующего выпуска безопасности.
Номер версии не содержит нулевых элементов в конце; т. е. $SECURITY опускается, если его значение равно нулю, а $MINOR опускается, если и $MINOR, и $SECURITY равны нулю.
Последовательность чисел в номере версии сравнивается с другой такой последовательностью численно, поэлементно; например, 9.9.1 меньше 9.10.3. Если одна последовательность короче другой, недостающие элементы более короткой последовательности считаются меньше соответствующих элементов более длинной; например, 9.1.2 меньше 9.1.2.1.
Строки версий
Строка версии, $VSTR, состоит из номера версии $VNUM, описанного выше, за которым могут следовать сведения о предварительном выпуске и сборке в одном из следующих форматов:
$VNUM(-$PRE)?\+$BUILD(-$OPT)?
$VNUM-$PRE(-$OPT)?
$VNUM(+-$OPT)?
где:
-
$PRE, соответствует([a-zA-Z0-9]+), — идентификатор предварительного выпуска. Обычноea— для выпуска Early Access (ранний доступ), который находится в активной разработке и может быть нестабилен, илиinternal— для внутренней сборки разработчика.При сравнении двух строк версий строка с идентификатором предварительного выпуска всегда меньше строки с равным
$VNUM, но без такого идентификатора. Идентификаторы предварительного выпуска сравниваются численно, если состоят только из цифр, и лексикографически в остальных случаях. Числовые идентификаторы считаются меньше нечисловых. -
$BUILD, соответствует(0|[1-9][0-9]*), — номер сборки, увеличивается для каждой продвинутой сборки.$BUILDсбрасывается в единицу при увеличении любой части$VNUM.При сравнении двух строк версий с равными компонентами
$VNUMи$PREстрока без компонента$BUILDвсегда меньше строки с компонентом$BUILD; в остальных случаях номера$BUILDсравниваются численно. -
$OPT, соответствует
([-a-zA-Z0-9\.]+), — дополнительные сведения о сборке, если нужны. В случае сборкиinternalздесь часто будут указаны дата и время сборки.При сравнении двух строк версий значение
$OPT, если оно есть, может учитываться или не учитываться в зависимости от выбранного способа сравнения.
Номер версии 10-ea соответствует $VNUM = "10" и $PRE = "ea". Номер версии 10+-ea соответствует $VNUM = "10" и $OPT = "ea".
В следующей таблице сравниваются возможные строки версий для JDK 9 в существующем и предлагаемом форматах:
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
Для справки: в этой таблице показаны строки версий в новом формате в том виде, в каком они гипотетически использовались бы для некоторых выпусков обновлений и выпусков безопасности JDK 7:
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
Удаление начального элемента 1 из номеров версий
Это предложение удаляет начальный элемент 1 из номеров версий JDK. То есть предлагается, чтобы первый выпуск JDK 9 имел номер версии 9.0.0, а не 1.9.0.0.
Спустя почти двадцать лет ясно, что второй элемент текущей схемы номеров версий — это де-факто номер версии $MAJOR JDK. Мы увеличиваем этот элемент, когда добавляем значительные новые возможности, а также когда вносим несовместимые изменения.
Мы могли бы начать считать начальный элемент текущей схемы номером версии $MAJOR, но тогда JDK 9 получил бы номер версии 2.0.0, хотя все уже называют его «JDK 9». Это никому бы не помогло.
Если сохранить начальный 1, номера версий JDK будут и дальше нарушать принципы Semantic Versioning, а разработчики, впервые знакомящиеся с Java, будут и дальше путаться в разнице между, например, 1.9 и 9.
Удаление начального 1 связано с некоторым риском. Сравнивать номера версий можно многими способами; одни будут работать правильно, другие нет.
-
Существующий код, который сравнивает номера версий, разбирая их элементы и сравнивая их численно, продолжит работать, поскольку девять больше единицы; т. е.
9.0.0будет считаться более поздней версией, чем1.8.0. -
Существующий код, который пропускает начальный элемент, если его значение равно
1, тоже продолжит работать, поскольку в новой схеме начальный элемент никогда не будет иметь такого значения. -
Однако существующий код, который предполагает, что начальный элемент имеет значение
1, и поэтому при сравнении номеров версий всегда переходит сразу ко второму элементу, будет работать неправильно; например, такой код будет считать, что9.0.1предшествует1.8.0.
Отдельные наблюдения говорят о том, что существующий код третьей категории встречается не очень часто, но мы будем рады данным, говорящим об обратном.
API
Будет определён простой Java API для разбора, проверки и сравнения строк версий (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();
}
}
Будет определён эквивалентный C API, скорее всего на основе изменённой структуры jvm_version_info.
Весь код в JDK, который анализирует и сравнивает строки версий JDK, будет переведён на эти API. Разработчикам, чьи библиотеки или приложения анализируют и сравнивают строки версий JDK, будет рекомендовано использовать эти API.
Системные свойства
Этот JEP изменяет значения, возвращаемые следующими системными свойствами. Общий синтаксис таков:
Name Syntax
------------------------------ --------------
java.version $VNUM(\-$PRE)?
java.runtime.version $VSTR
java.vm.version $VSTR
java.specification.version $VNUM
java.vm.specification.version $VNUM
Системное свойство java.class.version не затрагивается.
В следующей таблице показаны существующие и предлагаемые значения для разных типов выпусков:
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
Обратите внимание: весь код, который исторически распознавал . в любом из этих системных свойств при определении версии, нужно будет проверить и, возможно, изменить. Например, System.getProperty("java.version").indexof('.') для основных выпусков будет возвращать -1.
Лаунчер
В реализации лаунчера java в OpenJDK системные свойства используются при выводе сведений о версии, например java -version, java -fullversion и java -showversion.
Вывод лаунчера по-прежнему зависит от системных свойств следующим образом:
$ 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}\"
Подробности реализации можно найти в исходном коде.
Тег JavaDoc @since
Значение тега JavaDoc @since по-прежнему будет согласовано с системным свойством java.specification.version; следовательно, новые API JDK 9 будут обозначаться как @since 9.
Теги наборов изменений Mercurial
Теги Mercurial используются для обозначения наборов изменений, вошедших в продвижение сборки. Такие инструменты, как jcheck из Code Tools, который используется для проверки всех наборов изменений, отправляемых в леса репозиториев выпусков JDK, будут доработаны для поддержки тегов в новой схеме версий.
Общий синтаксис тегов Mercurial: jdk\-$VNUM\+$BUILD. В следующей таблице показаны предлагаемые значения для разных типов выпусков:
Release Type Proposed
---------------- -----------
Major (GA) jdk-9+100
Minor #1 (GA) jdk-9.1.2+27
Security #1 (GA) jdk-9.0.1+3
Некоторым инструментам может потребоваться поддержка как существующего, так и предлагаемого формата тегов.
Тестирование
Изменение синтаксиса и семантики строк версий потребует обширного тестирования всех компонентов. Существующие тесты, не зависящие от строки версии JDK, должны по-прежнему проходить.