diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index fe21f2d0a7..e8c823ea67 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -38,12 +38,13 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Deque; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Queue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentMap; @@ -1018,51 +1019,48 @@ public final class PlatformDependent { return false; } - @SuppressWarnings("LoopStatementThatDoesntLoop") private static int javaVersion0() { - int javaVersion; + final int majorVersion; - // Not really a loop - for (;;) { - // Android - if (isAndroid()) { - javaVersion = 6; - break; - } - - try { - Method getVersion = java.lang.Runtime.class.getMethod("version"); - Object version = getVersion.invoke(null); - javaVersion = (Integer) version.getClass().getMethod("major").invoke(version); - break; - } catch (Throwable ignored) { - // Ignore - } - - try { - Class.forName("java.time.Clock", false, getClassLoader(Object.class)); - javaVersion = 8; - break; - } catch (Throwable ignored) { - // Ignore - } - - try { - Class.forName("java.util.concurrent.LinkedTransferQueue", false, getClassLoader(BlockingQueue.class)); - javaVersion = 7; - break; - } catch (Throwable ignored) { - // Ignore - } - - javaVersion = 6; - break; + if (isAndroid()) { + majorVersion = 6; + } else { + majorVersion = majorVersionFromJavaSpecificationVersion(); } - if (logger.isDebugEnabled()) { - logger.debug("Java version: {}", javaVersion); + logger.debug("Java version: {}", majorVersion); + + return majorVersion; + } + + static int majorVersionFromJavaSpecificationVersion() { + try { + final String javaSpecVersion = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public String run() { + return System.getProperty("java.specification.version"); + } + }); + return majorVersion(javaSpecVersion); + } catch (SecurityException e) { + logger.debug("security exception while reading java.specification.version", e); + return 6; + } + } + + static int majorVersion(final String javaSpecVersion) { + final String[] components = javaSpecVersion.split("\\."); + final int[] version = new int[components.length]; + for (int i = 0; i < components.length; i++) { + version[i] = Integer.parseInt(components[i]); + } + + if (version[0] == 1) { + assert version[1] >= 6; + return version[1]; + } else { + return version[0]; } - return javaVersion; } private static boolean hasUnsafe0() { diff --git a/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java b/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java index 0c38f85a56..2999b66b04 100644 --- a/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java +++ b/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java @@ -17,6 +17,7 @@ package io.netty.util.internal; import org.junit.Test; +import java.security.Permission; import java.util.Random; import static io.netty.util.internal.PlatformDependent.hashCodeAscii; @@ -129,4 +130,40 @@ public class PlatformDependentTest { hashCodeAscii(string)); } } + + @Test + public void testMajorVersionFromJavaSpecificationVersion() { + final SecurityManager current = System.getSecurityManager(); + + try { + System.setSecurityManager(new SecurityManager() { + @Override + public void checkPropertyAccess(String key) { + if (key.equals("java.specification.version")) { + // deny + throw new SecurityException(key); + } + } + + // so we can restore the security manager + @Override + public void checkPermission(Permission perm) { + } + }); + + assertEquals(6, PlatformDependent.majorVersionFromJavaSpecificationVersion()); + } finally { + System.setSecurityManager(current); + } + } + + @Test + public void testMajorVersion() { + assertEquals(6, PlatformDependent.majorVersion("1.6")); + assertEquals(7, PlatformDependent.majorVersion("1.7")); + assertEquals(8, PlatformDependent.majorVersion("1.8")); + assertEquals(8, PlatformDependent.majorVersion("8")); + assertEquals(9, PlatformDependent.majorVersion("1.9")); // early version of JDK 9 before Project Verona + assertEquals(9, PlatformDependent.majorVersion("9")); + } }