【问题标题】:Replacing statically referenced method in Java替换Java中的静态引用方法
【发布时间】:2023-03-09 14:40:01
【问题描述】:

我有一个像下面这样的类,它的方法只返回一个字符串,但我想修改它从另一个类返回的内容,而不是自己硬编码。

public class Name {
    public static String getName() {
        return "MyName";
    }
}

有没有办法做到这一点?我尝试了 BCEL,但这似乎并没有改变返回值。

编辑:这是一个模组。我试图通过不修改它使其完全独立于现有代码。

谢谢。

【问题讨论】:

  • 为什么要这么做?你可以用setter方法来代替吗?
  • Name.getName() 方法返回硬编码值(如上)还是静态类字段?
  • 它返回一个像上面一样的硬编码值。如果该值是一个类变量,我可以使用简单的反射来修改它的值,但它不是。

标签: java reflection methods static bcel


【解决方案1】:

你可以将参数传递给方法

 public class Main {
        getName("newName")
    }

public class Name {
    public static String getName(String name) {
        return name;
    }
}

【讨论】:

  • 是的,但是我无法修改返回字符串的现有类。我试图在不更改现有代码的情况下做到这一点。 (是的,它是一个模组)
【解决方案2】:

您可以尝试添加一个-javaagent 代理,它将使用asmbcel 之类的东西来修改Name 类的字节码,这样静态方法将返回另一个字符串。许多模拟测试框架 - 例如powermockjmockit - 可以做到这一点。

编辑Here 是一些帮助您入门的示例代码。这是一个 javaagent,它可以修改给定的公共静态方法,该方法返回一个 String 以返回另一个常量 String。例如:

public class TestMain
{
    public static void main(String[] args)
    {
        System.out.println(Name.getName());
    }
}

class Name
{
    public static String getName()
    {
        return "ORIGINAL";
    }
}

$ java -cp build/libs/bciex.jar mycompany.myapp.TestMain
ORIGINAL
$ java -cp build/libs/bciex.jar -javaagent:build/libs/bciex.jar="mycompany.myapp.TestMain|getName|SOME_STRING" mycompany.myapp.TestMain
Agent loaded; will modify [getName] method of classes in [mycompany.myapp.TestMain] to return [SOME_STRING]
SOME_STRING
$ 

【讨论】:

    【解决方案3】:

    确定你尝试过 BCEL 吗?我创建了一个完整的示例here

    JavaClass target;
    try {
      target = Repository.lookupClass("Target");
    } catch (final ClassNotFoundException ex) {
      throw new RuntimeException("unable to resolve Target", ex);
    }
    final ClassGen targetGen = new ClassGen(target);
    final ConstantPoolGen pool = targetGen.getConstantPool();
    final ConstantMethodref ref = (ConstantMethodref) pool.getConstant(
        pool.lookupMethodref("Name", "getName", "()Ljava/lang/String;"));
    ref.setClassIndex(pool.lookupClass("Target"));
    ref.setNameAndTypeIndex(pool.addNameAndType("$Name$getName", "()Ljava/lang/String;"));
    final InstructionList code = new InstructionList();
    final InstructionFactory factory = new InstructionFactory(targetGen, pool);
    code.append(factory.createConstant("overriden-name"));
    code.append(factory.createReturn(Type.STRING));
    code.setPositions();
    final MethodGen methodGen = new MethodGen(
        Constants.ACC_PRIVATE | Constants.ACC_SYNTHETIC | Constants.ACC_STATIC,
        Type.STRING, new Type[0], new String[0], "$Name$getName", "Target",
        code, pool);
    methodGen.setMaxLocals(0);
    methodGen.setMaxStack(1);
    targetGen.addMethod(methodGen.getMethod());
    try {
      targetGen.getJavaClass().dump("Target.class");
    } catch (final IOException ex) {
      throw new RuntimeException("unable to save Target", ex);
    }
    
    C:\dev\scrap>javac Target.java
    C:\dev\scrap>java Target
    original-name
    C:\dev\scrap>javac -cp .;bcel-6.0.jar Instrumenter.java
    C:\dev\scrap>java -cp .;bcel-6.0.jar Instrumenter
    C:\dev\scrap>java Target
    overriden-name
    

    【讨论】:

    • 嗯,我需要将 BCEL 添加到类路径中,我的项目中只有它的源代码并让我的 mod 运行此方法,我得到一个 ArrayOutOfBoundsException -1。我会玩一下,谢谢。
    • 这主要是一个概念验证,但我可以验证它是否有效。
    猜你喜欢
    • 2019-06-27
    • 2015-02-21
    • 1970-01-01
    • 2016-07-29
    • 2018-11-25
    • 2019-03-10
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多