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

   ## Root Cause Analysis
   
   ### What "null" actually means
   
   The `null` is **not** the dependency collector returning null. It comes from 
`CollectRequest.toString()`:
   
   ```java
   // CollectRequest.java line 336
   public String toString() {
       return getRoot() + " -> " + getDependencies() + " < " + 
getRepositories();
   }
   ```
   
   When a project build resolves dependencies, the `CollectRequest` is 
constructed with **direct dependencies** (no root dependency). `getRoot()` 
returns `null`, hence `"null ->"`. This is expected behavior.
   
   ### What "compile?" means
   
   Also not scope uncertainty. It comes from `Dependency.toString()`:
   
   ```java
   // Dependency.java line 203
   public String toString() {
       return getArtifact() + " (" + getScope() + (isOptional() ? "?" : "") + 
")";
   }
   ```
   
   `(compile?)` = scope is `"compile"` and `isOptional() == true`. The 
`spring-boot-configuration-processor` is declared as a compile-scope optional 
dependency. The `?` is the optional flag.
   
   ### Actual cause: unfiltered managed dependency with `${…}` placeholder
   
   The error is thrown by 
`DefaultRepositorySystemValidator.validateCollectRequest()` 
([DefaultRepositorySystemValidator.java:220](https://github.com/apache/maven/blob/master/tmp-resolver/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java#L220))
 when `MavenValidator.validateDependency()` finds a `${…}` placeholder in one 
of the dependencies:
   
   ```java
   // MavenValidator.java line 59
   public void validateDependency(Dependency dependency) throws 
IllegalArgumentException {
       if (containsPlaceholder(artifact.getGroupId())
               || containsPlaceholder(artifact.getArtifactId())
               || containsPlaceholder(artifact.getVersion())
               || ...) {
           throw new IllegalArgumentException("Not fully interpolated 
dependency " + dependency);
       }
   }
   ```
   
   The validator iterates **both** `getDependencies()` and 
`getManagedDependencies()`. The failing entry is almost certainly a **managed 
dependency** — it doesn't appear in the `toString()` output (which only shows 
`getDependencies()`), explaining why all three visible deps look fully resolved.
   
   ### The gap: managed deps go unfiltered into the CollectRequest
   
   In `DefaultProjectDependenciesResolver.resolve()`:
   
   ```java
   // Lines 102-113: direct deps have null/empty filter
   for (Dependency dependency : project.getDependencies()) {
       if (dependency.getGroupId() == null || dependency.getGroupId().isEmpty()
               || dependency.getArtifactId() == null || 
dependency.getArtifactId().isEmpty()
               || dependency.getVersion() == null || 
dependency.getVersion().isEmpty()) {
           continue;  // some guard, but no ${…} check
       }
       collect.addDependency(RepositoryUtils.toDependency(dependency, 
stereotypes));
   }
   
   // Lines 145-150: managed deps have NO filtering at all
   DependencyManagement depMgmt = project.getDependencyManagement();
   if (depMgmt != null) {
       for (Dependency dependency : depMgmt.getDependencies()) {
           
collect.addManagedDependency(RepositoryUtils.toDependency(dependency, 
stereotypes));
       }
   }
   ```
   
   The fix for **transitive** uninterpolated expressions was already applied in 
`DefaultArtifactDescriptorReader` (commits `bb28b1748c`, `f101f3fc07`). The 
same guard is missing for **project-level** managed dependencies.
   
   The `DefaultDependencyResolver.collect()` (new API path) has the identical 
gap — `session.toDependencies(managedDependencies, true)` is passed directly to 
the `CollectRequest` without filtering.
   
   ### Fix
   
   Apply the same `${…}` placeholder filtering to managed deps in both 
resolvers, symmetric with what `f101f3fc07` did for transitive deps:
   
   **`DefaultProjectDependenciesResolver`** — extend `isInvalidDependency()` to 
cover `${…}`, and apply it to managed deps:
   ```java
   DependencyManagement depMgmt = project.getDependencyManagement();
   if (depMgmt != null) {
       for (Dependency dependency : depMgmt.getDependencies()) {
           if (isInvalidDependency(dependency)) {
               logger.debug("Filtered managed dependency with uninterpolated 
expression: {}", dependency);
               continue;
           }
           
collect.addManagedDependency(RepositoryUtils.toDependency(dependency, 
stereotypes));
       }
   }
   ```
   
   **`DefaultDependencyResolver`** — add `filterUninterpolated()` before 
building the `CollectRequest`.
   
   A complete version of this fix exists in branch 
`origin/maven-4.0.x-test-fixes` (commit `dfcbfe38bf`); it just needs to be 
reviewed and merged.
   
   The deeper question of *why* Causeway's parent chain produces managed 
dependencies with unresolved expressions is worth tracking separately — likely 
a subset of the same property-propagation issue that triggered `f101f3fc07` for 
transitive POMs.
   
   _Claude Code on behalf of Guillaume Nodet_


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