You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by ta...@apache.org on 2021/09/19 14:34:16 UTC

[deltaspike] branch master updated: DELTASPIKE-1432 Implement MethodHandles.Lookup based fallback for class definition on Java 9+

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/deltaspike.git


The following commit(s) were added to refs/heads/master by this push:
     new e3f9ce5  DELTASPIKE-1432 Implement MethodHandles.Lookup based fallback for class definition on Java 9+
     new 2bf31a3  Merge pull request #119 from beikov/DELTASPIKE-1432
e3f9ce5 is described below

commit e3f9ce55fe774ffde12802e94a760880c23b3c9b
Author: Christian Beikov <ch...@gmail.com>
AuthorDate: Mon Aug 30 00:28:44 2021 +0200

    DELTASPIKE-1432 Implement MethodHandles.Lookup based fallback for class definition on Java 9+
---
 .../impl/AsmDeltaSpikeProxyClassGenerator.java     |  46 +-----
 .../apache/deltaspike/proxy/impl/ClassDefiner.java | 160 +++++++++++++++++++++
 deltaspike/parent/pom.xml                          |   2 +-
 3 files changed, 163 insertions(+), 45 deletions(-)

diff --git a/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/AsmDeltaSpikeProxyClassGenerator.java b/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/AsmDeltaSpikeProxyClassGenerator.java
index b5409c1..2911243 100644
--- a/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/AsmDeltaSpikeProxyClassGenerator.java
+++ b/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/AsmDeltaSpikeProxyClassGenerator.java
@@ -23,7 +23,6 @@ import org.apache.deltaspike.proxy.spi.DeltaSpikeProxy;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.UndeclaredThrowableException;
-import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -70,8 +69,8 @@ public class AsmDeltaSpikeProxyClassGenerator implements DeltaSpikeProxyClassGen
         byte[] proxyBytes = generateProxyClassBytes(targetClass,
                 classFileName, superAccessorMethodSuffix, additionalInterfaces, delegateMethods, interceptMethods);
 
-        Class<T> proxyClass = (Class<T>) loadClass(classLoader, proxyName, proxyBytes,
-                targetClass.getProtectionDomain());
+        Class<T> proxyClass = (Class<T>) ClassDefiner.defineClass(classLoader, proxyName, proxyBytes,
+                targetClass, targetClass.getProtectionDomain());
 
         return proxyClass;
     }
@@ -504,45 +503,4 @@ public class AsmDeltaSpikeProxyClassGenerator implements DeltaSpikeProxyClassGen
         }
         return result;
     }
-
-    /**
-     * Adapted from http://asm.ow2.org/doc/faq.html#Q5
-     *
-     * @param b
-     *
-     * @return Class<?>
-     */
-    private static Class<?> loadClass(ClassLoader loader, String className, byte[] b,
-            ProtectionDomain protectionDomain)
-    {
-        // override classDefine (as it is protected) and define the class.
-        try
-        {
-            java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(
-                    "defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
-
-            // protected method invocation
-            boolean accessible = method.isAccessible();
-            if (!accessible)
-            {
-                method.setAccessible(true);
-            }
-            try
-            {
-                return (Class<?>) method.invoke(loader, className, b, Integer.valueOf(0), Integer.valueOf(b.length),
-                        protectionDomain);
-            }
-            finally
-            {
-                if (!accessible)
-                {
-                    method.setAccessible(false);
-                }
-            }
-        }
-        catch (Exception e)
-        {
-            throw e instanceof RuntimeException ? ((RuntimeException) e) : new RuntimeException(e);
-        }
-    }
 }
