使用JavaCompiler 编译 Java 类文件

      从1.6版本的JDK开始,JDK提供了标准的包(javax.tools)可以方便的调用JVM的编译器,可以方便的通过JVM的编译器来编译java源文件。
   JDK提供的调用接口是JavaCompiler类,该类及CompilerAPI相关类在JDK的tools.jar包中。
   
   注意:在开发过程中由于使用的开发工具(IntelliJ IDEA或Eclipse)默认加载jdk包中的jre下的lib中的jar,请检查是否将lib下的tool.jar引入,
        如果没有引用将导致ClassNotFoundException异常

编译java文件demo

 /**
     * 编译java文件,使用StandardJavaFileManager编译Java源程式
     * @param encoding 编译编码
     * @param filePath 文件或者目录(若为目录,自动递归编译)
     * @param diagnostics 存放编译过程中的错误信息
     * @return
     * @throws Exception
     */
    public boolean compiler(String encoding, String filePath,String outputFile, DiagnosticCollector<JavaFileObject> diagnostics)  throws Exception{

        String sourceDir=filePath;//java源文件存放目录
        String targetDir="";//编译后class类文件存放目录

        // 获取编译器实例
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 获取标准文件管理器实例
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, Charset.forName(encoding));
        try {
            //得到编译关联的jar
            List<File> jars = new ArrayList<File>();
            getJarFiles(new File(filePath),jars);
            // 得到filePath目录下的所有java源文件
            File sourceFile = new File(sourceDir);
            List<File> sourceFileList = new ArrayList<File>();
            getSourceFiles(sourceFile, sourceFileList);
            // 没有java文件,直接返回
            if (sourceFileList.size() == 0) {
                System.out.println(sourceDir + "目录下查找不到任何java文件");
                return false;
            }
            //加载依赖的jar文件和依赖的class文件
            List<File> dependencies = new ArrayList<File>();
            dependencies.addAll(jars);
            //dependencies.addAll(sourceFileList);
            fileManager.setLocation(StandardLocation.CLASS_PATH,dependencies);
            fileManager.setLocation(StandardLocation.SOURCE_PATH,sourceFileList);
            //编译后输出的地址
            fileManager.setLocation(StandardLocation.CLASS_OUTPUT,Arrays.asList(new File[]{new File(outputFile)}));

            // 获取要编译的编译单元
            Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFileList);
            /**
             * 编译选项,在编译java文件时,编译程序会自动的去寻找java文件引用的其他的java源文件或者class。
             * -sourcepath选项就是定义java源文件的查找目录,有时我们编译一个Java源程式文件,而这个源程式文件需要另几个Java文件,
             *            而这些Java文件又在另外一个目录,那么这就需要为编译器指定这些文件所在的目录。
             * -classpath选项就是定义class文件的查找目录。
             * -d 是用来指定存放编译生成的.class文件的路径
             */
            //Iterable<String> options = Arrays.asList("-encoding", encoding, "-classpath", jars.toString(), "-d", targetDir, "-sourcepath", sourceDir);
            Iterable<String> options = Arrays.asList("-encoding", encoding,"-source","1.8");
            JavaCompiler.CompilationTask compilationTask = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);
            //运行编译任务
            return compilationTask.call();
        }finally {
            fileManager.close();
        }
    }

查找该目录下的所有的java文件

    private void getSourceFiles(File sourceFile, List<File> sourceFileList) throws Exception {
        if (sourceFile.exists() && sourceFileList != null) {//文件或者目录必须存在
            if (sourceFile.isDirectory()) {// 若file对象为目录
                File[] childrenFiles=sourceFile.listFiles((pathname->{
                    if (pathname.isDirectory()) {
                        return true;
                    }else{
                        String name = pathname.getName();
                        if (name.endsWith(".java") ? true : false) {
                            return true;
                        }
                        return false;
                    }
                }));
                // 递归调用
                for (File childFile : childrenFiles) {
                    getSourceFiles(childFile, sourceFileList);
                }
            }else{
                //若file对象为文件
                String name = sourceFile.getName();
                if (name.endsWith(".java") ? true : false) {
                    //System.out.println(sourceFile.getAbsolutePath());
                    sourceFileList.add(sourceFile);
                }
            }
        }
    }

递归查找该目录下的所有的jar文件

private void getJarFiles(File jarFile,List<File> jars) throws Exception {
        if (jarFile.exists() && jarFile != null) {//文件或者目录必须存在
            if (jarFile.isDirectory()) {// 若file对象为目录
                File[] childrenFiles= jarFile.listFiles((pathname) -> {
                        if (pathname.isDirectory()) {
                            return true;
                        } else {
                            String name = pathname.getName();
                            if (name.endsWith(".jar") ? true : false) {
                                return true;
                            }
                            return false;
                        }
                    });
                // 递归调用
                for (File childFile : childrenFiles) {
                    getJarFiles(childFile, jars);
                }
            }else{
                String name = jarFile.getName();
                if (name.endsWith(".jar") ? true : false) {
                   // System.out.println(jarFile.getAbsolutePath());
                    jars.add(jarFile);
                }
            }
        }
    }

调用

public static void main(String[] objs){
   DynamicCompilerTool tool = new DynamicCompilerTool();
   String outputFile = target.getAbsolutePath()+File.separator+"WebContent"+File.separator+"WEB-INF"+File.separator+"classes";
   File cls=new File(outputFile);
   if(!cls.exists()){
        cls.mkdir();
    }
    String encoding = "utf-8";
    boolean b = tool.compiler(encoding, javaProject.getAbsolutePath(), outputFile, diagnostics);
     if(!b){
	    StringJoiner rs=new StringJoiner(System.getProperty("line.separator"));
	       for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
	           rs.add(String.format("%s:%s[line %d column %d]-->%s%n", diagnostic.getKind(), diagnostic.getSource(), diagnostic.getLineNumber(),
	                   diagnostic.getColumnNumber(),
	                   diagnostic.getMessage(null)));
	      System.out.println("编译失败,原因:"+rs.toString());
	}else{
	   System.out.println("编译成功");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值