From 90bc60547784877366a3294e6b945a5241b7099f Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 13 Feb 2017 07:48:41 +0100 Subject: [PATCH] Initialization of PlatformDependent0 fails on Java 9 Motivation: Initialization of PlatformDependent0 fails on Java 9 in static initializer when calling setAccessible(true). Modifications: Add RefelectionUtil which can be used to safely try if setAccessible(true) can be used or not and if not fail back to non reflection. Result: Fixed [#6345] --- .../util/internal/PlatformDependent0.java | 34 ++++++++++--- .../netty/util/internal/ReflectionUtil.java | 49 +++++++++++++++++++ .../io/netty/channel/nio/NioEventLoop.java | 20 ++++---- 3 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 common/src/main/java/io/netty/util/internal/ReflectionUtil.java diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java index cbfd8ed425..6abdb0035f 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java @@ -36,7 +36,7 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull; final class PlatformDependent0 { private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class); - static final Unsafe UNSAFE; + private static final Unsafe UNSAFE; private static final long ADDRESS_FIELD_OFFSET; private static final long BYTE_ARRAY_BASE_OFFSET; private static final Constructor DIRECT_BUFFER_CONSTRUCTOR; @@ -69,7 +69,10 @@ final class PlatformDependent0 { public Object run() { try { final Field field = Buffer.class.getDeclaredField("address"); - field.setAccessible(true); + Throwable cause = ReflectionUtil.trySetAccessible(field); + if (cause != null) { + return cause; + } // if direct really is a direct buffer, address will be non-zero if (field.getLong(direct) == 0) { return null; @@ -102,7 +105,10 @@ final class PlatformDependent0 { public Object run() { try { final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); + Throwable cause = ReflectionUtil.trySetAccessible(unsafeField); + if (cause != null) { + return cause; + } // the unsafe instance return unsafeField.get(null); } catch (NoSuchFieldException e) { @@ -179,7 +185,10 @@ final class PlatformDependent0 { try { final Constructor constructor = direct.getClass().getDeclaredConstructor(long.class, int.class); - constructor.setAccessible(true); + Throwable cause = ReflectionUtil.trySetAccessible(constructor); + if (cause != null) { + return cause; + } return constructor; } catch (NoSuchMethodException e) { return e; @@ -226,10 +235,21 @@ final class PlatformDependent0 { Class bitsClass = Class.forName("java.nio.Bits", false, PlatformDependent.getSystemClassLoader()); Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned"); - unalignedMethod.setAccessible(true); + Throwable cause = ReflectionUtil.trySetAccessible(unalignedMethod); + if (cause != null) { + return cause; + } return unalignedMethod.invoke(null); - } catch (Throwable cause) { - return cause; + } catch (NoSuchMethodException e) { + return e; + } catch (SecurityException e) { + return e; + } catch (IllegalAccessException e) { + return e; + } catch (ClassNotFoundException e) { + return e; + } catch (InvocationTargetException e) { + return e; } } }); diff --git a/common/src/main/java/io/netty/util/internal/ReflectionUtil.java b/common/src/main/java/io/netty/util/internal/ReflectionUtil.java new file mode 100644 index 0000000000..ef39b35215 --- /dev/null +++ b/common/src/main/java/io/netty/util/internal/ReflectionUtil.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 The Netty Project + * + * The Netty Project licenses this file to you 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 io.netty.util.internal; + +import java.lang.reflect.AccessibleObject; + +public final class ReflectionUtil { + + private ReflectionUtil() { } + + /** + * Try to call {@link AccessibleObject#setAccessible(boolean)} but will catch any {@link SecurityException} and + * {@link java.lang.reflect.InaccessibleObjectException} and return it. + * The caller must check if it returns {@code null} and if not handle the returned exception. + */ + public static Throwable trySetAccessible(AccessibleObject object) { + try { + object.setAccessible(true); + return null; + } catch (SecurityException e) { + return e; + } catch (RuntimeException e) { + return handleInaccessibleObjectException(e); + } + } + + private static RuntimeException handleInaccessibleObjectException(RuntimeException e) { + // JDK 9 can throw an inaccessible object exception here; since Netty compiles + // against JDK 7 and this exception was only added in JDK 9, we have to weakly + // check the type + if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) { + return e; + } + throw e; + } +} diff --git a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java index ac25e42590..76f3fc79d6 100644 --- a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java +++ b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java @@ -24,6 +24,7 @@ import io.netty.channel.SingleThreadEventLoop; import io.netty.util.IntSupplier; import io.netty.util.concurrent.RejectedExecutionHandler; import io.netty.util.internal.PlatformDependent; +import io.netty.util.internal.ReflectionUtil; import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -195,8 +196,14 @@ public final class NioEventLoop extends SingleThreadEventLoop { Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); - selectedKeysField.setAccessible(true); - publicSelectedKeysField.setAccessible(true); + Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField); + if (cause != null) { + return cause; + } + cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField); + if (cause != null) { + return cause; + } selectedKeysField.set(selector, selectedKeySet); publicSelectedKeysField.set(selector, selectedKeySet); @@ -205,15 +212,6 @@ public final class NioEventLoop extends SingleThreadEventLoop { return e; } catch (IllegalAccessException e) { return e; - } catch (RuntimeException e) { - // JDK 9 can throw an inaccessible object exception here; since Netty compiles - // against JDK 7 and this exception was only added in JDK 9, we have to weakly - // check the type - if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) { - return e; - } else { - throw e; - } } } });