Fix resource targetPath resolution to be relative to output directory (fixes #11381) by gnodet · Pull Request #11394 · apache/maven (original) (raw)
added 2 commits
… output directory
This commit fixes a regression in Maven 4 where resource targetPath was being resolved relative to the project base directory instead of the output directory (target/classes or target/test-classes).
The issue was in the DefaultSourceRoot constructor that takes a Resource parameter. It was resolving targetPath relative to baseDir instead of the output directory.
Changes made:
- Added a new constructor to DefaultSourceRoot that accepts an outputDir parameter
- Deprecated the old constructor to maintain backward compatibility
- Updated all call sites in DefaultProjectBuilder, ConnectedResource, and MavenProject to use the new constructor with the appropriate output directory
- Updated unit tests in DefaultSourceRootTest to verify correct behavior
- Added integration test MavenITgh11381ResourceTargetPathTest to verify the fix
This restores Maven 3.x behavior where relative targetPath values in resources are correctly resolved relative to the output directory.
Fixes apache#11381
…elative targetPath
This commit fixes two issues in ConnectedResource:
Handle null output directories: When the Build object doesn't have output directories set (e.g., in tests), use default values (target/classes for main scope, target/test-classes for test scope).
Compute relative targetPath: The SourceRoot stores the targetPath as a resolved path (absolute or relative to baseDir), but the Resource model expects it to be relative to the output directory. Added a helper method computeRelativeTargetPath() to extract the relative path from the resolved path by relativizing it against the output directory.
Also updated ResourceIncludeTest to:
- Set build output directories in setUp() method
- Use the new DefaultSourceRoot constructor with output directory parameter instead of the deprecated constructor
This ensures that the targetPath is correctly preserved through the conversion chain from Resource -> SourceRoot -> ConnectedResource.
gnodet changed the title
[GH-11381] Fix resource targetPath resolution to be relative to output directory Fix resource targetPath resolution to be relative to output directory (fixes #11381)
gnodet marked this pull request as draft
The root cause of the issue was that DefaultSourceRoot was resolving the targetPath against baseDir (or baseDir + outputDir), which required complex logic in ConnectedResource to extract the relative path back out.
This commit simplifies the approach by keeping the targetPath as a relative path in DefaultSourceRoot (using Path::of instead of resolving it). This eliminates the need for:
- The outputDir parameter in the DefaultSourceRoot constructor
- The computeRelativeTargetPath() method in ConnectedResource
- Complex path resolution and relativization logic
Changes:
- DefaultSourceRoot: Keep targetPath as relative path using Path::of
- DefaultSourceRoot: Remove the outputDir parameter from constructor
- DefaultSourceRoot: Remove the deprecated constructor (both constructors are now identical)
- ConnectedResource: Simplify to just convert targetPath to string
- ConnectedResource: Remove outputDir parameter from updateProjectSourceRoot
- DefaultSourceRootTest: Update tests to expect relative paths
- ResourceIncludeTest: Remove outputDir parameter from test
This ensures that the targetPath is correctly preserved through the conversion chain from Resource -> SourceRoot -> ConnectedResource.
…rojectBuilder
Since the targetPath is now kept as a relative path in DefaultSourceRoot, the outputDir parameter is no longer needed when creating DefaultSourceRoot instances from Resources.
Changes:
- MavenProject.addResource(): Remove outputDir calculation and parameter
- DefaultProjectBuilder: Remove outputDir parameter from DefaultSourceRoot calls
gnodet marked this pull request as ready for review
Based on PR comments, the solution has been updated:
SourceRoot.targetPath() returns a Path relative to the project's basedir (e.g., 'target/classes/custom-output')
- Reverted DefaultSourceRoot to resolve targetPath against baseDir
ConnectedResource.getTargetPath() (Maven 3 API) returns a path relative to the output directory (e.g., 'custom-output')
- Added computeRelativeTargetPath() method to make the path relative to the output directory when converting from SourceRoot to Resource
This maintains backward compatibility with Maven 3 API while using the new Maven 4 API internally.
Changes:
- DefaultSourceRoot: Reverted to resolve targetPath against baseDir
- ConnectedResource: Added computeRelativeTargetPath() to convert from basedir-relative to outputdir-relative paths
- DefaultSourceRootTest: Updated tests to expect basedir-relative paths
- ResourceIncludeTest: Tests still pass with the new conversion logic
…directory
This commit fixes the regression where resources with a relative targetPath were being copied to the project root instead of relative to the output directory (target/classes or target/test-classes).
Changes:
DefaultSourceRoot.fromModel: Store targetPath as a relative path instead of resolving it against baseDir and outputDir. This ensures that SourceRoot.targetPath() returns a relative path as intended by the Maven 4 API javadoc.
ConnectedResource.computeRelativeTargetPath: Simplified to directly return the relative targetPath from SourceRoot, since it's now always stored as relative.
Updated tests to expect relative paths from SourceRoot.targetPath().
Maven 4 API Conformance:
- SourceRoot.targetPath() returns an Optional
containing the explicit target path, which should be relative to the output directory (or absolute if explicitly specified as absolute). - SourceRoot.targetPath(Project) resolves this relative path against the project's output directory to produce an absolute path.
Maven 3 Compatibility:
- Resource.getTargetPath() in Maven 3 was always relative to the output directory. This behavior is preserved by storing targetPath as relative in SourceRoot and converting it back to relative for the Resource API via ConnectedResource.
Example: With custom-dir:
- Maven 3: Resources copied to target/classes/custom-dir
- Maven 4 (before fix): Resources copied to project-root/custom-dir
- Maven 4 (after fix): Resources copied to target/classes/custom-dir
Fixes apache#11381
Enhanced the javadoc for SourceRoot.targetPath() and targetPath(Project) to make it explicit that:
targetPath() returns a path that is typically relative to the output directory (e.g., 'custom-dir' or 'META-INF/resources'), but may be absolute if explicitly specified.
targetPath(Project) returns the fully resolved absolute path where files should be copied, with clear examples of how it handles:
- Empty Optional: returns the default output directory
- Relative path: resolves against the output directory
- Absolute path: returns unchanged
These clarifications help implementers understand the intended behavior and prevent regressions like apacheGH-11381 where targetPath was incorrectly stored as an absolute path.
…ctory()
This commit improves the documentation for resource targetPath handling to clarify the Maven 4 API semantics while preserving Maven 3 backward compatibility.
Key documentation improvements:
SourceRoot.targetPath():
- Clarifies that relative paths are resolved relative to the output directory (target/classes for MAIN scope, target/test-classes for TEST scope)
- Documents that absolute paths are used as-is
- Explicitly states Maven 3 compatibility is maintained
- Adds concrete examples showing path resolution
SourceRoot.targetPath(Project):
- Documents the complete resolution algorithm step-by-step
- Provides detailed examples with actual paths
- Cross-references Project.getOutputDirectory()
Project.getOutputDirectory():
- Clarifies that it returns the directory for both compiled classes AND resources
- Documents its role in SourceRoot targetPath resolution
- Explicitly states Maven 3 compatibility semantics
DefaultSourceRoot constructor from Resource:
- Documents that targetPath is stored as-is (not resolved against basedir)
- Clarifies that baseDir parameter is only used for source directory resolution
- Explains how this preserves Maven 3.x behavior
Implementation details:
- DefaultSourceRoot stores targetPath as provided (relative or absolute)
- ConnectedResource extracts targetPath as-is for maven-resources-plugin
- Resolution to absolute paths happens via SourceRoot.targetPath(Project)
- This maintains Maven 3 behavior where resource targetPath is relative to the output directory, not the project base directory
Related to apache#11381
This commit significantly enhances the javadoc documentation to make the targetPath handling semantics even more explicit and clear for all audiences: API consumers, plugin developers, and implementers.
Key improvements:
SourceRoot.targetPath():
- Explicitly states this returns the path AS CONFIGURED (no resolution)
- Clearly distinguishes between storage (this method) and resolution (targetPath(Project))
- Provides detailed "Return Value Semantics" section explaining empty/relative/absolute cases
- Adds "Usage Guidance" section for different audiences:
- Maven 4 API consumers: use targetPath(Project)
- Maven 3 compatibility: use this method for legacy plugins
- Implementers: store path as-is, don't resolve at storage time
- Emphasizes Maven 3 compatibility with explicit reference to project.build.outputDirectory and project.build.testOutputDirectory
SourceRoot.targetPath(Project):
- Adds "Purpose" section explaining this is THE resolution method
- Provides detailed step-by-step resolution algorithm with all cases
- Includes comprehensive table with concrete examples showing:
- Configuration input
- Output directory
- Final resolved result
- Explanation of each case
- Adds "Relationship to targetPath()" section explaining storage vs resolution
- Includes implementation note with equivalent code for clarity
Project.getOutputDirectory():
- Adds comprehensive table showing scope-to-directory mapping
- Includes "Role in SourceRoot Path Resolution" section with concrete examples
- Expands Maven 3 compatibility section with actual XML configuration example
- Shows how maven-resources-plugin uses this in Maven 3
- Provides code examples demonstrating usage
HTML5 Compliance:
- Replaced deprecated table attributes (cellpadding, cellspacing, border)
- Uses modern HTML5 table styling with class="striped"
The refined documentation makes it crystal clear that:
- targetPath() is for STORAGE (returns path as configured)
- targetPath(Project) is for RESOLUTION (returns absolute path)
- getOutputDirectory() provides the base for resolution
- Maven 3 compatibility is maintained by storing relative paths
- Different audiences have clear guidance on which method to use
Related to apache#11381
gnodet added a commit to gnodet/maven that referenced this pull request
…fixes apache#11381) (apache#11394)
This commit fixes the regression where resources with a relative targetPath were being copied to the project root instead of relative to the output directory (target/classes or target/test-classes).
Changes:
DefaultSourceRoot.fromModel: Store targetPath as a relative path instead of resolving it against baseDir and outputDir. This ensures that SourceRoot.targetPath() returns a relative path as intended by the Maven 4 API javadoc.
ConnectedResource.computeRelativeTargetPath: Simplified to directly return the relative targetPath from SourceRoot, since it's now always stored as relative.
Updated tests to expect relative paths from SourceRoot.targetPath().
Maven 4 API Conformance:
- SourceRoot.targetPath() returns an Optional
containing the explicit target path, which should be relative to the output directory (or absolute if explicitly specified as absolute). - SourceRoot.targetPath(Project) resolves this relative path against the project's output directory to produce an absolute path.
Maven 3 Compatibility:
- Resource.getTargetPath() in Maven 3 was always relative to the output directory. This behavior is preserved by storing targetPath as relative in SourceRoot and converting it back to relative for the Resource API via ConnectedResource.
Example: With custom-dir:
- Maven 3: Resources copied to target/classes/custom-dir
- Maven 4 (before fix): Resources copied to project-root/custom-dir
- Maven 4 (after fix): Resources copied to target/classes/custom-dir
Fixes apache#11381
(cherry picked from commit 9b95526)
gnodet added a commit to gnodet/maven that referenced this pull request
…fixes apache#11381) (apache#11394)
This commit fixes the regression where resources with a relative targetPath were being copied to the project root instead of relative to the output directory (target/classes or target/test-classes).
Changes:
DefaultSourceRoot.fromModel: Store targetPath as a relative path instead of resolving it against baseDir and outputDir. This ensures that SourceRoot.targetPath() returns a relative path as intended by the Maven 4 API javadoc.
ConnectedResource.computeRelativeTargetPath: Simplified to directly return the relative targetPath from SourceRoot, since it's now always stored as relative.
Updated tests to expect relative paths from SourceRoot.targetPath().
Maven 4 API Conformance:
- SourceRoot.targetPath() returns an Optional
containing the explicit target path, which should be relative to the output directory (or absolute if explicitly specified as absolute). - SourceRoot.targetPath(Project) resolves this relative path against the project's output directory to produce an absolute path.
Maven 3 Compatibility:
- Resource.getTargetPath() in Maven 3 was always relative to the output directory. This behavior is preserved by storing targetPath as relative in SourceRoot and converting it back to relative for the Resource API via ConnectedResource.
Example: With custom-dir:
- Maven 3: Resources copied to target/classes/custom-dir
- Maven 4 (before fix): Resources copied to project-root/custom-dir
- Maven 4 (after fix): Resources copied to target/classes/custom-dir
Fixes apache#11381
(cherry picked from commit 9b95526)
gnodet deleted the fix-gh-11381-resource-targetpath branch
gnodet added a commit that referenced this pull request
…fixes #11381) (#11394) (#11406)
This commit fixes the regression where resources with a relative targetPath were being copied to the project root instead of relative to the output directory (target/classes or target/test-classes).
Changes:
DefaultSourceRoot.fromModel: Store targetPath as a relative path instead of resolving it against baseDir and outputDir. This ensures that SourceRoot.targetPath() returns a relative path as intended by the Maven 4 API javadoc.
ConnectedResource.computeRelativeTargetPath: Simplified to directly return the relative targetPath from SourceRoot, since it's now always stored as relative.
Updated tests to expect relative paths from SourceRoot.targetPath().
Maven 4 API Conformance:
- SourceRoot.targetPath() returns an Optional
containing the explicit target path, which should be relative to the output directory (or absolute if explicitly specified as absolute). - SourceRoot.targetPath(Project) resolves this relative path against the project's output directory to produce an absolute path.
Maven 3 Compatibility:
- Resource.getTargetPath() in Maven 3 was always relative to the output directory. This behavior is preserved by storing targetPath as relative in SourceRoot and converting it back to relative for the Resource API via ConnectedResource.
Example: With custom-dir:
- Maven 3: Resources copied to target/classes/custom-dir
- Maven 4 (before fix): Resources copied to project-root/custom-dir
- Maven 4 (after fix): Resources copied to target/classes/custom-dir
Fixes #11381
(cherry picked from commit 9b95526)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
[ Show hidden characters]({{ revealButtonHref }})