gnodet commented on issue #11381:
URL: https://github.com/apache/maven/issues/11381#issuecomment-3502272376

   ## Implementation Explanation: Resource targetPath Fix
   
   This fix addresses the regression in Maven 4 where resource `targetPath` was 
being resolved relative to the project base directory instead of the output 
directory, breaking compatibility with Maven 3.x behavior.
   
   ### Problem Analysis
   
   In Maven 3.x, when a resource has a relative `targetPath`, it's resolved 
relative to the output directory (`target/classes` or `target/test-classes`). 
However, in Maven 4, the `DefaultSourceRoot` constructor that takes a 
`Resource` parameter was incorrectly resolving the targetPath as:
   
   ```java
   nonBlank(resource.getTargetPath()).map(baseDir::resolve).orElse(null)
   ```
   
   This resolved the targetPath relative to the base directory, not the output 
directory.
   
   ### Solution Design
   
   The fix was implemented with careful consideration for both Maven 4 API 
conformance and Maven 3 compatibility:
   
   #### 1. **API-First Approach**
   The solution leverages Maven 4's new `SourceRoot` API which represents a 
more structured approach to handling source and resource directories. The 
`SourceRoot.targetPath()` method returns an `Optional<Path>` that should 
contain a path relative to the output directory.
   
   #### 2. **Backward Compatibility Strategy**
   To maintain compatibility with existing Maven 3 code that uses the 
`Resource` API:
   
   - **Preserved existing constructor**: The original `DefaultSourceRoot(Path 
baseDir, ProjectScope scope, Resource resource)` constructor was kept unchanged 
to avoid breaking existing code
   - **Correct targetPath handling**: The constructor now properly stores the 
targetPath as a relative path (using `Path.of()`) instead of resolving it 
against the base directory
   - **ConnectedResource wrapper**: This class bridges between the Maven 4 
`SourceRoot` API and the Maven 3 `Resource` API, ensuring that when Maven 3 
code calls `Resource.getTargetPath()`, it receives the correct relative path
   
   #### 3. **Implementation Details**
   
   **DefaultSourceRoot Constructor (lines 157-171)**:
   ```java
   public DefaultSourceRoot(final Path baseDir, ProjectScope scope, Resource 
resource) {
       this(
               scope,
               Language.RESOURCES,
               null,
               null,
               baseDir.resolve(nonBlank(resource.getDirectory())
                       .orElseThrow(() -> new IllegalArgumentException("Source 
declaration without directory value."))),
               resource.getIncludes(),
               resource.getExcludes(),
               Boolean.parseBoolean(resource.getFiltering()),
               nonBlank(resource.getTargetPath()).map(Path::of).orElse(null), 
// Key fix: Path.of() instead of baseDir.resolve()
               true);
   }
   ```
   
   **ConnectedResource Bridge (lines 52-60)**:
   ```java
   private static String computeRelativeTargetPath(SourceRoot sourceRoot, 
ProjectScope scope, MavenProject project) {
       return sourceRoot.targetPath().map(Path::toString).orElse(null);
   }
   ```
   
   ### Maven 4 API Conformance
   
   #### 1. **Consistent Path Semantics**
   The fix ensures that `SourceRoot.targetPath()` always returns a relative 
path, which is the expected behavior in Maven 4's API design. This provides a 
clear contract: targetPath is always relative to the output directory.
   
   #### 2. **Type Safety**
   By using `Path.of()` instead of string manipulation, the implementation 
leverages Java's type-safe path handling, reducing the risk of path-related 
bugs.
   
   #### 3. **Optional Usage**
   The implementation properly uses `Optional<Path>` for targetPath, following 
Maven 4's API patterns for nullable values.
   
   ### Compatibility Preservation
   
   #### 1. **Maven 3 Resource API**
   Existing Maven 3 code that uses `Resource.getTargetPath()` continues to work 
unchanged. The `ConnectedResource` class ensures that the returned string 
represents a path relative to the output directory, maintaining the expected 
Maven 3 behavior.
   
   #### 2. **Plugin Compatibility**
   Maven plugins that rely on the Resource API (like the 
maven-resources-plugin) continue to work without modification, as they receive 
the correct relative paths through the `ConnectedResource` wrapper.
   
   #### 3. **Build Tool Integration**
   IDEs and other build tools that inspect Maven project models will see 
consistent behavior between Maven 3 and Maven 4.
   
   ### Testing Strategy
   
   The fix includes comprehensive testing at multiple levels:
   
   #### 1. **Unit Tests** (`DefaultSourceRootTest.java`)
   - Tests for Resource constructor with various targetPath scenarios
   - Verification that relative paths are preserved correctly
   - Edge case handling (null, empty targetPath)
   
   #### 2. **Integration Test** (`MavenITgh11381ResourceTargetPathTest.java`)
   - End-to-end verification that resources are copied to the correct location
   - Validates that `target/classes/target-dir/` is used instead of 
`target-dir/`
   - Ensures the fix works in real Maven builds
   
   ### Why This Approach?
   
   This implementation was chosen because it:
   
   1. **Minimizes Breaking Changes**: Existing code continues to work without 
modification
   2. **Follows Maven 4 Patterns**: Uses the new SourceRoot API as the primary 
abstraction
   3. **Maintains Clear Separation**: The SourceRoot API handles the "truth" 
while ConnectedResource provides compatibility
   4. **Enables Future Evolution**: The SourceRoot API can be extended without 
affecting the Resource compatibility layer
   5. **Provides Type Safety**: Uses Path objects internally while maintaining 
string compatibility externally
   
   This solution successfully bridges the gap between Maven 3's 
Resource-centric approach and Maven 4's SourceRoot-centric design, ensuring 
that both APIs work correctly while maintaining the expected behavior for 
resource targetPath resolution.


-- 
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