5454import java .util .jar .Attributes ;
5555import java .util .jar .JarFile ;
5656import java .util .jar .Manifest ;
57+ import java .util .stream .Stream ;
5758
5859import org .apache .maven .api .JavaPathType ;
60+ import org .apache .maven .api .Language ;
5961import org .apache .maven .api .PathScope ;
6062import org .apache .maven .api .PathType ;
6163import org .apache .maven .api .Project ;
6264import org .apache .maven .api .ProjectScope ;
6365import org .apache .maven .api .Session ;
66+ import org .apache .maven .api .SourceRoot ;
6467import org .apache .maven .api .Toolchain ;
6568import org .apache .maven .api .Type ;
6669import org .apache .maven .api .annotations .Nonnull ;
@@ -202,6 +205,15 @@ private Charset charset() {
202205 @ Parameter (property = "maven.compiler.enablePreview" , defaultValue = "false" )
203206 protected boolean enablePreview ;
204207
208+ /**
209+ * The root directories containing the source files to be compiled. If {@code null} or empty,
210+ * the directories will be obtained from the {@code <Source>} elements declared in the project.
211+ * If non-empty, the project {@code <Source>} elements are ignored. This configuration option
212+ * should be used only when there is a need to override the project configuration.
213+ */
214+ @ Parameter
215+ protected List <String > compileSourceRoots ;
216+
205217 /**
206218 * Additional arguments to be passed verbatim to the Java compiler. This parameter can be used when
207219 * the Maven compiler plugin does not provide a parameter for a Java compiler option. It may happen,
@@ -817,26 +829,20 @@ private Charset charset() {
817829 private String tipForCommandLineCompilation ;
818830
819831 /**
820- * {@code true} if this MOJO is for compiling tests, or {@code false} if compiling the main code.
832+ * {@code MAIN_COMPILE} if this MOJO is for compiling the main code,
833+ * or {@code TEST_COMPILE} if compiling the tests.
821834 */
822- final boolean isTestCompile ;
835+ final PathScope compileScope ;
823836
824837 /**
825838 * Creates a new MOJO.
826839 *
827- * @param isTestCompile {@code true} for compiling tests, or {@code false} for compiling the main code
840+ * @param compileScope {@code MAIN_COMPILE} or {@code TEST_COMPILE}
828841 */
829- protected AbstractCompilerMojo (boolean isTestCompile ) {
830- this .isTestCompile = isTestCompile ;
842+ protected AbstractCompilerMojo (PathScope compileScope ) {
843+ this .compileScope = compileScope ;
831844 }
832845
833- /**
834- * {@return the root directories of Java source files to compile}. If the sources are organized according the
835- * <i>Module Source Hierarchy</i>, then the list shall enumerate the root source directory for each module.
836- */
837- @ Nonnull
838- protected abstract List <Path > getCompileSourceRoots ();
839-
840846 /**
841847 * {@return the inclusion filters for the compiler, or an empty list for all Java source files}.
842848 * The filter patterns are described in {@link java.nio.file.FileSystem#getPathMatcher(String)}.
@@ -924,11 +930,13 @@ boolean hasModuleDeclaration(final List<SourceDirectory> roots) throws IOExcepti
924930 * The typical case is the compilation of tests, which depends on the main compilation outputs.
925931 * The default implementation does nothing.
926932 *
933+ * @param sourceDirectories the source directories
927934 * @param addTo where to add dependencies
928935 * @param hasModuleDeclaration whether the main sources have or should have a {@code module-info} file
929936 * @throws IOException if this method needs to walk through directories and that operation failed
930937 */
931- protected void addImplicitDependencies (Map <PathType , List <Path >> addTo , boolean hasModuleDeclaration )
938+ void addImplicitDependencies (
939+ List <SourceDirectory > sourceDirectories , Map <PathType , List <Path >> addTo , boolean hasModuleDeclaration )
932940 throws IOException {
933941 // Nothing to add in a standard build of main classes.
934942 }
@@ -939,10 +947,10 @@ protected void addImplicitDependencies(Map<PathType, List<Path>> addTo, boolean
939947 * options may be used) or the test classes (in which case the {@code --patch-module} option may be used).
940948 *
941949 * @param addTo the collection of source paths to augment
942- * @param compileSourceRoots the source paths to eventually adds to the {@code toAdd} map
950+ * @param sourceDirectories the source paths to eventually adds to the {@code toAdd} map
943951 * @throws IOException if this method needs to read a module descriptor and this operation failed
944952 */
945- void addSourceDirectories (Map <PathType , List <Path >> addTo , List <SourceDirectory > compileSourceRoots )
953+ void addSourceDirectories (Map <PathType , List <Path >> addTo , List <SourceDirectory > sourceDirectories )
946954 throws IOException {
947955 // No need to specify --source-path at this time, as it is for additional sources.
948956 }
@@ -1100,7 +1108,7 @@ protected Options acceptParameters(final OptionChecker compiler) {
11001108 compilerConfiguration .addIfNonBlank ("--source" , getSource ());
11011109 targetOrReleaseSet = compilerConfiguration .addIfNonBlank ("--target" , getTarget ());
11021110 targetOrReleaseSet |= compilerConfiguration .addIfNonBlank ("--release" , getRelease ());
1103- if (!targetOrReleaseSet && ! isTestCompile ) {
1111+ if (!targetOrReleaseSet && ProjectScope . MAIN . equals ( compileScope . projectScope ()) ) {
11041112 MessageBuilder mb = messageBuilderFactory
11051113 .builder ()
11061114 .a ("No explicit value set for --release or --target. "
@@ -1186,11 +1194,17 @@ private void compile(final JavaCompiler compiler, final Options compilerConfigur
11861194 */
11871195 List <SourceFile > sourceFiles = List .of ();
11881196 final Path outputDirectory = Files .createDirectories (getOutputDirectory ());
1189- final List <SourceDirectory > compileSourceRoots =
1190- SourceDirectory .fromPaths (getCompileSourceRoots (), outputDirectory );
1197+ final List <SourceDirectory > sourceDirectories ;
1198+ if (compileSourceRoots == null || compileSourceRoots .isEmpty ()) {
1199+ ProjectScope scope = compileScope .projectScope ();
1200+ Stream <SourceRoot > roots = projectManager .getEnabledSourceRoots (project , scope , Language .JAVA_FAMILY );
1201+ sourceDirectories = SourceDirectory .fromProject (roots , outputDirectory );
1202+ } else {
1203+ sourceDirectories = SourceDirectory .fromPluginConfiguration (compileSourceRoots , outputDirectory );
1204+ }
11911205 final boolean hasModuleDeclaration ;
11921206 if (incAspects .contains (IncrementalBuild .Aspect .MODULES )) {
1193- for (SourceDirectory root : compileSourceRoots ) {
1207+ for (SourceDirectory root : sourceDirectories ) {
11941208 if (root .moduleName == null ) {
11951209 throw new CompilationFailureException ("The <incrementalCompilation> value can be \" modules\" "
11961210 + "only if all source directories are Java modules." );
@@ -1205,7 +1219,7 @@ && getIncrementalExcludes().isEmpty())) {
12051219 hasModuleDeclaration = true ;
12061220 } else {
12071221 var filter = new PathFilter (getIncludes (), getExcludes (), getIncrementalExcludes ());
1208- sourceFiles = filter .walkSourceFiles (compileSourceRoots );
1222+ sourceFiles = filter .walkSourceFiles (sourceDirectories );
12091223 if (sourceFiles .isEmpty ()) {
12101224 String message = "No sources to compile." ;
12111225 try {
@@ -1224,7 +1238,7 @@ && getIncrementalExcludes().isEmpty())) {
12241238 hasModuleDeclaration = true ;
12251239 break ;
12261240 default :
1227- hasModuleDeclaration = hasModuleDeclaration (compileSourceRoots );
1241+ hasModuleDeclaration = hasModuleDeclaration (sourceDirectories );
12281242 break ;
12291243 }
12301244 }
@@ -1234,13 +1248,13 @@ && getIncrementalExcludes().isEmpty())) {
12341248 * and this MOJO is compiling the main code, then a warning will be logged.
12351249 *
12361250 * NOTE: this method assumes that the map and the list values are modifiable.
1237- * This is true with org.apache.maven.internal. impl.DefaultDependencyResolverResult,
1251+ * This is true with org.apache.maven.impl.DefaultDependencyResolverResult,
12381252 * but may not be true in the general case. To be safe, we should perform a deep copy.
12391253 * But it would be unnecessary copies in most cases.
12401254 */
12411255 final Map <PathType , List <Path >> dependencies = resolveDependencies (compilerConfiguration , hasModuleDeclaration );
12421256 resolveProcessorPathEntries (dependencies );
1243- addImplicitDependencies (dependencies , hasModuleDeclaration );
1257+ addImplicitDependencies (sourceDirectories , dependencies , hasModuleDeclaration );
12441258 /*
12451259 * Verify if a dependency changed since the build started, or if a source file changed since the last build.
12461260 * If there is no change, we can skip the build. If a dependency or the source tree has changed, we may
@@ -1305,7 +1319,7 @@ && getIncrementalExcludes().isEmpty())) {
13051319 * the `javax.tools.StandardLocation` API.
13061320 */
13071321 if (hasModuleDeclaration ) {
1308- addSourceDirectories (dependencies , compileSourceRoots );
1322+ addSourceDirectories (dependencies , sourceDirectories );
13091323 }
13101324 /*
13111325 * Create a `JavaFileManager`, configure all paths (dependencies and sources), then run the compiler.
@@ -1450,7 +1464,7 @@ && getIncrementalExcludes().isEmpty())) {
14501464 .append ("Cannot compile " )
14511465 .append (project .getId ())
14521466 .append (' ' )
1453- .append (isTestCompile ? "test" : "main" )
1467+ .append (compileScope . projectScope (). id () )
14541468 .append (" classes." );
14551469 listener .firstError (failureCause ).ifPresent ((c ) -> message .append (System .lineSeparator ())
14561470 .append ("The first error is: " )
@@ -1571,7 +1585,7 @@ private Map<PathType, List<Path>> resolveDependencies(Options compilerConfigurat
15711585 .session (session )
15721586 .project (project )
15731587 .requestType (DependencyResolverRequest .RequestType .RESOLVE )
1574- .pathScope (isTestCompile ? PathScope . TEST_COMPILE : PathScope . MAIN_COMPILE )
1588+ .pathScope (compileScope )
15751589 .pathTypeFilter (allowedTypes )
15761590 .build ());
15771591 /*
@@ -1597,7 +1611,7 @@ private Map<PathType, List<Path>> resolveDependencies(Options compilerConfigurat
15971611 throw (RuntimeException ) exception ; // A ClassCastException here would be a bug in above loop.
15981612 }
15991613 }
1600- if (! isTestCompile ) {
1614+ if (ProjectScope . MAIN . equals ( compileScope . projectScope ()) ) {
16011615 String warning = dependencies .warningForFilenameBasedAutomodules ().orElse (null );
16021616 if (warning != null ) { // Do not use Optional.ifPresent(…) for avoiding confusing source class name.
16031617 logger .warn (warning );
@@ -1619,7 +1633,7 @@ private Map<PathType, List<Path>> resolveDependencies(Options compilerConfigurat
16191633 * to the {@link JavaPathType#PROCESSOR_CLASSES} entry of given map, which should be modifiable.
16201634 *
16211635 * <h4>Implementation note</h4>
1622- * We rely on the fact that {@link org.apache.maven.internal. impl.DefaultDependencyResolverResult} creates
1636+ * We rely on the fact that {@link org.apache.maven.impl.DefaultDependencyResolverResult} creates
16231637 * modifiable instances of map and lists. This is a fragile assumption, but this method is deprecated anyway
16241638 * and may be removed in a future version.
16251639 *
@@ -1690,17 +1704,19 @@ private Set<Path> addGeneratedSourceDirectory(Path generatedSourcesDirectory) th
16901704 // `createDirectories(Path)` does nothing if the directory already exists.
16911705 generatedSourcesDirectory = Files .createDirectories (generatedSourcesDirectory );
16921706 }
1693- ProjectScope scope = isTestCompile ? ProjectScope . TEST : ProjectScope . MAIN ;
1694- projectManager .addCompileSourceRoot (project , scope , generatedSourcesDirectory .toAbsolutePath ());
1707+ ProjectScope scope = compileScope . projectScope () ;
1708+ projectManager .addSourceRoot (project , scope , Language . JAVA_FAMILY , generatedSourcesDirectory .toAbsolutePath ());
16951709 if (logger .isDebugEnabled ()) {
16961710 var sb = new StringBuilder ("Adding \" " )
16971711 .append (generatedSourcesDirectory )
16981712 .append ("\" to " )
16991713 .append (scope .id ())
17001714 .append ("-compile source roots. New roots are:" );
1701- for (Path p : projectManager .getCompileSourceRoots (project , scope )) {
1702- sb .append (System .lineSeparator ()).append (" " ).append (p );
1703- }
1715+ projectManager
1716+ .getEnabledSourceRoots (project , scope , Language .JAVA_FAMILY )
1717+ .forEach ((p ) -> {
1718+ sb .append (System .lineSeparator ()).append (" " ).append (p .directory ());
1719+ });
17041720 logger .debug (sb .toString ());
17051721 }
17061722 return Set .of (generatedSourcesDirectory );
0 commit comments