java - ByteBuddy fails when trying to redefine sun.reflect.GeneratedMethodAccessor1 -
driven curiosity, tried export bytecode of generatedmethodaccessor1 (generated jvm when using reflection).
i try bytecode of class following way:
public class methodextractor { public static void main(string[] args) throws exception { exampleclass example = new exampleclass(); method examplemethod = exampleclass.class .getdeclaredmethod("examplemethod"); examplemethod.setaccessible(true); int rndsum = 0; (int = 0; < 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 save class file"); } } }
i following error when executing class:
exception in thread "main" java.lang.nullpointerexception @ net.bytebuddy.dynamic.scaffold.typewriter$engine$forredefinition.create(typewriter.java:172) @ net.bytebuddy.dynamic.scaffold.typewriter$default.make(typewriter.java:1182) @ net.bytebuddy.dynamic.scaffold.inline.inlinedynamictypebuilder.make(inlinedynamictypebuilder.java:244) @ reegnz.dyna.proxy.extractor.methodextractor.main(methodextractor.java:48)
basically first iterate on method call enough times jvm inflate method (generate generatedmethodaccessor) , try redefine class bytecode.
i tried same method export generated proxy class, , worked flawlessly. that's drove me try this.
it seems delegatingclassloader of generatedmethodaccessor1 class can't reload class when try load class loadclass method.
any ideas how retrieve bytecode generatedmethodaccessor classes?
first of all, nullpointerexception
bug, fixed that. loader should have thrown illegalargumentexception
instead never got far. bringing attention.
boiled down, problem byte buddy facing that
gma.getclass().getclassloader().findclass(gma.getclass().getname());
throws classnotfoundexception
. consequence of using delegatingclassloader
accessor classes. educated guess, think class loader intends shield classes outside in order make them garbage collectable. however, not allowing lookup of class breaks contract classloader
. apart that, assume loading routine refactored use jdk's anonymous class loaders @ point in future (similar classes representing lambda expressions). strangely enough, seems the source code delegatingclassloader
not available in jdk though can find in distribution. probably, vm treats these loader specially @ place.
for now, can use following classfiletransformer
uses reflection magic on class loader locate loaded class , extract byte array. (the classfilelocator
interface takes name instead of loaded class in order allow working unloaded types case. no idea why not work in case.)
class delegateextractor extends classfilelocator.agentbased { private final classloader classloader; private final instrumentation instrumentation; public delegateextractor(classloader classloader, instrumentation instrumentation) { super(classloader, instrumentation); this.classloader = classloader; this.instrumentation = instrumentation; } @override public resolution locate(string typename) { try { extractionclassfiletransformer classfiletransformer = new extractionclassfiletransformer(classloader, typename); try { instrumentation.addtransformer(classfiletransformer, true); // start nasty hack field field = classloader.class.getdeclaredfield("classes"); field.setaccessible(true); instrumentation.retransformclasses( (class<?>) ((vector<?>) field.get(classloader)).get(0)); // end nasty hack byte[] binaryrepresentation = classfiletransformer.getbinaryrepresentation(); return binaryrepresentation == null ? resolution.illegal.instance : new resolution.explicit(binaryrepresentation); } { instrumentation.removetransformer(classfiletransformer); } } catch (exception ignored) { return resolution.illegal.instance; } } }
to further simplify code, can use classfilelocator
s directly instead of applying rewrite matter of fact might modify class file if not apply changes class.
Comments
Post a Comment