2

I am learing Java Compiler API recently and I write some code that can compile one simple java source code file into a class file, but it can't compile a source code file which refer another class in other source code file. Below is my code:

public static void main(String[] args) throws IOException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        Path path = Paths.get("demo/Test2.java");
        File sourceFile = path.toFile();
        // set compiler's classpath to be same as the runtime's
        String classpath = System.getProperty("java.class.path");
        optionList.addAll(Arrays.asList("-classpath", classpath));
        optionList = Arrays.asList("-d", "demo_class");
        try (StandardJavaFileManager fileManager =
                compiler.getStandardFileManager(null, null, null)) {
            Iterable<? extends JavaFileObject> fileObjects =
                    fileManager.getJavaFileObjects(sourceFile);
            JavaCompiler.CompilationTask task =
                    compiler.getTask(null, null, null, options, null, fileObjects);
            Boolean result = task.call();
            if (result == null || !result.booleanValue()) {
                throw new RuntimeException(
                        "Compilation failed. class file path:" + sourceFile.getPath());
            }
        }
    }

demo/Test.java:

public class Test1 {}

demo/Test2.java:

public class Test2 extends Test1{
    public static void main(String[] args) {
        System.out.println("Test2 compiled.");
    }
}

The output:

demo/Test2.java:2: error: cannot find symbol
public class Test2 extends Test1{
                           ^
  symbol: class Test1
1 error
Exception in thread "main" java.lang.RuntimeException: Compilation failed. class file path:demo/Test2.java
    at test.DynamicCompile.main(DynamicCompile.java:28)

My question is how to make the compiler know class Test1 is in file Test1.java and this file is in the same source code folder as Test2.java so that it can compile recursively?

1 Answer 1

0

You should pass both classes as input

public static void main(String[] args) throws IOException {
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    List<String> sources = Arrays.asList(new String[] {"demo/Test2.java", "demo/Test1.java"});
    // set compiler's classpath to be same as the runtime's
    String classpath = System.getProperty("java.class.path");
    List<String> optionList = new ArrayList<>();
    optionList.addAll(Arrays.asList("-classpath", classpath));
    optionList = Arrays.asList("-d", "demo_class");
    try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {
        Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjectsFromStrings(sources);
        JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, optionList, null, fileObjects);
        Boolean result = task.call();
        if (result == null || !result) {
            throw new RuntimeException(
                    "Compilation failed. class file path:" + fileObjects);
        }
    }catch (Exception e){
        e.printStackTrace();

    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is there a way I can just set a source code file folder for the compiler and tell the compiler to compile Test2.java, then the compiler can find out it need to compile Test1.java file first?
You can list all files from that folder and pass it to compiler. If you create that files not by hand, you also can look at ASM asm.ow2.org/doc/tutorial-asm-2.0.html maybe it better will suit your needs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.