public boolean compile()

in src/main/java/org/apache/maven/plugin/compiler/ToolExecutor.java [491:624]


    public boolean compile(final JavaCompiler compiler, final Options configuration, final Writer otherOutput)
            throws IOException {
        /*
         * Announce what the compiler is about to do.
         */
        if (sourceFiles.isEmpty()) {
            String message = "No sources to compile.";
            try {
                Files.delete(outputDirectory);
            } catch (DirectoryNotEmptyException e) {
                message += " However, the output directory is not empty.";
            }
            logger.info(message);
            return true;
        }
        if (logger.isDebugEnabled()) {
            int n = sourceFiles.size();
            @SuppressWarnings("checkstyle:MagicNumber")
            var sb = new StringBuilder(n * 40).append("The source files to compile are:");
            for (SourceFile file : sourceFiles) {
                sb.append(System.lineSeparator()).append("    ").append(file);
            }
            logger.debug(sb);
        }
        /*
         * Create a `JavaFileManager`, configure all paths (dependencies and sources), then run the compiler.
         * The Java file manager has a cache, so it needs to be disposed after the compilation is completed.
         * The same `JavaFileManager` may be reused for many compilation units (e.g. multi-releases) before
         * disposal in order to reuse its cache.
         */
        boolean success = true;
        try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(listener, LOCALE, encoding)) {
            setDependencyPaths(fileManager);
            if (!generatedSourceDirectories.isEmpty()) {
                fileManager.setLocationFromPaths(StandardLocation.SOURCE_OUTPUT, generatedSourceDirectories);
            }
            boolean isVersioned = false;
            Path latestOutputDirectory = null;
            /*
             * More than one compilation unit may exist in the case of a multi-releases project.
             * Units are compiled in the order of the release version, with base compiled first.
             * At the beginning of each new iteration, `latestOutputDirectory` is the path to
             * the compiled classes of the previous version.
             */
            compile:
            for (final SourcesForRelease unit : groupByReleaseAndModule()) {
                Path outputForRelease = null;
                boolean isClasspathProject = false;
                boolean isModularProject = false;
                configuration.setRelease(unit.getReleaseString());
                for (final Map.Entry<String, Set<Path>> root : unit.roots.entrySet()) {
                    final String moduleName = inferModuleNameIfMissing(root.getKey());
                    if (moduleName.isEmpty()) {
                        isClasspathProject = true;
                    } else {
                        isModularProject = true;
                    }
                    if (isClasspathProject & isModularProject) {
                        throw new CompilationFailureException("Mix of modular and non-modular sources.");
                    }
                    final Set<Path> sourcePaths = root.getValue();
                    if (isClasspathProject) {
                        fileManager.setLocationFromPaths(StandardLocation.SOURCE_PATH, sourcePaths);
                    } else {
                        fileManager.setLocationForModule(StandardLocation.MODULE_SOURCE_PATH, moduleName, sourcePaths);
                    }
                    outputForRelease = outputDirectory; // Modified below if compiling a non-base release.
                    if (isVersioned) {
                        if (isClasspathProject) {
                            /*
                             * For a non-modular project, this block is executed at most once par compilation unit.
                             * Add the paths to the classes compiled for previous versions.
                             */
                            if (classpath == null) {
                                classpath = new ArrayList<>();
                            }
                            classpath.add(0, latestOutputDirectory);
                            fileManager.setLocationFromPaths(StandardLocation.CLASS_PATH, classpath);
                            outputForRelease = Files.createDirectories(
                                    SourceDirectory.outputDirectoryForReleases(outputForRelease, unit.release));
                        } else {
                            /*
                             * For a modular project, this block can be executed an arbitrary number of times
                             * (once per module).
                             * TODO: need to provide --patch-module. Difficulty is that we can specify only once.
                             */
                            throw new UnsupportedOperationException(
                                    "Multi-versions of a modular project is not yet implemented.");
                        }
                    } else {
                        /*
                         * This addition is for allowing AbstractCompilerMojo.writeDebugFile(…) to show those paths.
                         * It has no effect on the compilation performed in this method, because the dependencies
                         * have already been set by the call to `setDependencyPaths(fileManager)`.
                         */
                        if (!sourcePaths.isEmpty()) {
                            dependencies.put(SourcePathType.valueOf(moduleName), List.copyOf(sourcePaths));
                        }
                    }
                }
                fileManager.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Set.of(outputForRelease));
                latestOutputDirectory = outputForRelease;
                /*
                 * Compile the source files now. The following loop should be executed exactly once.
                 * It may be executed twice when compiling test classes overwriting the `module-info`,
                 * in which case the `module-info` needs to be compiled separately from other classes.
                 * However, this is a deprecated practice.
                 */
                JavaCompiler.CompilationTask task;
                for (CompilationTaskSources c : toCompilationTasks(unit)) {
                    Iterable<? extends JavaFileObject> sources = fileManager.getJavaFileObjectsFromPaths(c.files);
                    task = compiler.getTask(otherOutput, fileManager, listener, configuration.options, null, sources);
                    success = c.compile(task);
                    if (!success) {
                        break compile;
                    }
                }
                isVersioned = true; // Any further iteration is for a version after the base version.
            }
            /*
             * Post-compilation.
             */
            if (listener instanceof DiagnosticLogger diagnostic) {
                diagnostic.logSummary();
            }
        } catch (UncheckedIOException e) {
            throw e.getCause();
        }
        if (success && incrementalBuild != null) {
            incrementalBuild.writeCache();
            incrementalBuild = null;
        }
        return success;
    }