Fixes the reflection allocator with Java 9, tested with Java 9 Early Access build 129 and OpenJDK 1.8.0 update 101

define_list_fix
Julien Gouesse 9 years ago
parent e89e0e7c12
commit f820bbfd94
  1. 61
      jme3-core/src/main/java/com/jme3/util/ReflectionAllocator.java

@ -40,7 +40,7 @@ import java.util.logging.Logger;
/** /**
* This class contains the reflection based way to remove DirectByteBuffers in * This class contains the reflection based way to remove DirectByteBuffers in
* java < 9, allocation is done via ByteBuffer.allocateDirect * java, allocation is done via ByteBuffer.allocateDirect
*/ */
public final class ReflectionAllocator implements BufferAllocator { public final class ReflectionAllocator implements BufferAllocator {
private static Method cleanerMethod = null; private static Method cleanerMethod = null;
@ -54,7 +54,7 @@ public final class ReflectionAllocator implements BufferAllocator {
cleanMethod = loadMethod("sun.misc.Cleaner", "clean"); cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer"); viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
if (viewedBufferMethod == null) { if (viewedBufferMethod == null) {
// They changed the name in Java 7 (???) // They changed the name in Java 7
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment"); viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
} }
@ -72,7 +72,7 @@ public final class ReflectionAllocator implements BufferAllocator {
private static Method loadMethod(String className, String methodName) { private static Method loadMethod(String className, String methodName) {
try { try {
Method method = Class.forName(className).getMethod(methodName); Method method = Class.forName(className).getMethod(methodName);
method.setAccessible(true); method.setAccessible(true);// according to the Java documentation, by default, a reflected object is not accessible
return method; return method;
} catch (NoSuchMethodException ex) { } catch (NoSuchMethodException ex) {
return null; // the method was not found return null; // the method was not found
@ -80,6 +80,12 @@ public final class ReflectionAllocator implements BufferAllocator {
return null; // setAccessible not allowed by security policy return null; // setAccessible not allowed by security policy
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
return null; // the direct buffer implementation was not found return null; // the direct buffer implementation was not found
} catch (Throwable t) {
if (t.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
return null;// the class is in an exported module
} else {
throw t;
}
} }
} }
@ -96,13 +102,52 @@ public final class ReflectionAllocator implements BufferAllocator {
if (freeMethod != null) { if (freeMethod != null) {
freeMethod.invoke(toBeDestroyed); freeMethod.invoke(toBeDestroyed);
} else { } else {
Object cleaner = cleanerMethod.invoke(toBeDestroyed); //TODO load the methods only once, store them into a cache (only for Java >= 9)
Method localCleanerMethod;
if (cleanerMethod == null) {
localCleanerMethod = loadMethod(toBeDestroyed.getClass().getName(), "cleaner");
} else {
localCleanerMethod = cleanerMethod;
}
if (localCleanerMethod == null) {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE,
"Buffer cannot be destroyed: {0}", toBeDestroyed);
} else {
Object cleaner = localCleanerMethod.invoke(toBeDestroyed);
if (cleaner != null) { if (cleaner != null) {
cleanMethod.invoke(cleaner); Method localCleanMethod;
if (cleanMethod == null) {
if (cleaner instanceof Runnable) {
// jdk.internal.ref.Cleaner implements Runnable in Java 9
localCleanMethod = loadMethod(Runnable.class.getName(), "run");
} else {
// sun.misc.Cleaner does not implement Runnable in Java < 9
localCleanMethod = loadMethod(cleaner.getClass().getName(), "clean");
}
} else { } else {
// Try the alternate approach of getting the viewed buffer localCleanMethod = cleanMethod;
}
if (localCleanMethod == null) {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE,
"Buffer cannot be destroyed: {0}", toBeDestroyed);
} else {
localCleanMethod.invoke(cleaner);
}
} else {
Method localViewedBufferMethod;
if (viewedBufferMethod == null) {
localViewedBufferMethod = loadMethod(toBeDestroyed.getClass().getName(), "viewedBuffer");
} else {
localViewedBufferMethod = viewedBufferMethod;
}
if (localViewedBufferMethod == null) {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE,
"Buffer cannot be destroyed: {0}", toBeDestroyed);
} else {
// Try the alternate approach of getting the viewed
// buffer
// first // first
Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed); Object viewedBuffer = localViewedBufferMethod.invoke(toBeDestroyed);
if (viewedBuffer != null) { if (viewedBuffer != null) {
destroyDirectBuffer((Buffer) viewedBuffer); destroyDirectBuffer((Buffer) viewedBuffer);
} else { } else {
@ -111,6 +156,8 @@ public final class ReflectionAllocator implements BufferAllocator {
} }
} }
} }
}
}
} catch (IllegalAccessException ex) { } catch (IllegalAccessException ex) {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
} catch (IllegalArgumentException ex) { } catch (IllegalArgumentException ex) {

Loading…
Cancel
Save