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>