lundi 16 mars 2015

ByteBuddy fails when trying to redefine sun.reflect.GeneratedMethodAccessor1

Driven by curiosity, I tried to export the bytecode of GeneratedMethodAccessor1 (generated by the JVM when using reflection).


I try to get the bytecode of the class the following way:



public class MethodExtractor {

public int extract() {
return new Random().nextInt();
}

public static void main(String[] args) throws Exception {

ExampleClass example = new ExampleClass();

Method exampleMethod = ExampleClass.class
.getDeclaredMethod("exampleMethod");
exampleMethod.setAccessible(true);

int rndSum = 0;
for (int i = 0; i < 20; i++) {
rndSum += (Integer) exampleMethod.invoke(example);
}

Field field = Method.class.getDeclaredField("methodAccessor");
field.setAccessible(true);
Object methodAccessor = field.get(exampleMethod);
Field delegate = methodAccessor.getClass().getDeclaredField("delegate");
delegate.setAccessible(true);
Object gma = delegate.get(methodAccessor);

ByteBuddyAgent.installOnOpenJDK();
try {
ClassFileLocator classFileLocator = ClassFileLocator.AgentBased
.fromInstalledAgent(gma.getClass().getClassLoader());
Unloaded<? extends Object> unloaded = new ByteBuddy().redefine(
gma.getClass(), classFileLocator).make();
Map<TypeDescription, File> saved = unloaded.saveIn(Files
.createTempDirectory("javaproxy").toFile());
saved.forEach((t, u) -> System.out.println(u.getAbsolutePath()));
} catch (IOException e) {
throw new RuntimeException("Failed to save class to file");
}
}
}


I however get the following error when executing this class:



Exception in thread "main" java.lang.NullPointerException
at net.bytebuddy.dynamic.scaffold.TypeWriter$Engine$ForRedefinition.create(TypeWriter.java:172)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1182)
at net.bytebuddy.dynamic.scaffold.inline.InlineDynamicTypeBuilder.make(InlineDynamicTypeBuilder.java:244)
at reegnz.dyna.proxy.extractor.MethodExtractor.main(MethodExtractor.java:48)


Basically I first iterate on the method call enough times for the JVM to inflate the method (generate the GeneratedMethodAccessor) and then try to redefine the class to get the bytecode.


I tried the same method to export a generated Proxy class, and it worked flawlessly. That's what drove me to try this.


It seems that the DelegatingClassLoader of the GeneratedMethodAccessor1 class can't even reload the class when I try to load the class with the loadClass method.


Any ideas how I could retrieve the bytecode for GeneratedMethodAccessor classes?






Aucun commentaire:

Enregistrer un commentaire