javajava-bytecode-asm

Exception when parsing Java 16 bytecode with ASM library


I'm trying to parse bytecode from Java 16 (bytecode version 60) using the ObjectWeb ASM. I've written the following code:

@Test
void parseBytecode() {
    try (InputStream stream = this.getClass()
         .getClassLoader()
         .getResourceAsStream("MethodByte.class")) {
         //MethodByte.class has 60 version (Java 16)
        new ClassReader(stream).accept(new ClassPrinter(), 0);
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

private class ClassPrinter extends ClassVisitor {
    protected ClassPrinter() {
        super(Opcodes.ASM9);
    }
}

When I run the code, I'm getting an IllegalArgumentException:

Caused by: java.lang.IllegalArgumentException
   at org.objectweb.asm.ClassReader.<init>(ClassReader.java:262)
   at org.objectweb.asm.ClassReader.<init>(ClassReader.java:180)
   at org.objectweb.asm.ClassReader.<init>(ClassReader.java:166)
   at org.objectweb.asm.ClassReader.<init>(ClassReader.java:287)

Version of ASM library is 9.5 (from pom.xml):

<dependency>
  <groupId>org.ow2.asm</groupId>
  <artifactId>asm</artifactId>
  <version>9.5</version>
  <scope>compile</scope>
</dependency>

Also, it's worth mentioning that I checked the MethodByte.class lies in the correct place. I printed its content to ensure that it is reachable in the test.

From my understanding, ASM 9 should support java 16. I suspect the error might be due to the ASM version I'm using, and its incompatibility with Java 16 bytecode, so I tried Opcodes.V16 instead of Opcodes.ASM9 and it didn't help.

Also I tried to parse the bytecode with 52 version (Java 8) and it didn't help either.

Has anyone encountered this before?


Update: How I get MethodByte.class.

I'm using maven to build project and run the tests. So, I have the next pipeline:

  1. I create a java class with the next content:
package org.eolang.jeo;

public class MethodByte {
    public static void main(String[] args) {
        System.out.println(method());
        System.out.println("passed");
    }
    static byte method() {
        return 52;
    }
}
  1. I run mvn clean compile in order to build that class. I use the next maven configuration properties for that:
<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>16</maven.compiler.source>
  <maven.compiler.target>16</maven.compiler.target>
</properties>
  1. Then I copy that class under resource directory:
cp target/classes/org/eolang/jeo/MethodByte.class src/test/resources/.
  1. Finally I run tests and get the exception which I mention above.

Solution

  • As Johannes Kuhn mentioned, the binary representation of the original class didn't match the byte array passed into the org.objectweb.asm.ClassReader class. The root of the problem lies in the Maven Resource Filtering mechanism. To put it simply, Maven triggers the resources:3.3.1:testResources goal during the generate-test-sources phase, which replaces placeholders in resource files with actual values. When Maven attempts to apply this filtering to binary files, it can encounter encoding issues, leading to the exception I mentioned in my question.

    While the src/test/resources folder contained the correct bytecode, it was corrupted when I ran the tests (using mvn clean test command), subsequently causing the IllegalArgumentException.

    To address this, I excluded .class files from filtering:

    <build>
      <testResources>
        <testResource>
          <directory>src/test/resources</directory>
          <filtering>false</filtering>
          <includes>
            <include>**/*.class</include>
          </includes>
        </testResource>
      </testResources>
    </build>
    

    With this configuration, everything now works as expected without exceptions.