diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index 140a9cab..bb5bab6e 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -1295,8 +1295,9 @@ public Class> toClass() throws CannotCompileException { * Once this method is called, further modifications are not * allowed any more. * - *
This method is provided for convenience. If you need more - * complex functionality, you should write your own class loader. + *
This method is provided for convenience. You should use + * {@code toClass(Lookup)} for better compatibility with the + * module system. * *
Note: this method calls toClass()
* in ClassPool
.
@@ -1308,6 +1309,7 @@ public Class> toClass() throws CannotCompileException {
* @param neighbor A class belonging to the same package that this
* class belongs to. It is used to load the class.
* @see ClassPool#toClass(CtClass,Class)
+ * @see #CtClass(java.lang.invoke.MethodHandles.Lookup)
* @since 3.24
*/
public Class> toClass(Class> neighbor) throws CannotCompileException
diff --git a/src/main/javassist/util/proxy/DefineClassHelper.java b/src/main/javassist/util/proxy/DefineClassHelper.java
index dea53670..401fed69 100644
--- a/src/main/javassist/util/proxy/DefineClassHelper.java
+++ b/src/main/javassist/util/proxy/DefineClassHelper.java
@@ -292,6 +292,7 @@ public static Class> toClass(Class> neighbor, byte[] bcode)
throws CannotCompileException
{
try {
+ DefineClassHelper.class.getModule().addReads(neighbor.getModule());
Lookup lookup = MethodHandles.lookup();
Lookup prvlookup = MethodHandles.privateLookupIn(neighbor, lookup);
return prvlookup.defineClass(bcode);
diff --git a/src/main/javassist/util/proxy/FactoryHelper.java b/src/main/javassist/util/proxy/FactoryHelper.java
index 38fcbf42..1928fdd5 100644
--- a/src/main/javassist/util/proxy/FactoryHelper.java
+++ b/src/main/javassist/util/proxy/FactoryHelper.java
@@ -141,6 +141,24 @@ public static Class> toClass(ClassFile cf, Class> neighbor,
}
}
+ /**
+ * Loads a class file by a given lookup.
+ *
+ * @param lookup used to define the class.
+ * @since 3.24
+ */
+ public static Class> toClass(ClassFile cf, java.lang.invoke.MethodHandles.Lookup lookup)
+ throws CannotCompileException
+ {
+ try {
+ byte[] b = toBytecode(cf);
+ return DefineClassHelper.toClass(lookup, b);
+ }
+ catch (IOException e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
private static byte[] toBytecode(ClassFile cf) throws IOException {
ByteArrayOutputStream barray = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(barray);
diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java
index 07b0e161..bc2c024f 100644
--- a/src/main/javassist/util/proxy/ProxyFactory.java
+++ b/src/main/javassist/util/proxy/ProxyFactory.java
@@ -35,6 +35,7 @@
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.lang.invoke.MethodHandles.Lookup;
import javassist.CannotCompileException;
import javassist.bytecode.AccessFlag;
@@ -436,43 +437,92 @@ public void setFilter(MethodFilter mf) {
/**
* Generates a proxy class using the current filter.
+ * The module or package where a proxy class is created
+ * has to be opened to this package or the Javassist module.
+ *
+ * @see #createClass(Lookup)
*/
public Class> createClass() {
if (signature == null) {
computeSignature(methodFilter);
}
- return createClass1();
+ return createClass1(null);
}
/**
* Generates a proxy class using the supplied filter.
+ * The module or package where a proxy class is created
+ * has to be opened to this package or the Javassist module.
*/
public Class> createClass(MethodFilter filter) {
computeSignature(filter);
- return createClass1();
+ return createClass1(null);
}
/**
* Generates a proxy class with a specific signature.
* access is package local so ProxyObjectInputStream can use this
* @param signature
- * @return
*/
Class> createClass(byte[] signature)
{
installSignature(signature);
- return createClass1();
+ return createClass1(null);
+ }
+
+ /**
+ * Generates a proxy class using the current filter.
+ *
+ * @param lookup used for loading the proxy class.
+ * It needs an appropriate right to invoke {@code defineClass}
+ * for the proxy class.
+ * @since 3.24
+ */
+ public Class> createClass(Lookup lookup) {
+ if (signature == null) {
+ computeSignature(methodFilter);
+ }
+ return createClass1(lookup);
}
- private Class> createClass1() {
+ /**
+ * Generates a proxy class using the supplied filter.
+ *
+ * @param lookup used for loading the proxy class.
+ * It needs an appropriate right to invoke {@code defineClass}
+ * for the proxy class.
+ * @param filter the filter.
+ * @since 3.24
+ */
+ public Class> createClass(Lookup lookup, MethodFilter filter) {
+ computeSignature(filter);
+ return createClass1(lookup);
+ }
+
+ /**
+ * Generates a proxy class with a specific signature.
+ * access is package local so ProxyObjectInputStream can use this.
+ *
+ * @param lookup used for loading the proxy class.
+ * It needs an appropriate right to invoke {@code defineClass}
+ * for the proxy class.
+ * @param signature the signature.
+ */
+ Class> createClass(Lookup lookup, byte[] signature)
+ {
+ installSignature(signature);
+ return createClass1(lookup);
+ }
+
+ private Class> createClass1(Lookup lookup) {
Class> result = thisClass;
if (result == null) {
ClassLoader cl = getClassLoader();
synchronized (proxyCache) {
if (factoryUseCache)
- createClass2(cl);
+ createClass2(cl, lookup);
else
- createClass3(cl);
+ createClass3(cl, lookup);
result = thisClass;
// don't retain any unwanted references
@@ -512,7 +562,7 @@ public String getKey(Class> superClass, Class>[] interfaces, byte[] signatur
return sbuf.toString();
}
- private void createClass2(ClassLoader cl) {
+ private void createClass2(ClassLoader cl, Lookup lookup) {
String key = getKey(superClass, interfaces, signature, factoryWriteReplace);
/*
* Excessive concurrency causes a large memory footprint and slows the
@@ -534,13 +584,13 @@ private void createClass2(ClassLoader cl) {
return;
}
}
- createClass3(cl);
+ createClass3(cl, lookup);
details = new ProxyDetails(signature, thisClass, factoryWriteReplace);
cacheForTheLoader.put(key, details);
// }
}
- private void createClass3(ClassLoader cl) {
+ private void createClass3(ClassLoader cl, Lookup lookup) {
// we need a new class so we need a new class name
allocateClassName();
@@ -549,7 +599,11 @@ private void createClass3(ClassLoader cl) {
if (writeDirectory != null)
FactoryHelper.writeFile(cf, writeDirectory);
- thisClass = FactoryHelper.toClass(cf, getClassInTheSamePackage(), cl, getDomain());
+ if (lookup == null)
+ thisClass = FactoryHelper.toClass(cf, getClassInTheSamePackage(), cl, getDomain());
+ else
+ thisClass = FactoryHelper.toClass(cf, lookup);
+
setField(FILTER_SIGNATURE_FIELD, signature);
// legacy behaviour : we only set the default interceptor static field if we are not using the cache
if (!factoryUseCache) {