Byte Buddy Member Substitution throwing IllegalStateException error

社会主义新天地 提交于 2020-03-23 11:59:08

问题


I'm trying to write a java instrumentation agent using byte buddy. My goal is to replace a java standard library method call with a proxy call of my own. I was suggested to use Byte Buddy's MemberSubstitution to achieve this. I used this and this questions from SO for my reference.

I'm using Intellij IDEA for coding. My Agent code is split into multiple files as follows:

MyFirstAgent.java

public class MyFirstAgent {

    public static void premain(String agentArgs, Instrumentation inst) {

        new AgentBuilder.Default()
                .type(ElementMatchers.any())
                .transform(new ByteBuddyTransformer())
                .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .installOn(inst);
}

ByteBuddyTransformer.java

public class ByteBuddyTransformer implements AgentBuilder.Transformer {

    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                            ClassLoader classLoader, JavaModule javaModule) {

        try {
            return builder.visit(MemberSubstitution.relaxed()
                    .method(named("add"))
                    .replaceWith(MyClass.class.getMethod("printLine"))
                    .on(any()));

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return builder;
    }
}

MyClass.java

public class MyClass {
    public boolean printLine(){
        System.out.println("This is the proxy!");
        return true;
    }
}

And the application that I want to instrument is in another Intellij IDEA project with the following:

Main.java

public class Main {
    public static void main(String[] args) {
        ClassToMonitor classToMonitor = new ClassToMonitor();
        classToMonitor.bar();
    }
}

ClassToMonitor.java

package com.company;

import java.util.ArrayList;
import java.util.Arrays;

public class ClassToMonitor {
    public void bar() {
// create an empty array list with an initial capacity
        ArrayList<Integer> arrlist = new ArrayList<Integer>(5);

// use add() method to add elements in the list
        arrlist.add(15);

// print all the elements available in list
        for (Integer number : arrlist) {
            System.out.println("Number = " + number);
        }
    }
}

When I build the fat jar of my agent and run it with my application, I get the following error:

[Byte Buddy] ERROR com.company.ClassToMonitor [jdk.internal.loader.ClassLoaders$AppClassLoader@2626b418, unnamed module @385e9564, loaded=false]
java.lang.IllegalStateException: Cannot invoke public boolean com.company.MyClass.printLine() on [class java.util.ArrayList, E]

I can provide the full error message if required. Also, I'm new to Java and Instrumentation in general so I might be missing something fundamental here, please kindly excuse me and point it out if that's the case.


回答1:


For substitution to work, the target method needs to accept the same arguments as the replaced method, in your case an int. Also, since you are calling a member, the implicit first argument of your class needs to be the receiver type, i.e. ArrayList or any super type, even Object. Also, your replacement method needs to be static:

public class MyClass {
  public static boolean printLine(Object ignored, int ignored2){
    System.out.println("This is the proxy!");
    return true;
  }
}

MemberSubstitution is still not as flexible as it is supposed to be. You can however already inject custom byte code using the chained step if that is what you want.



来源:https://stackoverflow.com/questions/60584788/byte-buddy-member-substitution-throwing-illegalstateexception-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!