Dynamic Compilation in Memory for Java for classes and classes that have dependencies on those classes

2.4k views Asked by At

I have a List of class names and class source code. I need to compile in memory these classes so I can use them in the program. Compiling a class is fine, except when that class requires another class that has to be compiled. For example, if I have class A

package example;
public class A {
    public A() {
        doSomething();
    }
}

The class works fine, however if I have to compile this class after it:

package example;
public class B {
    private A holderForA;
    public B() {
        this.holderForA = new A();
    }
}

B will not successfully compile.

Here is my compilation code (code is the list of code mentioned before) with the two classes.

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
for(String key : code.keySet()) {
    CODE = code.get(key);
    NAME =  key;

    JavaFileObject file = new JavaSourceFromString(NAME, CODE);
    Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);
    System.out.println("The task completed: " + task.call() + " for " + NAME);
}

The first class returns true, the second returns false. If I set up multiple classes like A and B, A type classes work, B type classes fail. What do I do?

1

There are 1 answers

3
John Ericksen On

I believe your problem is in the JavaSourceFromString class, which needs to encode a URI for the class name:

@Test
public void test(){
    Map<String, String> code = new HashMap<String, String>();

    code.put("example.A",
            "package example;\n" +
                    "public class A {\n" +
                    "    public A() {\n" +
                    "        doSomething();\n" +
                    "    }\n" +
                    "}");

    code.put("example.B",
            "package example;\n" +
            "public class B {\n" +
            "    private A holderForA;\n" +
            "    public B() {\n" +
            "        this.holderForA = new A();\n" +
            "    }\n" +
            "}");

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
    List<JavaFileObject> compilationUnits = new ArrayList<JavaFileObject>();
    for(String key : code.keySet()) {
        String toCompile = code.get(key);
        JavaFileObject file = new Source(key, JavaFileObject.Kind.SOURCE, toCompile);
        compilationUnits.add(file);
    }
    JavaCompiler.CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);
    System.out.println(task.call()+diagnostics.getDiagnostics().toString()); //passes every time
}

public class Source extends SimpleJavaFileObject {
    private final String content;

    public Source(String name, Kind kind, String content) {
        super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind);
        this.content = content;
    }

    @Override
    public CharSequence getCharContent(boolean ignore) {
        return this.content;
    }
}