mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8306678: Replace use of os.version with an internal Version record
Reviewed-by: mchung
This commit is contained in:
parent
f00a748bc5
commit
6acf032db8
6 changed files with 275 additions and 17 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -27,21 +27,15 @@ package jdk.internal.loader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import sun.security.action.GetPropertyAction;
|
|
||||||
|
import jdk.internal.util.OperatingSystem;
|
||||||
|
import jdk.internal.util.Version;
|
||||||
|
|
||||||
class ClassLoaderHelper {
|
class ClassLoaderHelper {
|
||||||
private static final boolean hasDynamicLoaderCache;
|
|
||||||
static {
|
|
||||||
String osVersion = GetPropertyAction.privilegedGetProperty("os.version");
|
|
||||||
// dynamic linker cache support on os.version >= 11.x
|
|
||||||
int major = 11;
|
|
||||||
int i = osVersion.indexOf('.');
|
|
||||||
try {
|
|
||||||
major = Integer.parseInt(i < 0 ? osVersion : osVersion.substring(0, i));
|
|
||||||
} catch (NumberFormatException e) {}
|
|
||||||
// SDK 10.15 and earlier always reports 10.16 instead of 11.x.x
|
// SDK 10.15 and earlier always reports 10.16 instead of 11.x.x
|
||||||
hasDynamicLoaderCache = major >= 11 || osVersion.equals("10.16");
|
private static final boolean hasDynamicLoaderCache = OperatingSystem.version()
|
||||||
}
|
.compareTo(new Version(10, 16)) >= 0;
|
||||||
|
|
||||||
private ClassLoaderHelper() {}
|
private ClassLoaderHelper() {}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,6 @@ package jdk.internal.util;
|
||||||
import jdk.internal.util.PlatformProps;
|
import jdk.internal.util.PlatformProps;
|
||||||
import jdk.internal.vm.annotation.ForceInline;
|
import jdk.internal.vm.annotation.ForceInline;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of operating system types and testing for the current OS.
|
* Enumeration of operating system types and testing for the current OS.
|
||||||
* The enumeration can be used to dispatch to OS specific code or values.
|
* The enumeration can be used to dispatch to OS specific code or values.
|
||||||
|
@ -129,7 +127,34 @@ public enum OperatingSystem {
|
||||||
* Names not recognized throw ExceptionInInitializerError with IllegalArgumentException.
|
* Names not recognized throw ExceptionInInitializerError with IllegalArgumentException.
|
||||||
*/
|
*/
|
||||||
private static OperatingSystem initOS(String osName) {
|
private static OperatingSystem initOS(String osName) {
|
||||||
return OperatingSystem.valueOf(osName.toUpperCase(Locale.ROOT));
|
// Too early to use Locale conversions, manually do uppercase
|
||||||
|
StringBuilder sb = new StringBuilder(osName);
|
||||||
|
for (int i = 0; i < sb.length(); i++) {
|
||||||
|
char ch = sb.charAt(i);
|
||||||
|
if (ch >= 'a' && ch <= 'z') {
|
||||||
|
sb.setCharAt(i, (char)(ch - ('a' - 'A'))); // Map lower case down to uppercase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osName = sb.toString();
|
||||||
|
return OperatingSystem.valueOf(osName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the operating system version with major, minor, micro}
|
||||||
|
*/
|
||||||
|
public static Version version() {
|
||||||
|
return CURRENT_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and save the current version
|
||||||
|
private static final Version CURRENT_VERSION = initVersion();
|
||||||
|
|
||||||
|
private static Version initVersion() {
|
||||||
|
final String osVer = StaticProperty.osVersion();
|
||||||
|
try {
|
||||||
|
return Version.parse(osVer);
|
||||||
|
} catch (IllegalArgumentException iae) {
|
||||||
|
throw new InternalError("os.version malformed: " + osVer, iae);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ public final class StaticProperty {
|
||||||
private static final String JAVA_LOCALE_USE_OLD_ISO_CODES;
|
private static final String JAVA_LOCALE_USE_OLD_ISO_CODES;
|
||||||
private static final String OS_NAME;
|
private static final String OS_NAME;
|
||||||
private static final String OS_ARCH;
|
private static final String OS_ARCH;
|
||||||
|
private static final String OS_VERSION;
|
||||||
|
|
||||||
private StaticProperty() {}
|
private StaticProperty() {}
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ public final class StaticProperty {
|
||||||
JAVA_LOCALE_USE_OLD_ISO_CODES = getProperty(props, "java.locale.useOldISOCodes", "");
|
JAVA_LOCALE_USE_OLD_ISO_CODES = getProperty(props, "java.locale.useOldISOCodes", "");
|
||||||
OS_NAME = getProperty(props, "os.name");
|
OS_NAME = getProperty(props, "os.name");
|
||||||
OS_ARCH = getProperty(props, "os.arch");
|
OS_ARCH = getProperty(props, "os.arch");
|
||||||
|
OS_VERSION = getProperty(props, "os.version");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getProperty(Properties props, String key) {
|
private static String getProperty(Properties props, String key) {
|
||||||
|
@ -265,4 +267,13 @@ public final class StaticProperty {
|
||||||
public static String osArch() {
|
public static String osArch() {
|
||||||
return OS_ARCH;
|
return OS_ARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the {@code os.version} system property}
|
||||||
|
* <strong>{@link SecurityManager#checkPropertyAccess} is NOT checked
|
||||||
|
* in this method. This property is not considered security sensitive.</strong>
|
||||||
|
*/
|
||||||
|
public static String osVersion() {
|
||||||
|
return OS_VERSION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
114
src/java.base/share/classes/jdk/internal/util/Version.java
Normal file
114
src/java.base/share/classes/jdk/internal/util/Version.java
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, 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.
|
||||||
|
*/
|
||||||
|
package jdk.internal.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A software Version with major, minor, and micro components.
|
||||||
|
* @param major major version
|
||||||
|
* @param minor minor version
|
||||||
|
* @param micro micro version
|
||||||
|
*/
|
||||||
|
public record Version(int major, int minor, int micro) implements Comparable<Version> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return a Version for major, minor versions}
|
||||||
|
*
|
||||||
|
* @param major major version
|
||||||
|
* @param minor minor version
|
||||||
|
*/
|
||||||
|
public Version(int major, int minor) {
|
||||||
|
this(major, minor, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return Compare this version with another version}
|
||||||
|
*
|
||||||
|
* @param other the object to be compared
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int compareTo(Version other) {
|
||||||
|
int result = Integer.compare(major, other.major);
|
||||||
|
if (result == 0) {
|
||||||
|
result = Integer.compare(minor, other.minor);
|
||||||
|
if (result == 0) {
|
||||||
|
return Integer.compare(micro, other.micro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (micro == 0)
|
||||||
|
? major + "." + minor
|
||||||
|
: major + "." + minor + "." + micro;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return A Version parsed from a version string split on "." characters}
|
||||||
|
* Only major, minor, and micro version numbers are parsed, finer detail is ignored.
|
||||||
|
* Missing values for minor and micro are replaced with zero.
|
||||||
|
* The string must start with a number, if there is a '.' it must be followed by a number.
|
||||||
|
* <p>
|
||||||
|
* Parsed by hand because it is called before RegEx can be initialized safely.
|
||||||
|
*
|
||||||
|
* @param str a version string
|
||||||
|
* @throws IllegalArgumentException if the string does not start with digits
|
||||||
|
* or digits do not follow '.'
|
||||||
|
*/
|
||||||
|
public static Version parse(String str) throws IllegalArgumentException {
|
||||||
|
int len = str.length();
|
||||||
|
int majorStart = 0;
|
||||||
|
int majorEnd = skipDigits(str, majorStart);
|
||||||
|
int major = Integer.parseInt(str.substring(majorStart, majorEnd));
|
||||||
|
|
||||||
|
int minor = 0, micro = 0;
|
||||||
|
if (majorEnd < len && str.charAt(majorEnd) == '.') {
|
||||||
|
int minorStart = majorEnd + 1;
|
||||||
|
int minorEnd = skipDigits(str, minorStart);
|
||||||
|
minor = Integer.parseInt(str.substring(minorStart, minorEnd));
|
||||||
|
|
||||||
|
if (minorEnd < len && str.charAt(minorEnd) == '.') {
|
||||||
|
int microStart = minorEnd + 1;
|
||||||
|
int microEnd = skipDigits(str, microStart);
|
||||||
|
micro = Integer.parseInt(str.substring(microStart, microEnd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Version(major, minor, micro);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return The index of the first non-digit from start}
|
||||||
|
* @throws IllegalArgumentException if there are no digits
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static int skipDigits(String s, int start) {
|
||||||
|
int index = start;
|
||||||
|
while (index < s.length() && Character.isDigit(s.charAt(index))) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (index == start)
|
||||||
|
throw new IllegalArgumentException("malformed version, missing digits: " + s);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,11 +32,14 @@ import static jdk.internal.util.OperatingSystem.LINUX;
|
||||||
import static jdk.internal.util.OperatingSystem.MACOS;
|
import static jdk.internal.util.OperatingSystem.MACOS;
|
||||||
import static jdk.internal.util.OperatingSystem.WINDOWS;
|
import static jdk.internal.util.OperatingSystem.WINDOWS;
|
||||||
|
|
||||||
|
import jdk.internal.util.StaticProperty;
|
||||||
|
import jdk.internal.util.Version;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,4 +86,12 @@ public class OSTest {
|
||||||
assertEquals(os == current, isXXX,
|
assertEquals(os == current, isXXX,
|
||||||
"Mismatch " + os + " == " + current + " vs is" + os);
|
"Mismatch " + os + " == " + current + " vs is" + os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkOsVersion() {
|
||||||
|
Version ver = OperatingSystem.version();
|
||||||
|
String osVersion = StaticProperty.osVersion();
|
||||||
|
System.err.printf("os.version: %s, version().toString(): %s%n", osVersion, ver);
|
||||||
|
assertTrue(osVersion.startsWith(ver.toString()), "version().toString() is not prefix of vs os.version property");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
103
test/jdk/jdk/internal/util/VersionTest.java
Normal file
103
test/jdk/jdk/internal/util/VersionTest.java
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, 2023, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import jdk.internal.util.Version;
|
||||||
|
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @summary test jdk.internal.util.Version
|
||||||
|
* @modules java.base/jdk.internal.util
|
||||||
|
* @run junit VersionTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class VersionTest {
|
||||||
|
|
||||||
|
private static Stream<Arguments> versionParams() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("1", new Version(1, 0)),
|
||||||
|
Arguments.of("1.2", new Version(1, 2)),
|
||||||
|
Arguments.of("1.2", new Version(1, 2, 0)),
|
||||||
|
Arguments.of("1.2.3", new Version(1, 2, 3)),
|
||||||
|
Arguments.of("1-abc", new Version(1, 0, 0)), // Ignore extra
|
||||||
|
Arguments.of("1.2-abc", new Version(1, 2, 0)), // Ignore extra
|
||||||
|
Arguments.of("1.2.3.4", new Version(1, 2, 3)), // Ignore extra
|
||||||
|
Arguments.of("1.2.3-abc", new Version(1, 2, 3)) // Ignore extra
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("versionParams")
|
||||||
|
public void checkParse(String verName, Version expected) {
|
||||||
|
Version actual = Version.parse(verName);
|
||||||
|
assertEquals(actual, expected, "Parsed version mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<String> illegalVersionParams() {
|
||||||
|
return Stream.of(
|
||||||
|
"1.", "1.2.", "1.-abc", "1.2.-abc", // dot without digits
|
||||||
|
"", // empty
|
||||||
|
"xaaa", "abc.xyz" // no initial digit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest()
|
||||||
|
@MethodSource("illegalVersionParams")
|
||||||
|
public void checkIllegalParse(String verName) {
|
||||||
|
Throwable th = assertThrows(IllegalArgumentException.class, () -> Version.parse(verName));
|
||||||
|
String expectedMsg = "malformed version, missing digits: " + verName;
|
||||||
|
assertEquals(th.getMessage(), expectedMsg, "message mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<Arguments> versionCompare() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(new Version(2, 1), new Version(2, 1), 0),
|
||||||
|
Arguments.of(new Version(2, 1), new Version(2, 0), +1),
|
||||||
|
Arguments.of(new Version(2, 0), new Version(2, 1), -1),
|
||||||
|
Arguments.of(new Version(3, 3, 1), new Version(3, 3, 1), 0),
|
||||||
|
Arguments.of(new Version(3, 3, 1), new Version(3, 3, 0), +1),
|
||||||
|
Arguments.of(new Version(3, 3, 0), new Version(3, 3, 1), -1),
|
||||||
|
Arguments.of(new Version(2, 0), new Version(3, 0), -1),
|
||||||
|
Arguments.of(new Version(3, 0), new Version(2, 0), +1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest()
|
||||||
|
@MethodSource("versionCompare")
|
||||||
|
public void checkVersionCompare(Version v1, Version v2, int expected) {
|
||||||
|
int result1 = v1.compareTo(v2);
|
||||||
|
assertEquals(result1, expected, "v1 vs v2");
|
||||||
|
int result2 = v2.compareTo(v1);
|
||||||
|
assertEquals(result1, -result2, "compare not reflexive");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue