Make JDK version check more robust. The current logic could fail due to StringIndexOutOfBoundsException because of calling version.substring(0, -1). The system property "java.version" could be a single integer that does not contain dot. RELNOTES: None PiperOrigin-RevId: 202578981
diff --git a/src/main/java/com/google/devtools/build/lib/unsafe/BUILD b/src/main/java/com/google/devtools/build/lib/unsafe/BUILD index 7c2b208..84feca8 100644 --- a/src/main/java/com/google/devtools/build/lib/unsafe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/unsafe/BUILD
@@ -14,7 +14,10 @@ java_library( name = "string", - srcs = ["StringUnsafe.java"], + srcs = [ + "RuntimeVersion.java", + "StringUnsafe.java", + ], deps = [ ":unsafe-provider", "//third_party:guava",
diff --git a/src/main/java/com/google/devtools/build/lib/unsafe/RuntimeVersion.java b/src/main/java/com/google/devtools/build/lib/unsafe/RuntimeVersion.java new file mode 100644 index 0000000..8c2bb2a --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/unsafe/RuntimeVersion.java
@@ -0,0 +1,49 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.unsafe; + +import java.lang.reflect.Method; + +/** + * JDK version string utilities. + * + * <p>Code in this class is copied from Java Platform Team's JDK version string utility class, + * in order to avoid exporting an extra dependence from internal repository. + */ +final class RuntimeVersion { + + private static final int MAJOR = getMajorJdkVersion(); + + private static int getMajorJdkVersion() { + try { + Method versionMethod = Runtime.class.getMethod("version"); + Object version = versionMethod.invoke(null); + return (int) version.getClass().getMethod("major").invoke(version); + } catch (Exception e) { + // continue below + } + + int version = (int) Double.parseDouble(System.getProperty("java.class.version")); + if (49 <= version && version <= 52) { + return version - (49 - 5); + } + throw new IllegalStateException( + "Unknown Java version: " + System.getProperty("java.specification.version")); + } + + /** Returns true if the current runtime is JDK 9 or newer. */ + static boolean isAtLeast9() { + return MAJOR >= 9; + } +}
diff --git a/src/main/java/com/google/devtools/build/lib/unsafe/StringUnsafe.java b/src/main/java/com/google/devtools/build/lib/unsafe/StringUnsafe.java index 8701e86..eeaa542 100644 --- a/src/main/java/com/google/devtools/build/lib/unsafe/StringUnsafe.java +++ b/src/main/java/com/google/devtools/build/lib/unsafe/StringUnsafe.java
@@ -30,8 +30,6 @@ * <p>The <code>value</code> field contains the actual bytes. */ public class StringUnsafe { - private static final boolean CAN_USE = getVersion() > 1.8; - // Fields corresponding to the coder public static final byte LATIN1 = 0; public static final byte UTF16 = 1; @@ -43,14 +41,7 @@ private final long coderOffset; public static boolean canUse() { - return CAN_USE; - } - - private static double getVersion() { - String version = System.getProperty("java.version"); - int pos = version.indexOf('.'); - pos = version.indexOf('.', pos + 1); - return Double.parseDouble(version.substring(0, pos)); + return RuntimeVersion.isAtLeast9(); } @Nullable