Acquire Java version simply
Motivation: The Java version is used for platform dependent logic. Yet, the logic for acquiring the Java version requires special permissions (the runtime permission "getClassLoader") that some downstream projects will never grant. As such, these projects are doomed to have Netty act is their Java major version is six. While there are ways to maintain the same logic without requiring these special permissions, the logic is needlessly complicated because it relies on loading classes that exist in version n but not version n - 1. This complexity can be removed. As a bonanza, the dangerous permission is no longer required. Modifications: Rather than attempting to load classes that exist in version n but not in version n - 1, we can just parse the Java specification version. This only requires a begign property (property permission "java.specification.version") and is simple. Result: Acquisition of the Java version is safe and simple.
This commit is contained in:
parent
3d7ae97359
commit
e00b797936
@ -38,12 +38,13 @@ import java.net.InetSocketAddress;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
@ -1018,51 +1019,48 @@ public final class PlatformDependent {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("LoopStatementThatDoesntLoop")
|
|
||||||
private static int javaVersion0() {
|
private static int javaVersion0() {
|
||||||
int javaVersion;
|
final int majorVersion;
|
||||||
|
|
||||||
// Not really a loop
|
|
||||||
for (;;) {
|
|
||||||
// Android
|
|
||||||
if (isAndroid()) {
|
if (isAndroid()) {
|
||||||
javaVersion = 6;
|
majorVersion = 6;
|
||||||
break;
|
} else {
|
||||||
|
majorVersion = majorVersionFromJavaSpecificationVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("Java version: {}", majorVersion);
|
||||||
|
|
||||||
|
return majorVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int majorVersionFromJavaSpecificationVersion() {
|
||||||
try {
|
try {
|
||||||
Method getVersion = java.lang.Runtime.class.getMethod("version");
|
final String javaSpecVersion = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||||
Object version = getVersion.invoke(null);
|
@Override
|
||||||
javaVersion = (Integer) version.getClass().getMethod("major").invoke(version);
|
public String run() {
|
||||||
break;
|
return System.getProperty("java.specification.version");
|
||||||
} catch (Throwable ignored) {
|
}
|
||||||
// Ignore
|
});
|
||||||
|
return majorVersion(javaSpecVersion);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
logger.debug("security exception while reading java.specification.version", e);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
static int majorVersion(final String javaSpecVersion) {
|
||||||
Class.forName("java.time.Clock", false, getClassLoader(Object.class));
|
final String[] components = javaSpecVersion.split("\\.");
|
||||||
javaVersion = 8;
|
final int[] version = new int[components.length];
|
||||||
break;
|
for (int i = 0; i < components.length; i++) {
|
||||||
} catch (Throwable ignored) {
|
version[i] = Integer.parseInt(components[i]);
|
||||||
// Ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (version[0] == 1) {
|
||||||
Class.forName("java.util.concurrent.LinkedTransferQueue", false, getClassLoader(BlockingQueue.class));
|
assert version[1] >= 6;
|
||||||
javaVersion = 7;
|
return version[1];
|
||||||
break;
|
} else {
|
||||||
} catch (Throwable ignored) {
|
return version[0];
|
||||||
// Ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
javaVersion = 6;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Java version: {}", javaVersion);
|
|
||||||
}
|
|
||||||
return javaVersion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasUnsafe0() {
|
private static boolean hasUnsafe0() {
|
||||||
|
@ -17,6 +17,7 @@ package io.netty.util.internal;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.Permission;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static io.netty.util.internal.PlatformDependent.hashCodeAscii;
|
import static io.netty.util.internal.PlatformDependent.hashCodeAscii;
|
||||||
@ -129,4 +130,40 @@ public class PlatformDependentTest {
|
|||||||
hashCodeAscii(string));
|
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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user