字节伙伴成员替换引发IllegalStateException错误

问题描述 投票:1回答:1

我正在尝试使用字节伙伴来编写Java工具代理。我的目标是用我自己的代理调用替换java标准库方法调用。建议使用Byte Buddy的MemberSubstitution实现此目的。我使用SO的thisthis问题作为参考。

我正在使用Intellij IDEA进行编码。我的代理代码分为以下多个文件:

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;
    }
}

并且我要检测的应用程序在另一个具有以下内容的Intellij IDEA项目中:

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);
        }
    }
}

当我构建代理的胖子并用我的应用程序运行它时,出现以下错误:

[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]

如果需要,我可以提供完整的错误消息。另外,我通常对Java和Instrumentation还是陌生的,因此在这里我可能会遗漏一些基本知识,请原谅并指出是这种情况。

java instrumentation byte-buddy
1个回答
0
投票

为了使替换生效,目标方法需要接受与替换方法相同的参数,在您的情况下为int。另外,由于您正在调用成员,因此该类的隐式第一个参数必须是接收器类型,即ArrayList或任何超级类型,甚至是Object。另外,您的替换方法必须是静态的:

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

MemberSubstitution仍然不如预期的那样灵活。但是,如果需要的话,您可以使用chained步骤注入自定义字节码。

© www.soinside.com 2019 - 2024. All rights reserved.