ascheman commented on code in PR #11505:
URL: https://github.com/apache/maven/pull/11505#discussion_r2642161285


##########
impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java:
##########
@@ -700,12 +709,27 @@ private void initProject(MavenProject project, 
ModelBuilderResult result) {
                 if (!hasTest) {
                     
project.addTestCompileSourceRoot(build.getTestSourceDirectory());
                 }
-                for (Resource resource : 
project.getBuild().getDelegate().getResources()) {
-                    project.addSourceRoot(new DefaultSourceRoot(baseDir, 
ProjectScope.MAIN, resource));
-                }
-                for (Resource resource : 
project.getBuild().getDelegate().getTestResources()) {
-                    project.addSourceRoot(new DefaultSourceRoot(baseDir, 
ProjectScope.TEST, resource));
-                }
+                // Extract modules from sources to detect modular projects
+                Set<String> modules = extractModules(sources);
+                boolean isModularProject = !modules.isEmpty();
+
+                logger.debug(

Review Comment:
   Changed to trace level in d2ce972700. This keeps the logs for detailed 
debugging while removing them from the `-X` output. Trace level requires 
explicit configuration via system properties.



##########
impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java:
##########
@@ -1099,6 +1123,193 @@ public Set<Entry<K, V>> entrySet() {
         }
     }
 
+    /**
+     * Context object for resource handling configuration.
+     * Groups parameters shared between main and test resource handling to 
reduce method parameter count.
+     */
+    private record ResourceHandlingContext(
+            MavenProject project,
+            Path baseDir,
+            Set<String> modules,
+            boolean modularProject,
+            ModelBuilderResult result) {}
+
+    /**
+     * Handles resource configuration for a given scope (main or test).
+     * This method applies the resource priority rules:
+     * <ol>
+     *   <li>Modular project: use resources from {@code <sources>} if present, 
otherwise inject defaults</li>
+     *   <li>Classic project: use resources from {@code <sources>} if present, 
otherwise use legacy resources</li>
+     * </ol>
+     *
+     * @param context the resource handling context containing project info
+     * @param resources the legacy resource list (from {@code <resources>} or 
{@code <testResources>})
+     * @param hasResourcesInSources whether resources are configured via 
{@code <sources>}
+     * @param scope the project scope (MAIN or TEST)
+     */
+    private void handleResourceConfiguration(
+            ResourceHandlingContext context,
+            List<Resource> resources,
+            boolean hasResourcesInSources,
+            ProjectScope scope) {
+
+        String scopeId = scope.id();
+        String scopeName = scope == ProjectScope.MAIN ? "Main" : "Test";
+        String legacyElement = scope == ProjectScope.MAIN ? "<resources>" : 
"<testResources>";
+        String sourcesConfig = scope == ProjectScope.MAIN
+                ? "<source><lang>resources</lang></source>"
+                : "<source><lang>resources</lang><scope>test</scope></source>";
+
+        if (context.modularProject()) {
+            if (hasResourcesInSources) {
+                // Modular project with resources configured via <sources> - 
already added above
+                if (hasExplicitLegacyResources(resources, context.baseDir(), 
scopeId)) {
+                    logger.warn(
+                            "Legacy {} element is ignored because {} resources 
are configured via {} in <sources>",
+                            legacyElement,
+                            scopeId,
+                            sourcesConfig);
+                }
+                logger.debug(
+                        "{} resources configured via <sources> element, 
ignoring legacy {} element",
+                        scopeName,
+                        legacyElement);
+            } else {
+                // Modular project without resources in <sources> - inject 
module-aware defaults
+                if (hasExplicitLegacyResources(resources, context.baseDir(), 
scopeId)) {
+                    String message = "Legacy " + legacyElement
+                            + " element is ignored because modular sources are 
configured. "
+                            + "Use " + sourcesConfig + " in <sources> for 
custom resource paths.";
+                    logger.warn(message);
+                    context.result()
+                            .getProblemCollector()
+                            .reportProblem(new 
org.apache.maven.impl.model.DefaultModelProblem(
+                                    message,
+                                    Severity.WARNING,
+                                    Version.V41,
+                                    context.project().getModel().getDelegate(),
+                                    -1,
+                                    -1,
+                                    null));
+                }
+                logger.debug(
+                        "Injecting module-aware {} resource roots for {} 
modules",
+                        scopeId,
+                        context.modules().size());
+                for (String module : context.modules()) {
+                    Path resourcePath = context.baseDir()
+                            .resolve("src")
+                            .resolve(module)
+                            .resolve(scopeId)
+                            .resolve("resources");
+                    logger.debug("  - Adding {} resource root: {} (module: 
{})", scopeId, resourcePath, module);
+                    
context.project().addSourceRoot(createModularResourceRoot(context.baseDir(), 
module, scope));
+                }
+            }
+        } else {
+            // Classic (non-modular) project
+            if (hasResourcesInSources) {
+                // Resources configured via <sources> - already added above
+                if (hasExplicitLegacyResources(resources, context.baseDir(), 
scopeId)) {
+                    logger.warn(
+                            "Legacy {} element is ignored because {} resources 
are configured via {} in <sources>",
+                            legacyElement,
+                            scopeId,
+                            sourcesConfig);
+                }
+                logger.debug(
+                        "{} resources configured via <sources> element, 
ignoring legacy {} element",
+                        scopeName,
+                        legacyElement);
+            } else {
+                // Use legacy resources element
+                logger.debug(
+                        "Using explicit or default {} resources ({} resources 
configured)", scopeId, resources.size());
+                for (Resource resource : resources) {
+                    context.project().addSourceRoot(new 
DefaultSourceRoot(context.baseDir(), scope, resource));
+                }
+            }
+        }
+    }
+
+    /**
+     * Extracts unique module names from the given list of source elements.
+     * A project is considered modular if it has at least one module name.
+     *
+     * @param sources list of source elements from the build
+     * @return set of non-blank module names
+     */
+    private static Set<String> 
extractModules(List<org.apache.maven.api.model.Source> sources) {
+        return sources.stream()
+                .map(org.apache.maven.api.model.Source::getModule)
+                .filter(Objects::nonNull)
+                .map(String::trim)
+                .filter(s -> !s.isBlank())
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Creates a DefaultSourceRoot for module-aware resource directories.
+     * Generates paths following the pattern: {@code 
src/<module>/<scope>/resources}
+     *
+     * @param baseDir base directory of the project
+     * @param module module name
+     * @param scope project scope (main or test)
+     * @return configured DefaultSourceRoot for the module's resources
+     */
+    private DefaultSourceRoot createModularResourceRoot(Path baseDir, String 
module, ProjectScope scope) {
+        Path resourceDir =
+                
baseDir.resolve("src").resolve(module).resolve(scope.id()).resolve("resources");
+
+        return new DefaultSourceRoot(
+                scope,
+                Language.RESOURCES,
+                module,
+                null, // targetVersion
+                resourceDir,
+                null, // includes
+                null, // excludes
+                false, // stringFiltering
+                Path.of(module), // targetPath - resources go to 
target/classes/<module>
+                true // enabled
+                );
+    }
+
+    /**
+     * Checks if the given resource list contains explicit legacy resources 
that differ
+     * from Super POM defaults. Super POM defaults are: src/{scope}/resources 
and src/{scope}/resources-filtered
+     *
+     * @param resources list of resources to check
+     * @param baseDir project base directory
+     * @param scope scope (main or test)
+     * @return true if explicit legacy resources are present that would be 
ignored
+     */
+    private boolean hasExplicitLegacyResources(List<Resource> resources, Path 
baseDir, String scope) {
+        if (resources.isEmpty()) {
+            return false; // No resources means no explicit legacy resources 
to warn about
+        }
+
+        // Super POM default paths
+        String defaultPath =
+                
baseDir.resolve("src").resolve(scope).resolve("resources").toString();
+        String defaultFilteredPath = baseDir.resolve("src")
+                .resolve(scope)
+                .resolve("resources-filtered")
+                .toString();
+
+        // Check if any resource differs from Super POM defaults
+        for (Resource resource : resources) {
+            String resourceDir = resource.getDirectory();
+            if (resourceDir != null && !resourceDir.equals(defaultPath) && 
!resourceDir.equals(defaultFilteredPath)) {
+                // Found an explicit legacy resource
+                return true;
+            }
+        }
+
+        logger.debug("Only Super POM default resources found for scope: {}", 
scope);

Review Comment:
   Changed to trace level in d2ce972700. The log in 
`hasExplicitLegacyResources` was removed entirely as suggested. The remaining 
trace logs are useful for understanding resource resolution but won't appear in 
normal debug output.



##########
impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java:
##########
@@ -1099,6 +1123,193 @@ public Set<Entry<K, V>> entrySet() {
         }
     }
 
+    /**
+     * Context object for resource handling configuration.
+     * Groups parameters shared between main and test resource handling to 
reduce method parameter count.
+     */
+    private record ResourceHandlingContext(
+            MavenProject project,
+            Path baseDir,
+            Set<String> modules,
+            boolean modularProject,
+            ModelBuilderResult result) {}
+
+    /**
+     * Handles resource configuration for a given scope (main or test).
+     * This method applies the resource priority rules:
+     * <ol>
+     *   <li>Modular project: use resources from {@code <sources>} if present, 
otherwise inject defaults</li>
+     *   <li>Classic project: use resources from {@code <sources>} if present, 
otherwise use legacy resources</li>
+     * </ol>
+     *
+     * @param context the resource handling context containing project info
+     * @param resources the legacy resource list (from {@code <resources>} or 
{@code <testResources>})
+     * @param hasResourcesInSources whether resources are configured via 
{@code <sources>}
+     * @param scope the project scope (MAIN or TEST)
+     */
+    private void handleResourceConfiguration(
+            ResourceHandlingContext context,
+            List<Resource> resources,
+            boolean hasResourcesInSources,
+            ProjectScope scope) {
+
+        String scopeId = scope.id();
+        String scopeName = scope == ProjectScope.MAIN ? "Main" : "Test";
+        String legacyElement = scope == ProjectScope.MAIN ? "<resources>" : 
"<testResources>";
+        String sourcesConfig = scope == ProjectScope.MAIN
+                ? "<source><lang>resources</lang></source>"
+                : "<source><lang>resources</lang><scope>test</scope></source>";
+
+        if (context.modularProject()) {
+            if (hasResourcesInSources) {
+                // Modular project with resources configured via <sources> - 
already added above
+                if (hasExplicitLegacyResources(resources, context.baseDir(), 
scopeId)) {
+                    logger.warn(
+                            "Legacy {} element is ignored because {} resources 
are configured via {} in <sources>",
+                            legacyElement,
+                            scopeId,
+                            sourcesConfig);
+                }
+                logger.debug(
+                        "{} resources configured via <sources> element, 
ignoring legacy {} element",
+                        scopeName,
+                        legacyElement);
+            } else {
+                // Modular project without resources in <sources> - inject 
module-aware defaults
+                if (hasExplicitLegacyResources(resources, context.baseDir(), 
scopeId)) {
+                    String message = "Legacy " + legacyElement
+                            + " element is ignored because modular sources are 
configured. "
+                            + "Use " + sourcesConfig + " in <sources> for 
custom resource paths.";
+                    logger.warn(message);
+                    context.result()
+                            .getProblemCollector()
+                            .reportProblem(new 
org.apache.maven.impl.model.DefaultModelProblem(
+                                    message,
+                                    Severity.WARNING,
+                                    Version.V41,
+                                    context.project().getModel().getDelegate(),
+                                    -1,
+                                    -1,
+                                    null));
+                }
+                logger.debug(
+                        "Injecting module-aware {} resource roots for {} 
modules",
+                        scopeId,
+                        context.modules().size());
+                for (String module : context.modules()) {
+                    Path resourcePath = context.baseDir()
+                            .resolve("src")
+                            .resolve(module)
+                            .resolve(scopeId)
+                            .resolve("resources");
+                    logger.debug("  - Adding {} resource root: {} (module: 
{})", scopeId, resourcePath, module);
+                    
context.project().addSourceRoot(createModularResourceRoot(context.baseDir(), 
module, scope));
+                }
+            }
+        } else {
+            // Classic (non-modular) project
+            if (hasResourcesInSources) {
+                // Resources configured via <sources> - already added above
+                if (hasExplicitLegacyResources(resources, context.baseDir(), 
scopeId)) {
+                    logger.warn(
+                            "Legacy {} element is ignored because {} resources 
are configured via {} in <sources>",
+                            legacyElement,
+                            scopeId,
+                            sourcesConfig);
+                }
+                logger.debug(
+                        "{} resources configured via <sources> element, 
ignoring legacy {} element",
+                        scopeName,
+                        legacyElement);
+            } else {
+                // Use legacy resources element
+                logger.debug(
+                        "Using explicit or default {} resources ({} resources 
configured)", scopeId, resources.size());
+                for (Resource resource : resources) {
+                    context.project().addSourceRoot(new 
DefaultSourceRoot(context.baseDir(), scope, resource));
+                }
+            }
+        }
+    }
+
+    /**
+     * Extracts unique module names from the given list of source elements.
+     * A project is considered modular if it has at least one module name.
+     *
+     * @param sources list of source elements from the build
+     * @return set of non-blank module names
+     */
+    private static Set<String> 
extractModules(List<org.apache.maven.api.model.Source> sources) {
+        return sources.stream()
+                .map(org.apache.maven.api.model.Source::getModule)
+                .filter(Objects::nonNull)
+                .map(String::trim)
+                .filter(s -> !s.isBlank())
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Creates a DefaultSourceRoot for module-aware resource directories.
+     * Generates paths following the pattern: {@code 
src/<module>/<scope>/resources}
+     *
+     * @param baseDir base directory of the project
+     * @param module module name
+     * @param scope project scope (main or test)
+     * @return configured DefaultSourceRoot for the module's resources
+     */
+    private DefaultSourceRoot createModularResourceRoot(Path baseDir, String 
module, ProjectScope scope) {

Review Comment:
   Done in d2ce972700. Both `hasExplicitLegacyResources` and 
`createModularResourceRoot` are now instance methods in the extracted 
`ResourceHandlingContext` class (see dcc621c014).



##########
impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java:
##########
@@ -1099,6 +1123,193 @@ public Set<Entry<K, V>> entrySet() {
         }
     }
 
+    /**
+     * Context object for resource handling configuration.
+     * Groups parameters shared between main and test resource handling to 
reduce method parameter count.
+     */
+    private record ResourceHandlingContext(
+            MavenProject project,
+            Path baseDir,
+            Set<String> modules,
+            boolean modularProject,
+            ModelBuilderResult result) {}
+
+    /**
+     * Handles resource configuration for a given scope (main or test).
+     * This method applies the resource priority rules:
+     * <ol>
+     *   <li>Modular project: use resources from {@code <sources>} if present, 
otherwise inject defaults</li>
+     *   <li>Classic project: use resources from {@code <sources>} if present, 
otherwise use legacy resources</li>
+     * </ol>
+     *
+     * @param context the resource handling context containing project info
+     * @param resources the legacy resource list (from {@code <resources>} or 
{@code <testResources>})
+     * @param hasResourcesInSources whether resources are configured via 
{@code <sources>}
+     * @param scope the project scope (MAIN or TEST)
+     */
+    private void handleResourceConfiguration(

Review Comment:
   Done in dcc621c014. Extracted to `ResourceHandlingContext` as a 
package-private class with instance methods. The logger, project, baseDir, 
modules, modularProject, and result are now fields, and 
`handleResourceConfiguration` takes only scope and hasResourcesInSources as 
parameters.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to