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) {