如何以编程方式验证Java代码?

如何以编程方式验证Java代码?,java,java-compiler-api,javacompiler,Java,Java Compiler Api,Javacompiler,给定源代码和Java版本,我需要能够验证代码是否可以编译。如果代码没有编译,我需要能够返回源代码中的错误 以下解决方案有效,但仅适用于您的计算机上当前使用的Java版本 import javax.tools.*; import java.io.File; import java.io.IOException; import java.net.URI; import java.nio.file.Files; import java.util.ArrayList; import java.util.

给定源代码和Java版本,我需要能够验证代码是否可以编译。如果代码没有编译,我需要能够返回源代码中的错误

以下解决方案有效,但仅适用于您的计算机上当前使用的Java版本

import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class Validator {
    private final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler();
    
    //Assume srcFiles are java files that can be read
    public final boolean compiles(Set<File> srcFiles) throws IOException {

        //Convert files to JavaCompiler API compatible files
        List<JavaFileObject> compilationUnits = new ArrayList<>();
        for (File file : srcFiles) {
            CompilableFile compilableFile = new CompilableFile(file.getName(), Files.readString(file.toPath()));
            compilationUnits.add(compilableFile);
        }

        DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();
        JavaCompiler.CompilationTask task = COMPILER.getTask(null, null, diagnosticCollector, null, null, compilationUnits);
        boolean success = task.call();

        //Displaying the info of each warning, error, etc
        diagnosticCollector.getDiagnostics().forEach(Validator::printDiagnostic);

        return success;
    }

    private static void printDiagnostic(Diagnostic<?> diagnostic) {
        System.out.println(diagnostic.getCode());
        System.out.println(diagnostic.getKind());
        System.out.println(diagnostic.getPosition());
        System.out.println(diagnostic.getStartPosition());
        System.out.println(diagnostic.getEndPosition());
        System.out.println(diagnostic.getSource());
        System.out.println(diagnostic.getMessage(null));
    }

    /**
     * Instances of this class can be compiled with the JavaCompiler API
     */
    private static final class CompilableFile extends SimpleJavaFileObject {
        final String code;

        CompilableFile(String name, String code) {
            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return code;
        }
    }
}
import javax.tools.*;
导入java.io.File;
导入java.io.IOException;
导入java.net.URI;
导入java.nio.file.Files;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Set;
公共类验证器{
私有最终JavaCompiler编译器=ToolProvider.getSystemJavaCompiler();
//假设srcFiles是可以读取的java文件
公共最终布尔编译(Set srcFiles)引发IOException{
//将文件转换为与JavaCompiler API兼容的文件
List compilationUnits=new ArrayList();
用于(文件:srcFiles){
compileablefile compileablefile=新的可编译文件(file.getName(),Files.readString(file.toPath());
compilationUnits.add(可编译文件);
}
DiagnosticCollector DiagnosticCollector=新的DiagnosticCollector();
JavaCompiler.CompilationTask task=COMPILER.getTask(null,null,diagnosticCollector,null,null,compilationUnits);
布尔成功=task.call();
//显示每个警告、错误等的信息
diagnosticCollector.getDiagnostics().forEach(Validator::printDiagnostic);
回归成功;
}
专用静态无效打印诊断(诊断){
System.out.println(diagnostic.getCode());
System.out.println(diagnostic.getKind());
System.out.println(diagnostic.getPosition());
System.out.println(diagnostic.getStartPosition());
System.out.println(diagnostic.getEndPosition());
System.out.println(diagnostic.getSource());
System.out.println(diagnostic.getMessage(null));
}
/**
*这个类的实例可以用JavaCompilerAPI编译
*/
私有静态最终类CompileFile扩展SimpleJavaFileObject{
最终字符串代码;
可编译文件(字符串名称、字符串代码){
super(URI.create(“string://“+name.replace('.','/'))+Kind.SOURCE.extension)、Kind.SOURCE);
this.code=代码;
}
@凌驾
public CharSequence getCharContent(布尔ignoreEncodingErrors){
返回码;
}
}
}
我是否可以实现以下功能

public final boolean compiles(Set<File> srcFiles, SourceVersion version) {...}
public final boolean编译(Set srcFiles,SourceVersion版本){…}

此解决方案适用的版本范围似乎是特定于编译器的,但对于OpenJDK 11和15,我注意到此解决方案适用于[7,系统编译器版本]

JavaCompiler API允许您在调用方法
JavaCompiler.CompilationTask::getTask
时以
Iterable
的形式传递命令行选项,因此您可以传递
List.of(“--release”,”)
,其中
被您正在验证的版本替换

考虑到这一点,解决方案变得更加简单

import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class Validator {
    private final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler();
    
    //Assume srcFiles are java files that can be read
    public final boolean compiles(Set<File> srcFiles, String javaVersion) throws IOException {

        //Convert files to JavaCompiler API compatible files
        List<JavaFileObject> compilationUnits = new ArrayList<>();
        for (File file : srcFiles) {
            CompilableFile compilableFile = new CompilableFile(file.getName(), Files.readString(file.toPath()));
            compilationUnits.add(compilableFile);
        }

        DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();
        JavaCompiler.CompilationTask task = COMPILER.getTask(null, null, diagnosticCollector, List.of("--release", javaVersion), null, compilationUnits);
        boolean success = task.call();

        //Displaying the info of each warning, error, etc
        diagnosticCollector.getDiagnostics().forEach(Validator::printDiagnostic);

        return success;
    }

    private static void printDiagnostic(Diagnostic<?> diagnostic) {
        System.out.println(diagnostic.getCode());
        System.out.println(diagnostic.getKind());
        System.out.println(diagnostic.getPosition());
        System.out.println(diagnostic.getStartPosition());
        System.out.println(diagnostic.getEndPosition());
        System.out.println(diagnostic.getSource());
        System.out.println(diagnostic.getMessage(null));
    }

    /**
     * Instances of this class can be compiled with the JavaCompiler API
     */
    private static final class CompilableFile extends SimpleJavaFileObject {
        final String code;

        CompilableFile(String name, String code) {
            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return code;
        }
    }
}


import javax.tools.*;
导入java.io.File;
导入java.io.IOException;
导入java.net.URI;
导入java.nio.file.Files;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Set;
公共类验证器{
私有最终JavaCompiler编译器=ToolProvider.getSystemJavaCompiler();
//假设srcFiles是可以读取的java文件
公共最终布尔编译(Set srcFiles,String javaVersion)引发IOException{
//将文件转换为与JavaCompiler API兼容的文件
List compilationUnits=new ArrayList();
用于(文件:srcFiles){
compileablefile compileablefile=新的可编译文件(file.getName(),Files.readString(file.toPath());
compilationUnits.add(可编译文件);
}
DiagnosticCollector DiagnosticCollector=新的DiagnosticCollector();
JavaCompiler.CompilationTask task=COMPILER.getTask(null,null,diagnosticCollector,List.of(“--release”,javaVersion),null,compilationUnits);
布尔成功=task.call();
//显示每个警告、错误等的信息
diagnosticCollector.getDiagnostics().forEach(Validator::printDiagnostic);
回归成功;
}
专用静态无效打印诊断(诊断){
System.out.println(diagnostic.getCode());
System.out.println(diagnostic.getKind());
System.out.println(diagnostic.getPosition());
System.out.println(diagnostic.getStartPosition());
System.out.println(diagnostic.getEndPosition());
System.out.println(diagnostic.getSource());
System.out.println(diagnostic.getMessage(null));
}
/**
*这个类的实例可以用JavaCompilerAPI编译
*/
私有静态最终类CompileFile扩展SimpleJavaFileObject{
最终字符串代码;
可编译文件(字符串名称、字符串代码){
super(URI.create(“string://“+name.replace('.','/'))+Kind.SOURCE.extension)、Kind.SOURCE);
this.code=代码;
}
@凌驾
public CharSequence getCharContent(布尔ignoreEncodingErrors){
返回码;
}
}
}

请参见:。@Abra我不认为这有什么关系。我只是想验证代码,我不一定需要编译它,理论上我可以用Java9实现Java10编译器,然后用它来验证我的代码。即使如此,如果您有tools.jar文件,也可以使用Java 9编译Java 10代码。看见此外,如果我有一个Java 15编译器,它将无法验证它之前的所有Java代码,因为我可以为它提供一个有效的Java 15程序,该程序在以前的版本中无法工作。@Progman我的问题不是这种形式的吗?那么我该如何重新措辞呢?我看不出有别的方法可以问你怎么做