Given the source code and the Java version, I need to be able to validate whether or not the code will compile. If the code does not compile, I need to be able to return the errors within the source code.
The following solution works, but only for the Java version currently being used on your machine.
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;
}
}
}
Is there anyway I could implement the following function?
public final boolean compiles(Set<File> srcFiles, SourceVersion version) {...}
The range of version that this solution works on seem to be compiler specific, but for OpenJDK 11 and 15, I noticed this solution worked for [7, SYSTEM_COMPILER_VERSION]
The JavaCompiler API allows you to pass command line options as an
Iterable
when you call the methodJavaCompiler.CompilationTask::getTask
, so you can passList.of("--release", "<version>")
where<version>
is replaced by the version you are verifyingWith this in mind, the solution becomes