1

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)
Community
  • 1
  • 1
ceekay
  • 481
  • 3
  • 13
  • 1
    Are you sure you can have more than 1 class per file? I didn't dive in into `InMemoryJavaCompiler` but by default there should be the only Class per file. – deathangel908 Jun 24 '15 at 09:38
  • 1
    As i know java only limits the public class per file to 1. The `InMemoryJavaCompiler` was just to show you my current position, as I try to solve this problem step-by-step. If there are other ways to my wished solution, I'm willing to switch it out – ceekay Jun 24 '15 at 09:41
  • have u considered using ant? – nafas Jun 24 '15 at 09:47
  • @nafas Maybe I missed something, but I'm not sure how Ant provides runtime compilation features, which could help in my case. It would be nice if you could explain your thought a bit more in detail – ceekay Jun 24 '15 at 09:56
  • @ceekay as I understood you case you want to compile a project (with multiple classes in different folders and etc) you could write a generalized ant builder (build.xml) to compile your project e.g. if your project style is like eclipse (src,lib and etc). then you can simply call ProcessBuilder for ant – nafas Jun 24 '15 at 10:01
  • @nafas Ok sry when it wasn't clear. I want to compile java classes dynamically in-memory, during runtime. Therefore i guess a general build.xml would do the job – ceekay Jun 24 '15 at 10:03
  • @ceekay lemme know if you need an example ant builder – nafas Jun 24 '15 at 10:23

1 Answers1

0

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.

Ripon Saha
  • 43
  • 6