簡體   English   中英

如何以編程方式驗證 Java 代碼?

[英]How to validate Java code programatically?

給定源代碼和 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;
        }
    }
}

無論如何我可以實現以下功能嗎?

public final boolean compiles(Set<File> srcFiles, SourceVersion version) {...}

此解決方案適用的版本范圍似乎是特定於編譯器的,但對於 OpenJDK 11 和 15,我注意到此解決方案適用於 [7, SYSTEM_COMPILER_VERSION]

JavaCompiler API 允許您在調用方法JavaCompiler.CompilationTask::getTask時將命令行選項作為Iterable傳遞,因此您可以傳遞List.of("--release", "<version>")其中<version>是替換為您正在驗證的版本

考慮到這一點,解決方案變成

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;
        }
    }
}


暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM