Skip to content

Instantly share code, notes, and snippets.

@kaspernielsen
Created January 30, 2023 19:18
Show Gist options
  • Save kaspernielsen/e072a38654d63f2918540e24e9d0380e to your computer and use it in GitHub Desktop.
Save kaspernielsen/e072a38654d63f2918540e24e9d0380e to your computer and use it in GitHub Desktop.
import static org.objectweb.asm.Opcodes.ACC_BRIDGE;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_STATIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;
import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.V17;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.module.ModuleDescriptor.Opens;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.function.Supplier;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
/**
*
*/
public class PrivateLookup {
public static Lookup privateLookup(Lookup base, Class<?> clazz) throws IllegalAccessException {
base.lookupClass().getModule().addReads(clazz.getModule());
try {
return MethodHandles.privateLookupIn(clazz, base);
} catch (IllegalAccessException e) {
try {
return privateLookup0(base, clazz, e);
} catch (IOException | InstantiationException ioe) {
throw e;
}
}
}
private static Lookup privateLookup0(Lookup base, Class<?> clazz, IllegalAccessException e)
throws IllegalAccessException, IOException, InstantiationException {
for (Opens o : clazz.getModule().getDescriptor().opens()) {
if (o.targets().contains(base.lookupClass().getModule().getName())) {
String path = o.source().replace('.', '/');
Enumeration<URL> resources = clazz.getClassLoader().getResources(path);
while (resources.hasMoreElements()) {
File f = new File(resources.nextElement().getFile());
for (Path p : Files.newDirectoryStream(f.toPath(), "*.class")) {
String fname = p.getFileName().toString();
String className = o.source() + "." + fname.substring(0, fname.length() - 6);
try {
Class<?> cl = clazz.getClassLoader().loadClass(className);
Lookup lookup = MethodHandles.privateLookupIn(cl, base);
String newClass = cl.getPackageName().replace(".", "/") + "/" + System.nanoTime();
Class<?> c = lookup.defineClass(generate(newClass));
Supplier<Lookup> s = (Supplier<Lookup>) c.newInstance();
Lookup l = s.get();
return MethodHandles.privateLookupIn(clazz, l);
} catch (ClassNotFoundException ignore) {}
}
}
}
}
throw e;
}
public static byte[] generate(String cName) {
ClassWriter classWriter = new ClassWriter(0);
MethodVisitor methodVisitor;
classWriter.visit(V17, ACC_PUBLIC | ACC_SUPER, cName, "Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/invoke/MethodHandles$Lookup;>;",
"java/lang/Object", new String[] { "java/util/function/Supplier" });
classWriter.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup", ACC_PUBLIC | ACC_FINAL | ACC_STATIC);
{
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
methodVisitor.visitInsn(RETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
{
methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "get", "()Ljava/lang/invoke/MethodHandles$Lookup;", null, null);
methodVisitor.visitCode();
methodVisitor.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
{
methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC, "get", "()Ljava/lang/Object;", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(ALOAD, 0);
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, cName, "get", "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
methodVisitor.visitInsn(ARETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
classWriter.visitEnd();
return classWriter.toByteArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment