You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/12/29 14:13:11 UTC
[groovy] 18/28: GROOVY-8843: Fix illegal reflective access within
o.c.g.vmplugin.v7.Java7 (closes #811)
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch refine-groovydoc
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit f40f76af134b6d5fd2d466d410ac48ad907e3b15
Author: Paul King <pa...@asert.com.au>
AuthorDate: Mon Oct 15 18:12:45 2018 +1000
GROOVY-8843: Fix illegal reflective access within o.c.g.vmplugin.v7.Java7 (closes #811)
---
build.gradle | 6 +-
.../org/codehaus/groovy/vmplugin/v7/Java7.java | 67 +++++++++++-----------
.../org/codehaus/groovy/vmplugin/v9/Java9.java | 66 ++++++++++++++++++++-
3 files changed, 103 insertions(+), 36 deletions(-)
diff --git a/build.gradle b/build.gradle
index b36eb55..36db7ba 100644
--- a/build.gradle
+++ b/build.gradle
@@ -414,11 +414,11 @@ task checkCompatibility {
}
}
-if (!JavaVersion.current().java8Compatible) {
+if (!JavaVersion.current().java9Compatible) {
logger.lifecycle '''
**************************************** WARNING ********************************************
- ****** You are running the build with an older JDK. NEVER try to release with 1.7. ******
- ****** You must use a JDK 1.8+ in order to compile all features of the language. ******
+ ****** You are running the build with an older JDK. NEVER try to release with 1.8. ******
+ ****** You must use a JDK 1.9+ in order to compile all features of the language. ******
*********************************************************************************************
'''
}
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java b/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java
index 11a2091..8694d38 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v7/Java7.java
@@ -29,40 +29,44 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
/**
- * Java 7 based functions. Currently just a stub but you can
- * add your own methods to your own version and place it on the classpath
- * ahead of this one.
+ * Java 7 based functions.
*
- * @author Jochen Theodorou
+ * For crude customization, you can add your own methods to your own version and place it on the classpath ahead of this one.
*/
public class Java7 extends Java6 {
- private static final Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
- static {
- Constructor<MethodHandles.Lookup> con = null;
- try {
- con = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
- } catch (NoSuchMethodException e) {
- throw new GroovyBugError(e);
- }
- try {
- if (!con.isAccessible()) {
- final Constructor tmp = con;
- AccessController.doPrivileged(new PrivilegedAction() {
- @Override
- public Object run() {
- tmp.setAccessible(true);
- return null;
- }
- });
+ private static class LookupHolder {
+ private static final Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
+ static {
+ Constructor<MethodHandles.Lookup> con = null;
+ try {
+ con = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
+ } catch (NoSuchMethodException e) {
+ throw new GroovyBugError(e);
}
- } catch (SecurityException se) {
- con = null;
- } catch (RuntimeException re) {
- // test for JDK9 JIGSAW
- if (!"java.lang.reflect.InaccessibleObjectException".equals(re.getClass().getName())) throw re;
- con = null;
+ try {
+ if (!con.isAccessible()) {
+ final Constructor tmp = con;
+ AccessController.doPrivileged(new PrivilegedAction() {
+ @Override
+ public Object run() {
+ tmp.setAccessible(true);
+ return null;
+ }
+ });
+ }
+ } catch (SecurityException se) {
+ con = null;
+ } catch (RuntimeException re) {
+ // test for JDK9 JIGSAW
+ if (!"java.lang.reflect.InaccessibleObjectException".equals(re.getClass().getName())) throw re;
+ con = null;
+ }
+ LOOKUP_Constructor = con;
}
- LOOKUP_Constructor = con;
+ }
+
+ private static Constructor<MethodHandles.Lookup> getLookupConstructor() {
+ return LookupHolder.LOOKUP_Constructor;
}
@Override
@@ -77,7 +81,7 @@ public class Java7 extends Java6 {
@Override
public Object getInvokeSpecialHandle(final Method method, final Object receiver) {
- if (LOOKUP_Constructor==null) {
+ if (getLookupConstructor() == null) {
return super.getInvokeSpecialHandle(method, receiver);
}
if (!method.isAccessible()) {
@@ -91,8 +95,7 @@ public class Java7 extends Java6 {
}
Class declaringClass = method.getDeclaringClass();
try {
- return LOOKUP_Constructor.
- newInstance(declaringClass, -1).
+ return getLookupConstructor().newInstance(declaringClass, -1).
unreflectSpecial(method, declaringClass).
bindTo(receiver);
} catch (ReflectiveOperationException e) {
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
index 7468581..290a654 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
@@ -18,14 +18,78 @@
*/
package org.codehaus.groovy.vmplugin.v9;
+import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.vmplugin.v8.Java8;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
/**
- * Java 9 based functions will be added here if needed.
+ * Additional Java 9 based functions will be added here as needed.
*/
public class Java9 extends Java8 {
+
+ private static class LookupHolder {
+ private static final Method PRIVATE_LOOKUP;
+ private static final Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
+ static {
+ Constructor<MethodHandles.Lookup> lookup = null;
+ Method privateLookup = null;
+ try { // java 9
+ privateLookup = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
+ } catch (final NoSuchMethodException | RuntimeException e) { // java 8 or fallback if anything else goes wrong
+ try {
+ lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, Integer.TYPE);
+ if (!lookup.isAccessible()) {
+ lookup.setAccessible(true);
+ }
+ } catch (final NoSuchMethodException ex) {
+ throw new IllegalStateException("Incompatible JVM", e);
+ }
+ }
+ PRIVATE_LOOKUP = privateLookup;
+ LOOKUP_Constructor = lookup;
+ }
+ }
+
+ private static Constructor<MethodHandles.Lookup> getLookupConstructor() {
+ return LookupHolder.LOOKUP_Constructor;
+ }
+
+ private static Method getPrivateLookup() {
+ return LookupHolder.PRIVATE_LOOKUP;
+ }
+
+ public static MethodHandles.Lookup of(final Class<?> declaringClass) {
+ try {
+ if (getPrivateLookup() != null) {
+ return MethodHandles.Lookup.class.cast(getPrivateLookup().invoke(null, declaringClass, MethodHandles.lookup()));
+ }
+ return getLookupConstructor().newInstance(declaringClass, MethodHandles.Lookup.PRIVATE).in(declaringClass);
+ } catch (final IllegalAccessException | InstantiationException e) {
+ throw new IllegalArgumentException(e);
+ } catch (final InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public int getVersion() {
return 9;
}
+
+ @Override
+ public Object getInvokeSpecialHandle(Method method, Object receiver) {
+ if (getLookupConstructor() != null) {
+ Class declaringClass = method.getDeclaringClass();
+ try {
+ return of(declaringClass).unreflectSpecial(method, receiver.getClass()).bindTo(receiver);
+ } catch (ReflectiveOperationException e) {
+ throw new GroovyBugError(e);
+ }
+ }
+ return super.getInvokeSpecialHandle(method, receiver);
+ }
}