In-memory compilation with more than one class per file

623 views Asked by At

First of all what i try to achieve:
I want to compile java classes dynamically in-memory, during runtime. Basically with the provided Java Compiler API thats not really big of a deal, but when it comes to multiple classes per .java file I'm lost.

What i got so far:
I'm currently working with the InMemoryJavaCompiler provided in an answer to this question (Compile code fully in memory with javax.tools.JavaCompiler)

As described above, the compilation of single classes per file is no problem, but I want to be able to compile pretty much any valid .java files.

For example the file (FileOne.java) I try to compile looks like this:

package test;
public class FileOne {
    public static void main(String args[]) {
        System.out.println("Hello, World");
    }
}
class Functions {
    public static int test(int x) {
        return -x;
    }
}

When i try to compile this file like InMemoryJavaCompiler.compile("test.FileOne", source), I get an Exception marking the defineClass(...) line in the overwritten ClassLoader that says:

java.lang.ClassFormatError: Extra bytes at the end of class file test/FileOne

This problem also exists with inner classes, but there it is only some kind of naming/calling problem, I guess:

java.lang.NoClassDefFoundError: test/FileOne (wrong name: test/FileOne$Functions)
1

There are 1 answers

0
Ripon Saha On

Yes, you are right that InMemoryJavaCompilation as-is currently available on github does not work if a class has inner or anonymous classes. I have experienced exactly the same problem that you described.

After a long searching I found JSCC which is very complete. Thanks to verhas (github user name) for developing it and making it available. I tested JSCC with nested classes and it works fine. You can find the code and how to use it on Github.

https://github.com/verhas/jscc

As far as I understood, the problem with InMemoryJavaCompilation is that it stores one byte array per class. However, compiler generates more than one classes for a class with nested classes or anonymous classes. In that case, InMemoryJavaCompilation stores only the last class returned by the compiler, and that may not be the top level class. Therefore, you may get java.lang.NoClassDefFoundError. JSCC maintains a Byte Array Map to keep the compiled code of all the classes.

Although you asked this question long time back, I hope this helps.