Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,27 @@
package org.apache.dubbo.common.timer;

import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.common.utils.SystemPropertyConfigUtils;

import java.lang.ref.WeakReference;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import sun.misc.Unsafe;

import static org.awaitility.Awaitility.await;

Expand Down Expand Up @@ -171,4 +183,181 @@ void stopTaskTest() throws InterruptedException {
// this will throw an exception
Assertions.assertThrows(RuntimeException.class, () -> timer.newTimeout(new EmptyTask(), 5, TimeUnit.SECONDS));
}

@Test
@DisplayName("Check whether sun.misc.Unsafe (used by latest Netty HashedWheelTimer) could be compiled or not.")
void unsafeTest() {
// attempt to access field Unsafe#theUnsafe
final Object maybeUnsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
// We always want to try using Unsafe as the access still works on java9 as well and
// we need it for out native-transports and many optimizations.
Throwable cause = ReflectionUtil.trySetAccessible(unsafeField, false);
if (cause != null) {
return cause;
}
// the unsafe instance
return unsafeField.get(null);
} catch (NoSuchFieldException | IllegalAccessException | SecurityException e) {
return e;
} catch (NoClassDefFoundError e) {
// Also catch NoClassDefFoundError in case someone uses for example OSGI and it made
// Unsafe unloadable.
return e;
}
}
});

Assertions.assertInstanceOf(Unsafe.class, maybeUnsafe);
}

private static 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, boolean checkAccessible) {
if (checkAccessible && !explicitTryReflectionSetAccessible0()) {
return new UnsupportedOperationException("Reflective setAccessible(true) disabled");
}
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;
}

private static Class<?> fail(Class<?> type, String typeParamName) {
throw new IllegalStateException(
"cannot determine the type of the type parameter '" + typeParamName + "': " + type);
}

/**
* Resolve a type parameter of a class that is a subclass of the given parametrized superclass.
*
* @param object The object to resolve the type parameter for
* @param parametrizedSuperclass The parametrized superclass
* @param typeParamName The name of the type parameter to resolve
* @return The resolved type parameter
* @throws IllegalStateException if the type parameter could not be resolved
*/
public static Class<?> resolveTypeParameter(
final Object object, Class<?> parametrizedSuperclass, String typeParamName) {
final Class<?> thisClass = object.getClass();
Class<?> currentClass = thisClass;
for (; ; ) {
if (currentClass.getSuperclass() == parametrizedSuperclass) {
int typeParamIndex = -1;
TypeVariable<?>[] typeParams = currentClass.getSuperclass().getTypeParameters();
for (int i = 0; i < typeParams.length; i++) {
if (typeParamName.equals(typeParams[i].getName())) {
typeParamIndex = i;
break;
}
}

if (typeParamIndex < 0) {
throw new IllegalStateException(
"unknown type parameter '" + typeParamName + "': " + parametrizedSuperclass);
}

Type genericSuperType = currentClass.getGenericSuperclass();
if (!(genericSuperType instanceof ParameterizedType)) {
return Object.class;
}

Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments();

Type actualTypeParam = actualTypeParams[typeParamIndex];
if (actualTypeParam instanceof ParameterizedType) {
actualTypeParam = ((ParameterizedType) actualTypeParam).getRawType();
}
if (actualTypeParam instanceof Class) {
return (Class<?>) actualTypeParam;
}
if (actualTypeParam instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) actualTypeParam).getGenericComponentType();
if (componentType instanceof ParameterizedType) {
componentType = ((ParameterizedType) componentType).getRawType();
}
if (componentType instanceof Class) {
return Array.newInstance((Class<?>) componentType, 0)
.getClass();
}
}
if (actualTypeParam instanceof TypeVariable) {
// Resolved type parameter points to another type parameter.
TypeVariable<?> v = (TypeVariable<?>) actualTypeParam;
if (!(v.getGenericDeclaration() instanceof Class)) {
return Object.class;
}

currentClass = thisClass;
parametrizedSuperclass = (Class<?>) v.getGenericDeclaration();
typeParamName = v.getName();
if (parametrizedSuperclass.isAssignableFrom(thisClass)) {
continue;
}
return Object.class;
}

return fail(thisClass, typeParamName);
}
currentClass = currentClass.getSuperclass();
if (currentClass == null) {
return fail(thisClass, typeParamName);
}
}
}

private static boolean explicitTryReflectionSetAccessible0() {
// we disable reflective access
return Boolean.parseBoolean(SystemPropertyConfigUtils.getSystemProperty(
"io.netty.tryReflectionSetAccessible",
String.valueOf(javaVersion() < 9 || RUNNING_IN_NATIVE_IMAGE)));
}

private static final boolean RUNNING_IN_NATIVE_IMAGE =
SystemPropertyConfigUtils.getSystemProperty("org.graalvm.nativeimage.imagecode") != null;

private static int javaVersion() {
return majorVersion(SystemPropertyConfigUtils.getSystemProperty("java.specification.version", "1.6"));
}

private 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];
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package org.apache.dubbo.remoting.buffer;

import java.nio.Buffer;
import java.nio.ByteBuffer;

import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -75,7 +76,8 @@ void testWrappedBuffer() {
channelBuffer = ChannelBuffers.wrappedBuffer(byteBuffer);
Assertions.assertTrue(channelBuffer instanceof ByteBufferBackedChannelBuffer);

byteBuffer.position(byteBuffer.limit());
// be compatible with jdk8 by casting byteBuffer's type to its parent class - `java.nio.Buffer`.
((Buffer) byteBuffer).position(byteBuffer.limit());
channelBuffer = ChannelBuffers.wrappedBuffer(byteBuffer);
Assertions.assertEquals(channelBuffer, EMPTY_BUFFER);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.CollectionUtils;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
Expand Down Expand Up @@ -67,7 +68,8 @@ public static int readRawVarint32(ByteBuffer byteBuffer) {
val = val << 7;
val = val | (byteBuffer.get(index) & 0x7F);
}
byteBuffer.position(currentPosition + varIntLength);
// be compatible with jdk8 by casting byteBuffer's type to its parent class - `java.nio.Buffer`.
((Buffer) byteBuffer).position(currentPosition + varIntLength);
return val;
}

Expand Down
17 changes: 0 additions & 17 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -811,23 +811,6 @@
</build>
</profile>

<profile>
<id>jdk9-compile</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<release>8</release>
</configuration>
</plugin>
</plugins>
</build>
</profile>

<profile>
<id>jdk9-jdk11-spotless</id>
<activation>
Expand Down
Loading