-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Affected version
4.0.0-rc5
Bug description
Note that I asked Claude Code to help with the analysis and the fix.
This is a different bug from #11767, discovered while testing the fixes from that ticket. The #11767 fix (PR #11768) correctly passes repositories and profiles to the consumer POM builder, but a separate code path still causes failures when parent POMs define properties inside profiles with property-based activation.
$ mvn clean install
[...]
[INFO] --- install:3.1.3:install (default-install) @ xxx ---
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] --------------------------------------------------------------------------------------------------------------------------
[...]
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-install-plugin:3.1.3:install (default-install) on project xxx: Execution default-install of goal org.apache.maven.plugins:maven-install-plugin:3.1.3:install failed: Invalid Version Range Request: org.springframework:spring-framework-bom:pom:${spring.version} [...]
The property ${spring.version} is defined in a great-grandparent POM (lineup) inside a profile with property-based activation:
<!-- lineup pom.xml -->
<profiles>
<profile>
<id>spring-old</id>
<activation>
<property>
<name>!explicitelyDeactivated</name>
</property>
</activation>
<properties>
<spring.version>5.3.39</spring.version>
</properties>
</profile>
</profiles>
A grandparent POM uses this property in a BOM import:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
During BUILD_PROJECT, profiles are properly activated and the property resolves to 5.3.39. During BUILD_CONSUMER (install phase), the property is null and the BOM import fails with Invalid Version Range Request.
Root cause
The bug is in DefaultModelBuilder.readParentLocally() (line ~1151 in DefaultModelBuilder.java).
When the consumer POM is built (BUILD_CONSUMER), readParentLocally() finds the parent POM via resolveReactorModel() (because the parent was loaded into mappedSources during the earlier BUILD_PROJECT phase). It then calls:
// Line ~1151 - DefaultModelBuilder.java - readParentLocally()
ModelBuilderSessionState derived = derive(candidateSource);
derive(candidateSource) calls derive(ModelBuilderRequest.build(request, source)) which preserves the BUILD_CONSUMER request type. Since isBuildRequestWithActivation() returns false for BUILD_CONSUMER, POM profile activation is skipped for all parent POMs in the chain:
boolean isBuildRequestWithActivation() {
return request.getRequestType() != ModelBuilderRequest.RequestType.BUILD_CONSUMER;
}
In contrast, resolveAndReadParentExternally() (used when the parent is NOT in the reactor) explicitly creates a CONSUMER_PARENT request:
// Line ~1284 - DefaultModelBuilder.java - resolveAndReadParentExternally()
ModelBuilderRequest lenientRequest = ModelBuilderRequest.builder(request)
.requestType(ModelBuilderRequest.RequestType.CONSUMER_PARENT)
.source(modelSource)
.build();
CONSUMER_PARENT allows profile activation, so parent POMs resolved externally work correctly. Only parent POMs resolved locally (via reactor/mappedSources) are affected.
Fix
In readParentLocally(), when the current request is BUILD_CONSUMER, derive the parent session with CONSUMER_PARENT type — consistent with how resolveAndReadParentExternally() handles it:
ModelBuilderSessionState derived;
if (request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_CONSUMER) {
ModelBuilderRequest parentRequest = ModelBuilderRequest.builder(request)
.requestType(ModelBuilderRequest.RequestType.CONSUMER_PARENT)
.source(candidateSource)
.build();
derived = derive(parentRequest);
} else {
derived = derive(candidateSource);
}
Claude Code created the following unit test (which fails without the fix):
Test: DefaultModelBuilderTest.testBuildConsumerResolvesParentProfileProperties (maven-impl)
- Builds a parent POM with BUILD_PROJECT to populate the reactor (mappedSources) — the parent defines managed.version=1.2.3 inside a profile with property-based activation (!skipDefaultVersions)
- Builds the child POM with BUILD_CONSUMER on the same session — the parent is found via resolveReactorModel() in readParentLocally()
- Asserts the effective model has managed.version=1.2.3 (from the parent's profile)
- Asserts the managed dependency version is interpolated to 1.2.3, not ${managed.version}
Without the fix:AssertionFailedError: expected: <1.2.3> but was: <null>
I was also able to confirm that when implementing the fix on top of 4.0-rc5, my mvn clean install passed.
I am now preparing a Pull Request.