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]