diff --git a/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/ClassDefiner.java b/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/ClassDefiner.java
new file mode 100644
index 0000000..ea1ab81
--- /dev/null
+++ b/deltaspike/modules/proxy/impl-asm/src/main/java/org/apache/deltaspike/proxy/impl/ClassDefiner.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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 org.apache.deltaspike.proxy.impl;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+
+class ClassDefiner
+{
+    private static final Method CLASS_LOADER_DEFINE_CLASS;
+    private static final Method GET_MODULE;
+    private static final Method CAN_READ;
+    private static final Method ADD_READS;
+    private static final Method PRIVATE_LOOKUP_IN;
+    private static final Method DEFINE_CLASS;
+
+    static
+    {
+        Method classLoaderDefineClass = null;
+        try
+        {
+            java.lang.reflect.Method method = ClassLoader.class.getDeclaredMethod(
+                "defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
+            method.setAccessible(true);
+            classLoaderDefineClass = method;
+        }
+        catch (Exception ex)
+        {
+            // Ignore
+        }
+        CLASS_LOADER_DEFINE_CLASS = classLoaderDefineClass;
+
+        Method getModule = null;
+        Method canRead = null;
+        Method addReads = null;
+        Method privateLookupIn = null;
+        Method defineClass = null;
+        try
+        {
+            getModule = Class.class.getMethod("getModule");
+            Class<?> moduleClass = getModule.getReturnType();
+            canRead = moduleClass.getMethod("canRead", moduleClass);
+            addReads = moduleClass.getMethod("addReads", moduleClass);
+            privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
+            defineClass = MethodHandles.Lookup.class.getMethod("defineClass", byte[].class);
+        }
+        catch (Exception ex)
+        {
+            // Ignore
+        }
+        GET_MODULE = getModule;
+        CAN_READ = canRead;
+        ADD_READS = addReads;
+        PRIVATE_LOOKUP_IN = privateLookupIn;
+        DEFINE_CLASS = defineClass;
+    }
+
+    private ClassDefiner()
+    {
+
+    }
+
+    static Class<?> defineClass(ClassLoader loader, String className, byte[] b,
+            Class<?> originalClass, ProtectionDomain protectionDomain)
+    {
+        if (CLASS_LOADER_DEFINE_CLASS == null)
+        {
+            return defineClassMethodHandles(loader, className, b, originalClass, protectionDomain);
+        }
+        else
+        {
+            return defineClassClassLoader(loader, className, b, originalClass, protectionDomain);
+        }
+    }
+    /**
+     * Adapted from http://asm.ow2.org/doc/faq.html#Q5
+     *
+     * @param b
+     *
+     * @return Class<?>
+     */
+    static Class<?> defineClassClassLoader(ClassLoader loader, String className, byte[] b,
+                                Class<?> originalClass, ProtectionDomain protectionDomain)
+    {
+        try
+        {
+            return (Class<?>) CLASS_LOADER_DEFINE_CLASS.invoke(
+                loader, className, b, Integer.valueOf(0), Integer.valueOf(b.length), protectionDomain);
+        }
+        catch (Exception e)
+        {
+            throw e instanceof RuntimeException ? ((RuntimeException) e) : new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Implementation based on MethodHandles.Lookup.
+     *
+     * @return Class<?>
+     */
+    static Class<?> defineClassMethodHandles(ClassLoader loader, String className, byte[] b,
+                                             Class<?> originalClass, ProtectionDomain protectionDomain)
+    {
+        try
+        {
+            Object thisModule = GET_MODULE.invoke(AsmDeltaSpikeProxyClassGenerator.class);
+            Object lookupClassModule = GET_MODULE.invoke(originalClass);
+            if (!(boolean) CAN_READ.invoke(thisModule, lookupClassModule))
+            {
+                // we need to read the other module in order to have privateLookup access
+                // see javadoc for MethodHandles.privateLookupIn()
+                ADD_READS.invoke(thisModule, lookupClassModule);
+            }
+            Object lookup = PRIVATE_LOOKUP_IN.invoke(null, originalClass, MethodHandles.lookup());
+            return (Class<?>) DEFINE_CLASS.invoke(lookup, b);
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+//    static Class<?> defineClassMethodHandles(ClassLoader loader, String className, byte[] b,
+//                                Class<?> originalClass, ProtectionDomain protectionDomain)
+//    {
+//        Module thisModule = AsmDeltaSpikeProxyClassGenerator.class.getModule();
+//        try
+//        {
+//            Module lookupClassModule = originalClass.getModule();
+//            if (!thisModule.canRead(lookupClassModule))
+//            {
+//                // we need to read the other module in order to have privateLookup access
+//                // see javadoc for MethodHandles.privateLookupIn()
+//                thisModule.addReads(lookupClassModule);
+//            }
+//            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(originalClass, MethodHandles.lookup());
+//            return lookup.defineClass(b);
+//        }
+//        catch (IllegalAccessException e)
+//        {
+//            throw new RuntimeException(e);
+//        }
+//    }
+}
diff --git a/deltaspike/parent/pom.xml b/deltaspike/parent/pom.xml
index 813c2d3..acf5165 100644
--- a/deltaspike/parent/pom.xml
+++ b/deltaspike/parent/pom.xml
@@ -73,7 +73,7 @@
         <mojarra1.version>1.2_14</mojarra1.version>
 
         <!-- used for some bytecode proxy stuff. Shaded in -->
-        <asm.version>9.1</asm.version>
+        <asm.version>9.2</asm.version>
 
         <!-- Geronimo specs -->
         <geronimo-annotation_1.2_spec.version>1.0</geronimo-annotation_1.2_spec.version>