0

I am trying to figure out how ASM works, with the help of A Guide to Java Bytecode Manipulation with ASM. I followed the tutorial and created an 'extra' static field for the Integer class. Here is the simplified logic of the Instrumentation class:

public static void premain(String agentArgs, Instrumentation inst) {
  inst.addTransformer(new ClassFileTransformer() {
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, final byte[] buffer) {
      if (className.equals("ClassX")) {
        var reader = new ClassReader(bytes);
        var writer = new ClassWriter(reader, 0);
        var visitor = new ClassVisitor() { // simplified
          @Override
          public void visitEnd() {
            if (!isFieldPresent) {
              var fv = cv.visitField(ACC_PUBLIC + ACC_STATIC, "aNewBooleanField", BOOLEAN_TYPE.toString(), null, true);
              if (fv != null) fv.visitEnd();
            }
            cv.visitEnd();
          }
        };
        reader.accept(visitor, 0);
        return writer.toByteArray();
      }
      return buffer;
    }
  });
}

I packaged the ASM code with maven; now I am trying the run it, but I got no clue how to use it. I expected I should be able to to something like this:

public static void main(String[] args) {
    System.out.println(ClassX.aNewBooleanField);
}

This won't compile of course, as the compiler is not aware of the extra field. I tried adding the java agent¹ as the tutorial suggest, but I don't understand that either. How can the compiler be aware of a process (the agent) that operates at runtime?

So bottom line question would be, how do I use the ASM manipulated code?


¹ -javaagent:"/<path>/.m2/repository/org/example/try-asm/1.0-SNAPSHOT/try-asm-1.0-SNAPSHOT.jar"

Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
  • You run the transformation on the dependency, creating a new jar file, which can be used to compile against. Still a bad idea to rely on an agent to run stuff. – Johannes Kuhn Apr 06 '23 at 00:53
  • @JohannesKuhn Sure, but this whole exercise is just for educational purposes. I won't use stuff like java agents for production code :P. Even reflection code should be used as minimum as possible imho. – Jacob van Lingen Apr 06 '23 at 06:52

1 Answers1

0

As stated in the question, the compiler is indeed not aware of the modifications made to the bytecode of the class. Therefore, you can't call ClassX.aNewBooleanField directly. Thus you need to fall back to reflection:

var modifiedClass = Class.forName("ClassX");
var field = modifiedClass.getField("aNewBooleanField");
System.out.println(field.getBoolean(null));

As you can compile your code now, you can run it with the java agent and above code will print out the true value!

Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78