Search code examples
javareflectionmethodsstaticbcel

Replacing statically referenced method in Java


I have a class like below with a method that just returns a String, but I want to modify what it returns from another class, without hardcoding it myself.

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

Is there any way to do this? I tried BCEL but that didn't seem to change the return value.

Edit: This is for a mod. I'm trying to make it completely independant from the existing code, by not modifying it.

Thanks.


Solution

  • Are you sure you've tried BCEL? I created a fully-working example 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