All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.plugin.compiler.CompilerMojo Maven / Gradle / Ivy

There is a newer version: 4.0.0-beta-2
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.maven.plugin.compiler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.utils.StringUtils;
import org.apache.maven.shared.utils.logging.MessageUtils;
import org.apache.maven.toolchain.Toolchain;
import org.apache.maven.toolchain.java.DefaultJavaToolChain;
import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
import org.codehaus.plexus.languages.java.jpms.LocationManager;
import org.codehaus.plexus.languages.java.jpms.ModuleNameSource;
import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;

/**
 * Compiles application sources
 *
 * @author Jason van Zyl 
 * @since 2.0
 */
@Mojo(
        name = "compile",
        defaultPhase = LifecyclePhase.COMPILE,
        threadSafe = true,
        requiresDependencyResolution = ResolutionScope.COMPILE)
public class CompilerMojo extends AbstractCompilerMojo {
    /**
     * The source directories containing the sources to be compiled.
     */
    @Parameter(defaultValue = "${project.compileSourceRoots}", readonly = false, required = true)
    private List compileSourceRoots;

    /**
     * The directory for compiled classes.
     */
    @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true)
    private File outputDirectory;

    /**
     * Projects main artifact.
     *
     * @todo this is an export variable, really
     */
    @Parameter(defaultValue = "${project.artifact}", readonly = true, required = true)
    private Artifact projectArtifact;

    /**
     * A list of inclusion filters for the compiler.
     */
    @Parameter
    private Set includes = new HashSet<>();

    /**
     * A list of exclusion filters for the compiler.
     */
    @Parameter
    private Set excludes = new HashSet<>();

    /**
     * A list of exclusion filters for the incremental calculation.
     * @since 3.11
     */
    @Parameter
    private Set incrementalExcludes = new HashSet<>();

    /**
     * 

* Specify where to place generated source files created by annotation processing. Only applies to JDK 1.6+ *

* * @since 2.2 */ @Parameter(defaultValue = "${project.build.directory}/generated-sources/annotations") private File generatedSourcesDirectory; /** * Set this to 'true' to bypass compilation of main sources. Its use is NOT RECOMMENDED, but quite convenient on * occasion. */ @Parameter(property = "maven.main.skip") private boolean skipMain; @Parameter(defaultValue = "${project.compileClasspathElements}", readonly = true, required = true) private List compilePath; /** *

* When set to {@code true}, the classes will be placed in META-INF/versions/${release} The release * value must be set, otherwise the plugin will fail. *

* Note: A jar is only a multirelease jar if META-INF/MANIFEST.MF contains * Multi-Release: true. You need to set this by configuring the maven-jar-plugin. * This implies that you cannot test a multirelease jar using the outputDirectory. * * @since 3.7.1 */ @Parameter private boolean multiReleaseOutput; /** * when forking and debug activated the commandline used will be dumped in this file * @since 3.10.0 */ @Parameter(defaultValue = "javac") private String debugFileName; final LocationManager locationManager = new LocationManager(); private List classpathElements; private List modulepathElements; private Map pathElements; protected List getCompileSourceRoots() { return compileSourceRoots; } @Override protected List getClasspathElements() { return classpathElements; } @Override protected List getModulepathElements() { return modulepathElements; } @Override protected Map getPathElements() { return pathElements; } protected File getOutputDirectory() { File dir; if (!multiReleaseOutput) { dir = outputDirectory; } else { dir = new File(outputDirectory, "META-INF/versions/" + release); } return dir; } public void execute() throws MojoExecutionException, CompilationFailureException { if (skipMain) { getLog().info("Not compiling main sources"); return; } if (multiReleaseOutput && release == null) { throw new MojoExecutionException("When using 'multiReleaseOutput' the release must be set"); } super.execute(); if (outputDirectory.isDirectory()) { projectArtifact.setFile(outputDirectory); } } @Override protected Set getIncludes() { return includes; } @Override protected Set getExcludes() { return excludes; } @Override protected void preparePaths(Set sourceFiles) { // assert compilePath != null; File moduleDescriptorPath = null; boolean hasModuleDescriptor = false; for (File sourceFile : sourceFiles) { if ("module-info.java".equals(sourceFile.getName())) { moduleDescriptorPath = sourceFile; hasModuleDescriptor = true; break; } } if (hasModuleDescriptor) { // For now only allow named modules. Once we can create a graph with ASM we can specify exactly the modules // and we can detect if auto modules are used. In that case, MavenProject.setFile() should not be used, so // you cannot depend on this project and so it won't be distributed. modulepathElements = new ArrayList<>(compilePath.size()); classpathElements = new ArrayList<>(compilePath.size()); pathElements = new LinkedHashMap<>(compilePath.size()); ResolvePathsResult resolvePathsResult; try { Collection dependencyArtifacts = getCompileClasspathElements(getProject()); ResolvePathsRequest request = ResolvePathsRequest.ofFiles(dependencyArtifacts) .setIncludeStatic(true) .setMainModuleDescriptor(moduleDescriptorPath); Toolchain toolchain = getToolchain(); if (toolchain instanceof DefaultJavaToolChain) { request.setJdkHome(new File(((DefaultJavaToolChain) toolchain).getJavaHome())); } resolvePathsResult = locationManager.resolvePaths(request); for (Entry pathException : resolvePathsResult.getPathExceptions().entrySet()) { Throwable cause = pathException.getValue(); while (cause.getCause() != null) { cause = cause.getCause(); } String fileName = pathException.getKey().getName(); getLog().warn("Can't extract module name from " + fileName + ": " + cause.getMessage()); } JavaModuleDescriptor moduleDescriptor = resolvePathsResult.getMainModuleDescriptor(); detectFilenameBasedAutomodules(resolvePathsResult, moduleDescriptor); for (Map.Entry entry : resolvePathsResult.getPathElements().entrySet()) { pathElements.put(entry.getKey().getPath(), entry.getValue()); } if (compilerArgs == null) { compilerArgs = new ArrayList<>(); } for (File file : resolvePathsResult.getClasspathElements()) { classpathElements.add(file.getPath()); if (multiReleaseOutput) { if (getOutputDirectory().toPath().startsWith(file.getPath())) { compilerArgs.add("--patch-module"); compilerArgs.add(String.format("%s=%s", moduleDescriptor.name(), file.getPath())); } } } for (File file : resolvePathsResult.getModulepathElements().keySet()) { modulepathElements.add(file.getPath()); } compilerArgs.add("--module-version"); compilerArgs.add(getProject().getVersion()); } catch (IOException e) { getLog().warn(e.getMessage()); } } else { classpathElements = new ArrayList<>(); for (File element : getCompileClasspathElements(getProject())) { classpathElements.add(element.getPath()); } modulepathElements = Collections.emptyList(); } } private void detectFilenameBasedAutomodules( final ResolvePathsResult resolvePathsResult, final JavaModuleDescriptor moduleDescriptor) { List automodulesDetected = new ArrayList<>(); for (Entry entry : resolvePathsResult.getModulepathElements().entrySet()) { if (ModuleNameSource.FILENAME.equals(entry.getValue())) { automodulesDetected.add(entry.getKey().getName()); } } if (!automodulesDetected.isEmpty()) { final String message = "Required filename-based automodules detected: " + automodulesDetected + ". " + "Please don't publish this project to a public artifact repository!"; if (moduleDescriptor.exports().isEmpty()) { // application getLog().info(message); } else { // library writeBoxedWarning(message); } } } private List getCompileClasspathElements(MavenProject project) { // 3 is outputFolder + 2 preserved for multirelease List list = new ArrayList<>(project.getArtifacts().size() + 3); if (multiReleaseOutput) { File versionsFolder = new File(project.getBuild().getOutputDirectory(), "META-INF/versions"); // in reverse order for (int version = Integer.parseInt(getRelease()) - 1; version >= 9; version--) { File versionSubFolder = new File(versionsFolder, String.valueOf(version)); if (versionSubFolder.exists()) { list.add(versionSubFolder); } } } list.add(new File(project.getBuild().getOutputDirectory())); for (Artifact a : project.getArtifacts()) { list.add(a.getFile()); } return list; } protected SourceInclusionScanner getSourceInclusionScanner(int staleMillis) { if (includes.isEmpty() && excludes.isEmpty() && incrementalExcludes.isEmpty()) { return new StaleSourceScanner(staleMillis); } if (includes.isEmpty()) { includes.add("**/*.java"); } Set excludesIncr = new HashSet<>(excludes); excludesIncr.addAll(this.incrementalExcludes); return new StaleSourceScanner(staleMillis, includes, excludesIncr); } protected SourceInclusionScanner getSourceInclusionScanner(String inputFileEnding) { // it's not defined if we get the ending with or without the dot '.' String defaultIncludePattern = "**/*" + (inputFileEnding.startsWith(".") ? "" : ".") + inputFileEnding; if (includes.isEmpty()) { includes.add(defaultIncludePattern); } Set excludesIncr = new HashSet<>(excludes); excludesIncr.addAll(excludesIncr); return new SimpleSourceInclusionScanner(includes, excludesIncr); } protected String getSource() { return source; } protected String getTarget() { return target; } @Override protected String getRelease() { return release; } protected String getCompilerArgument() { return compilerArgument; } protected Map getCompilerArguments() { return compilerArguments; } protected File getGeneratedSourcesDirectory() { return generatedSourcesDirectory; } @Override protected String getDebugFileName() { return debugFileName; } private void writeBoxedWarning(String message) { String line = StringUtils.repeat("*", message.length() + 4); getLog().warn(line); getLog().warn("* " + MessageUtils.buffer().strong(message) + " *"); getLog().warn(line); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy