I am generating JVM bytecode in Krakatau syntax to load a large binary blob into a [B
. The point is to have all the actual data stored in the .class
file instead of reading it at runtime from an external source.
The code I have generated looks like this:
.method public static loadImage : ([B)V
.code stack 6 locals 1
aload_0
iconst_0
iconst_1
iadd
dup2
bipush 71
bastore
iconst_1
iadd
dup2
bipush 108
bastore
...
iconst_1
iadd
dup2
bipush 0
bastore
return
.end code
.end method
However, at runtime this method fails because it's too long:
Exception in thread "main" java.lang.ClassFormatError:
Invalid method Code length 572931 in class file Image
Is there a better way to load a large binary blob into a byte array? I guess one workaround would be to keep my current code, but split it into several methods, but that is quite horrible...
Put a static field on your class, which is statically initialised by reading a resource. I use Guava ByteStreams below, use any io utils you like though...
class MyClass {
static byte[] theData;
static {
try {
theData = ByteStreams.toByteArray(MyClass.class.getClassLoader().getResourceAsStream('/myBigResource.dat'))
} catch (IOException e) {
throw new RuntimeException(e);
}
}
...
}
You incur the cost of reading the secondary resource exactly once, at class loading time, but you would get that anyway even if you had the byte data embedded in your .class file. The only real extra cost you get is locating and opening that one extra resource, plus whatever object-interactions are involved in that.
The only real problem is the exception handling. If reading the resource throws an IOException that will appear in your program as a ClassNotFound exception, which can be confusing.
You also need to be aware that this is going to search your classpath for the resource file. Somebody could put a 'similarly' named file somewhere and create havoc. Particularly if it's a VeryLarge file.