Using JavaFileManager to compile projects

I am currently creating a system that will allow the user to compile one or more projects. I did some research and decided to use the JavaCompilerAPI for this. I play with it, and I managed to collect separate java files and make a list of individual java files.

What I cannot do is get one java project, not to mention a group of them. I read somewhere that you can use the JavaFileManager to do this, and I read a little about it, but I can't find any examples of this, so I'm stuck.

This is what I have done so far:

public List doCompilation(String sourceCode, String locationOfFile) { List<String> compile = new ArrayList<>(); SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject(locationOfFile, sourceCode); JavaFileObject javaFileObjects[] = new JavaFileObject[]{fileObject}; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, Locale.getDefault(), null); Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects); String[] compileOptions = new String[]{"-d", "C:/projects/Compiler/TempBINfolder/bin"}; Iterable<String> compilationOptions = Arrays.asList(compileOptions); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics, compilationOptions, null, compilationUnits); boolean status = compilerTask.call(); if (!status) {//If compilation error occurs // Iterate through each compilation problem and print it for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { compile.add(diagnostic.getKind().toString()+" on line "+ diagnostic.getLineNumber() +"\nIn file: \n"+ diagnostic.toString()+"\n\n"); } } try { stdFileManager.close();//Close the file manager } catch (IOException e) { e.printStackTrace(); } return compile; } 

Does anyone know how to do this?

+4
source share
3 answers
+3
source

You can list the files (and directories recursively, if necessary) in the specified project directory and compile them one by one the way you do now.

+1
source

You need to include the output directory in the compiler path. Notice how I include targetDirectory in the classpath below:

 /** * Compiles Java source-code. * <p/> * @author Gili Tzabari */ public final class JavaCompiler { private List<Path> sourcePath = new ArrayList<>(); private List<Path> classPath = new ArrayList<>(); private final Set<DebugType> debugOptions = new HashSet<>(Arrays.asList(DebugType.LINES, DebugType.SOURCE, DebugType.VARIABLES)); /** * Sets the compiler classpath. * <p/> * @param sourcePath the paths to search for the source format of dependent classes * @throws NullPointerException if sourcePath is null * @throws IllegalArgumentException if sourcePath refers to a non-existent path or a non-directory * @return the JavaCompiler */ public JavaCompiler sourcePath(List<Path> sourcePath) { Preconditions.checkNotNull(sourcePath, "sourcePath may not be null"); for (Path path: sourcePath) { if (!Files.exists(path)) { throw new IllegalArgumentException("sourcePath refers to non-existant path: " + path. toAbsolutePath()); } if (!Files.isDirectory(path)) { throw new IllegalArgumentException("sourcePath refers to a non-directory: " + path. toAbsolutePath()); } } this.sourcePath = ImmutableList.copyOf(sourcePath); return this; } /** * Sets the compiler classpath. * <p/> * @param classPath the paths to search for the compiled format of dependent classes * @throws NullPointerException if classPath is null * @throws IllegalArgumentException if classPath refers to a non-existent path * @return the JavaCompiler */ public JavaCompiler classPath(List<Path> classPath) { Preconditions.checkNotNull(classPath, "classPath may not be null"); for (Path path: classPath) { if (!Files.exists(path)) { throw new IllegalArgumentException("classPath refers to non-existant path: " + path. toAbsolutePath()); } } this.classPath = ImmutableList.copyOf(classPath); return this; } /** * Indicates the kind of debugging information the generated files should contain. * <p/> * @param debugOptions the kind of debugging information the generated files should contain. By * default all debugging information is generated. * @return the JavaCompiler object */ public JavaCompiler debug(DebugType... debugOptions) { this.debugOptions.clear(); this.debugOptions.addAll(Arrays.asList(debugOptions)); return this; } /** * Compiles the source code. * <p/> * @param sourceFiles the source files to compile * @param targetDirectory the directory to compile into. This path included in the compiler * classpath. * @throws IllegalArgumentException if sourceFiles, targetDirectory are null; or if sourceFiles * refers to a non-existent file or a non-file; or if targetDirectory is not a directory * @throws CompilationException if the operation fails */ public void run(final Collection<Path> sourceFiles, final Path targetDirectory) throws IllegalArgumentException, CompilationException { if (sourceFiles == null) throw new IllegalArgumentException("sourceFiles may not be null"); if (sourceFiles.isEmpty()) return; for (Path file: sourceFiles) { if (!Files.exists(file)) { throw new IllegalArgumentException("sourceFiles refers to a non-existant file: " + file.toAbsolutePath()); } if (!Files.isRegularFile(file)) { throw new IllegalArgumentException("sourceFiles refers to a non-file: " + file.toAbsolutePath()); } } if (targetDirectory == null) throw new IllegalArgumentException("targetDirectory may not be null"); if (!Files.exists(targetDirectory)) { throw new IllegalArgumentException("targetDirectory must exist: " + targetDirectory. toAbsolutePath()); } if (!Files.isDirectory(targetDirectory)) { throw new IllegalArgumentException("targetDirectory must be a directory: " + targetDirectory. toAbsolutePath()); } Set<Path> uniqueSourceFiles = ImmutableSet.copyOf(sourceFiles); Set<Path> uniqueSourcePath = ImmutableSet.copyOf(sourcePath); final javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { throw new AssertionError("javax.tools.JavaCompiler is not available. Is tools.jar missing " + "from the classpath?"); } final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); Iterable<? extends JavaFileObject> compilationUnits; try { Set<File> modifiedFiles = getModifiedFiles(uniqueSourceFiles, uniqueSourcePath, targetDirectory, new HashSet<Path>()); if (modifiedFiles.isEmpty()) return; compilationUnits = fileManager.getJavaFileObjectsFromFiles(modifiedFiles); } catch (IOException e) { throw new CompilationException(e); } final List<Path> effectiveClasspath = new ArrayList<>(); effectiveClasspath.add(targetDirectory); effectiveClasspath.addAll(classPath); final List<String> options = new ArrayList<>(); options.add("-cp"); options.add(Joiner.on(File.pathSeparatorChar).join(effectiveClasspath)); final StringBuilder debugLine = new StringBuilder("-g:"); for (DebugType type: debugOptions) { switch (type) { case LINES: { debugLine.append("lines,"); break; } case SOURCE: { debugLine.append("source,"); break; } case VARIABLES: { debugLine.append("vars,"); break; } default: throw new AssertionError(type); } } if (!debugOptions.isEmpty()) { debugLine.deleteCharAt(debugLine.length() - ",".length()); options.add(debugLine.toString()); } if (!uniqueSourcePath.isEmpty()) { options.add("-sourcepath"); options.add(Joiner.on(File.pathSeparatorChar).join(uniqueSourcePath)); } options.add("-s"); options.add(targetDirectory.toString()); options.add("-d"); options.add(targetDirectory.toString()); final Writer output = null; final CompilationTask task = compiler.getTask(output, fileManager, diagnostics, options, null, compilationUnits); final boolean result = task.call(); try { printDiagnostics(diagnostics, options, sourceFiles); } catch (IOException e) { throw new BuildException(e); } if (!result) throw new CompilationException(); try { fileManager.close(); } catch (IOException e) { throw new BuildException(e); } } /** * Returns the java source-code file corresponding to a class name. * <p/> * @param className the fully-qualified class name to look up * @param sourcePath the source-code search path * @return null if no match was found */ private static File getJavaSource(String className, Set<File> sourcePath) { // TODO: check for class files instead of source for (File path: sourcePath) { File result = classNameToFile(path, className); if (!result.exists()) continue; return result; } return null; } /** * Converts a class name to its source-code file. * <p/> * @param sourcePath the source-code search path * @param className the fully-qualified class name * @return the source-code file */ private static File classNameToFile(File sourcePath, String className) { return new File(sourcePath, className.replace(".", "/") + ".java"); } /** * Displays any compilation errors. * <p/> * @param diagnostics the compiler diagnostics * @param options the command-line options passed to the compiler * @param sourceFiles the source files to compile * @throws IOException if an I/O error occurs */ private void printDiagnostics(final DiagnosticCollector<JavaFileObject> diagnostics, final List<String> options, final Collection<Path> sourceFiles) throws IOException { Logger log = LoggerFactory.getLogger(JavaCompiler.class.getName() + ".stderr"); int errors = 0; int warnings = 0; boolean firstTime = true; for (Diagnostic<? extends JavaFileObject> diagnostic: diagnostics.getDiagnostics()) { if (firstTime) { firstTime = false; StringBuilder message = new StringBuilder(); message.append("Invoking: javac "); for (String token: options) message.append(token).append(" "); message.append(Joiner.on(" ").join(sourceFiles)); log.debug(message.toString()); } JavaFileObject source = diagnostic.getSource(); if (source == null) log.error(diagnostic.getMessage(null)); else { StringBuilder message = new StringBuilder(); message.append(source.getName()); if (diagnostic.getLineNumber() != Diagnostic.NOPOS) message.append(":").append(diagnostic.getLineNumber()); message.append(": ").append(diagnostic.getMessage(null)); log.error(message.toString()); try (BufferedReader reader = new BufferedReader(new InputStreamReader(source.openInputStream()))) { String line = null; for (long lineNumber = 0, size = diagnostic.getLineNumber(); lineNumber < size; ++lineNumber) { line = reader.readLine(); if (line == null) break; } if (line != null) { log.error(line); message = new StringBuilder(); for (long i = 1, size = diagnostic.getColumnNumber(); i < size; ++i) message.append(" "); message.append("^"); log.error(message.toString()); } } } switch (diagnostic.getKind()) { case ERROR: { ++errors; break; } case NOTE: case OTHER: case WARNING: case MANDATORY_WARNING: { ++warnings; break; } default: throw new AssertionError(diagnostic.getKind()); } } if (errors > 0) { StringBuilder message = new StringBuilder(); message.append(errors).append(" error"); if (errors > 1) message.append("s"); log.error(message.toString()); } if (warnings > 0) { StringBuilder message = new StringBuilder(); message.append(warnings).append(" warning"); if (warnings > 1) message.append("s"); log.warn(message.toString()); } } /** * Returns the source-code files that have been modified. * <p/> * @param sourceFiles the source files to process * @param sourcePath the source file search path * @param targetDirectory the directory to compile into * @param unmodifiedFiles files that are known not to have been modified * @return all changed source-code files that are accepted by the filter * @throws IOException if an I/O error occurs */ private Set<File> getModifiedFiles(final Set<Path> sourceFiles, final Set<Path> sourcePath, final Path targetDirectory, final Set<Path> unmodifiedFiles) throws IOException { // TODO: Right now all files are assumed to have been modified Set<File> result = new HashSet<>(); for (Path path: sourceFiles) result.add(path.toFile()); return result; } /** * Returns the command-line representation of the object. * <p/> * @param sourceFiles the source files to compile * @param targetDirectory the directory to compile into * @param sourcePath the source file search path * @return the command-line representation of the object * @throws IllegalArgumentException if the classpath contains non-file components * @throws IOException if an I/O error occurs */ private List<String> toCommandLine(final Collection<Path> sourceFiles, final Path targetDirectory, final Collection<Path> sourcePath) throws IOException { final List<String> result = Lists.newArrayList("javac"); if (!classPath.isEmpty()) { result.add("-cp"); try { final StringBuilder line = new StringBuilder(); for (final Iterator<Path> i = classPath.iterator(); i.hasNext();) { line.append(i.next().getParent().toString()); if (i.hasNext()) line.append(File.pathSeparatorChar); } result.add(line.toString()); } catch (IllegalArgumentException e) { // Occurs if URL does not refer to a file throw new IllegalStateException(e); } } for (File javaFile: getModifiedFiles(ImmutableSet.copyOf(sourceFiles), ImmutableSet.copyOf(sourcePath), targetDirectory, new HashSet<Path>())) { result.add(javaFile.getPath()); } result.add("-d"); result.add(targetDirectory.getParent().toString()); return result; } @Override public String toString() { return getClass().getName() + "[classPath=" + classPath + "]"; } /** * The type of debugging information that generated files may contain. * <p/> * @author Gili Tzabari */ @SuppressWarnings("PublicInnerClass") public enum DebugType { /** * No debugging information. */ NONE, /** * Line number information. */ LINES, /** * Local variable information. */ VARIABLES, /** * Source file information. */ SOURCE } } 
+1
source

Source: https://habr.com/ru/post/1415624/


All Articles