如何指定JavaCompiler的执行工作目录?
如何让javax.tools.JavaCompiler在指定目录执行编译
问题描述
我正在使用javax.tools.JavaCompiler通过运行中的Java应用程序以编程方式编译Java代码。目前功能正常,但不知道如何让编译器在当前应用的执行目录之外运行。我误以为javac和JavaCompiler只能使用相对路径,无法在运行时未知目标文件夹相对路径的情况下引用其他文件夹的内容。
我的文件夹结构:
root | |--- f1 <-- Java应用程序运行目录 | |--- f2 <-- 需要编译的代码所在目录
在终端里只需cd到f2就能操作,但不知道怎么用JavaCompiler实现同样效果。尝试过设置源代码路径,但路径似乎只能相对于应用运行位置生效,用--module-source-path=../f2不够健壮,希望能指定JavaCompiler在特定目录执行并以此为基准操作。
解决方案
JavaCompiler完全支持绝对路径,你之前的误解是核心问题。此外,还可以通过StandardJavaFileManager配置编译器的基准目录,实现类似cd到目标目录的效果。
方法1:直接使用绝对路径指定源文件与编译选项
直接用绝对路径指向f2目录下的源文件,同时给编译器选项(如模块源路径、输出目录)设置绝对路径,无需依赖相对路径:
import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.File; import java.util.List; public class SOQ_20240225 { public static void main(final String[] args) throws Exception { final JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); final StandardJavaFileManager fileManager = javac.getStandardFileManager(null, null, null); // 替换为f2目录的绝对路径,比如"/home/user/root/f2" File f2Dir = new File("/path/to/root/f2"); // 获取f2目录下的目标Java源文件 Iterable<? extends JavaFileObject> sourceFiles = fileManager.getJavaFileObjectsFromFiles( List.of(new File(f2Dir, "YourModule.java"), new File(f2Dir, "YourClass.java")) ); // 用绝对路径设置编译选项 List<String> compilerOptions = List.of( "--module-source-path=" + f2Dir.getAbsolutePath(), "-d", "/path/to/root/compiled-output" // 输出目录也用绝对路径 ); // 执行编译任务 var compilationTask = javac.getTask(null, fileManager, null, compilerOptions, null, sourceFiles); compilationTask.call(); fileManager.close(); } }
方法2:配置StandardJavaFileManager的基准位置
通过setLocation方法给文件管理器设置源路径的根目录,后续指定源文件时可直接使用基于该目录的相对路径:
import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaFileObject; import java.io.File; import java.util.List; public class SOQ_20240225 { public static void main(final String[] args) throws Exception { final JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); final StandardJavaFileManager fileManager = javac.getStandardFileManager(null, null, null); // 设置源路径的根目录为f2的绝对路径 File f2Dir = new File("/path/to/root/f2"); fileManager.setLocation(javax.tools.StandardLocation.SOURCE_PATH, List.of(f2Dir)); // 直接指定f2目录下的源文件名(无需前缀路径) Iterable<? extends JavaFileObject> sourceFiles = fileManager.getJavaFileObjects("YourModule.java", "YourClass.java"); // 编译选项按需设置,可继续使用绝对路径 List<String> compilerOptions = List.of( "-d", "/path/to/root/compiled-output" ); var compilationTask = javac.getTask(null, fileManager, null, compilerOptions, null, sourceFiles); compilationTask.call(); fileManager.close(); } }
关键说明
JavaCompiler和javac命令一样完全支持绝对路径,无需局限于相对路径,这是解决问题的核心。- 如果需要动态获取f2的绝对路径,可以通过当前运行目录推导:
new File(System.getProperty("user.dir")).getParentFile() + "/f2"(user.dir对应应用运行目录f1的绝对路径),避免硬编码路径。
内容的提问来源于stack exchange,提问作者davidalayachew
相关产品推荐
相关产品推荐

