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); + } }