You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/05/19 13:32:15 UTC

(maven) branch master updated: fix: propagate addResource() to model Build for Maven 3 compat (#11868)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 7bfc861e57 fix: propagate addResource() to model Build for Maven 3 compat (#11868)
7bfc861e57 is described below

commit 7bfc861e57bb0e0340d8f26f51e5d92e7a7feead
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Tue May 19 15:32:09 2026 +0200

    fix: propagate addResource() to model Build for Maven 3 compat (#11868)
    
    * fix: propagate addResource() to model Build for Maven 3 compat
    
    When a Maven 3 plugin dynamically adds a resource via
    project.addResource() or project.getResources().add(), the resource
    was only added to the internal sources set but not to the model's
    Build.resources. This caused project.getBuild().getResources() to be
    out of sync with project.getResources(), breaking plugins like
    maven-source-plugin that access resources through the Build model.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    
    * fix: sync Build.resources from sources set for Maven 3 compat
    
    Also sync the model's Build.resources after project building so that
    project.getBuild().getResources() is consistent with
    project.getResources() even when resources are defined via <sources>
    (Maven 4.1.0 model) rather than legacy <resources>.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    
    * fix: only sync Build.resources for <sources> projects
    
    Avoid syncing Build.resources for legacy projects to prevent
    Path.toString() from converting forward slashes to backslashes
    on Windows (fixes PomConstructionTest.testTargetPathResourceRegression).
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <no...@anthropic.com>
---
 .../maven/project/DefaultProjectBuilder.java       |  8 +++
 .../org/apache/maven/project/MavenProject.java     | 20 ++++++--
 .../apache/maven/project/ResourceIncludeTest.java  | 58 ++++++++++++++++++++++
 3 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
index cdddbdaafe..218ab338d6 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
@@ -777,6 +777,14 @@ implicit fallback (only if they match the default, e.g., inherited)
                     sourceContext.handleResourceConfiguration(ProjectScope.MAIN);
                     sourceContext.handleResourceConfiguration(ProjectScope.TEST);
                 }
+
+                // When resources are defined via <sources> (4.1.0 model), sync them to
+                // the model's Build so project.getBuild().getResources() is consistent.
+                // For legacy <resources>, the model already has the correct resources.
+                if (sourceContext.hasSources(Language.RESOURCES, ProjectScope.MAIN)
+                        || sourceContext.hasSources(Language.RESOURCES, ProjectScope.TEST)) {
+                    project.syncBuildResources();
+                }
             }
 
             project.setActiveProfiles(
diff --git a/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
index 45731697a7..e6c2c05acb 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
@@ -838,19 +838,31 @@ private Resource toConnectedResource(SourceRoot sourceRoot, ProjectScope scope)
 
     private void addResource(ProjectScope scope, Resource resource) {
         addSourceRoot(new DefaultSourceRoot(getBaseDirectory(), scope, resource.getDelegate()));
+        // Also update the model's Build to maintain compatibility with code that
+        // accesses resources via project.getBuild().getResources()
+        if (scope == ProjectScope.MAIN) {
+            getModelBuild().addResource(resource);
+        } else {
+            getModelBuild().addTestResource(resource);
+        }
     }
 
     /**
-     * @deprecated {@link Resource} is replaced by {@link SourceRoot}.
+     * Syncs {@code Build.resources/testResources} from the {@code sources} set
+     * for Maven 3 plugin compatibility (e.g. when resources come from {@code <sources>}).
      */
+    void syncBuildResources() {
+        getModelBuild().setResources(new java.util.ArrayList<>(getResources()));
+        getModelBuild().setTestResources(new java.util.ArrayList<>(getTestResources()));
+    }
+
+    /** @deprecated {@link Resource} is replaced by {@link SourceRoot}. */
     @Deprecated(since = "4.0.0")
     public void addResource(Resource resource) {
         addResource(ProjectScope.MAIN, resource);
     }
 
-    /**
-     * @deprecated {@link Resource} is replaced by {@link SourceRoot}.
-     */
+    /** @deprecated {@link Resource} is replaced by {@link SourceRoot}. */
     @Deprecated(since = "4.0.0")
     public void addTestResource(Resource testResource) {
         addResource(ProjectScope.TEST, testResource);
diff --git a/impl/maven-core/src/test/java/org/apache/maven/project/ResourceIncludeTest.java b/impl/maven-core/src/test/java/org/apache/maven/project/ResourceIncludeTest.java
index 519dbd5770..57ad0dbfc8 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/project/ResourceIncludeTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/project/ResourceIncludeTest.java
@@ -281,4 +281,62 @@ void testTargetPathEdgeCases() {
                 placeholderResult.getTargetPath(),
                 "Property placeholder in targetPath should be preserved");
     }
+
+    /**
+     * Verifies that resources added via {@code project.addResource()} or
+     * {@code project.getResources().add()} are visible through both
+     * {@code project.getResources()} and {@code project.getBuild().getResources()}.
+     * This is important for Maven 3 compatibility, since plugins may access
+     * resources through either path.
+     *
+     * @see <a href="https://github.com/apache/maven-source-plugin/pull/281">maven-source-plugin#281</a>
+     */
+    @Test
+    void testAddResourceVisibleViaBuildGetResources() {
+        // Initial state: one resource in sources, none added dynamically
+        assertEquals(1, project.getResources().size());
+        int initialBuildResources = project.getBuild().getResources().size();
+
+        // Add a resource dynamically (simulating what maven-remote-resources-plugin does)
+        Resource dynamicResource = new Resource();
+        dynamicResource.setDirectory("target/maven-shared-archive-resources");
+        project.addResource(dynamicResource);
+
+        // Verify visible via project.getResources()
+        List<Resource> projectResources = project.getResources();
+        assertEquals(2, projectResources.size(), "Dynamic resource should be visible via project.getResources()");
+
+        // Verify ALSO visible via project.getBuild().getResources()
+        List<Resource> buildResources = project.getBuild().getResources();
+        assertEquals(
+                initialBuildResources + 1,
+                buildResources.size(),
+                "Dynamic resource should also be visible via project.getBuild().getResources()");
+
+        boolean found =
+                buildResources.stream().anyMatch(r -> r.getDirectory().contains("maven-shared-archive-resources"));
+        assertTrue(found, "getBuild().getResources() should contain the dynamically added resource");
+    }
+
+    /**
+     * Same as above but using {@code project.getResources().add()} path.
+     */
+    @Test
+    void testAddResourceViaListVisibleViaBuildGetResources() {
+        int initialBuildResources = project.getBuild().getResources().size();
+
+        Resource dynamicResource = new Resource();
+        dynamicResource.setDirectory("target/maven-shared-archive-resources");
+        project.getResources().add(dynamicResource);
+
+        List<Resource> buildResources = project.getBuild().getResources();
+        assertEquals(
+                initialBuildResources + 1,
+                buildResources.size(),
+                "Resource added via getResources().add() should be visible via getBuild().getResources()");
+
+        boolean found =
+                buildResources.stream().anyMatch(r -> r.getDirectory().contains("maven-shared-archive-resources"));
+        assertTrue(found, "getBuild().getResources() should contain the resource added via getResources().add()");
+    }
 }