Search code examples
javajavassistbytecode-manipulation

Javassist seems to generate invalid field access code


I am trying to augment some code with additional functionality during startup of my application. The whole setup itself is working fine, but there is one point where I think javassist might generate bad code.

I am doing this on a specific method on a specific class, I checked before that the return value is actually of type StringBuilder or StringBuffer.

ctMethod.insertAfter("$_.SOME_METHOD(); $_.SOME_FIELD = <...>;");

SOME_METHOD() and SOME_FIELD are both declared in AbstractStringBuilder, the superclass of StringBuilder and StringBuffer. Both are defined as public, java.lang.AbstractStringBuilder itself is only package-private.

The operation itself is successful, but execution of this code results in the error "java.lang.IllegalAccessError: tried to access class java.lang.AbstractStringBuilder from class <...>". With print-debugging I found out, that accessing the method works fine but accessing the field crashes.

So I checked the generated bytecode:

...
invokevirtual #41 <java/lang/StringBuilder.SOME_METHOD>
...
getfield #72 <java/lang/AbstractStringBuilder.SOME_FIELD>
...

So for accessing the method it resolves to StringBuilder itself, but for the field it resolves to AbstractStringBuilder which is not obviously not accessible from the location of the modified code. Btw, the decompiled bytecode looks just fine.

I am also accessing this field in my static code, so I checked the bytecode of this one:

...
getfield #37 <java/lang/StringBuilder.SOME_FIELD>
...

This is code compiled by default compiler and it does not use AbstractStringBuilder for reference.

So my question is: did I oversee something regarding the JVMs concepts of visibility and inheritance or does javassist not correctly resolves this? I hope, my explanation is understandable - otherwise let me know and I will try to enhance it.


Solution

  • This is an error in Javassist.

    Fields are not virtual, by naming another class, you really access a different (shadowed) field which needs to be accessible by the class in question.