[MNG-8765] Pre-interpolate plugin configuration before type conversion - #12686
[MNG-8765] Pre-interpolate plugin configuration before type conversion#12686gnodet wants to merge 1 commit into
Conversation
Properties set dynamically at runtime (e.g., by Groovy/GMaven scripts via project.properties.setProperty()) are not available during model interpolation, which runs before the build lifecycle. When such a property is used in a URI-typed plugin parameter like https://example.com/${dynamic.prop}/path, the unresolved ${...} reaches the UriConverter, which fails with URISyntaxException because curly braces are illegal URI characters. Fix by pre-interpolating the PlexusConfiguration tree using the expression evaluator in DefaultMavenPluginManager before passing it to the ComponentConfigurator. This ensures all resolvable ${...} references are replaced before type converters process the values. Includes integration tests for URI property interpolation with POM properties, inherited parent properties, and CLI-passed properties. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gnodet
left a comment
There was a problem hiding this comment.
The pre-interpolation approach is sound in principle, but the implementation has a fundamental issue that renders the fix ineffective:
1. Interpolated values are silently discarded (high severity)
interpolateConfiguration stores resolved values in child XmlPlexusConfiguration wrappers obtained via getChildren(), but both the Plexus ObjectWithFieldsConverter and Maven's EnhancedConfigurationConverter access children via getChild(int), which creates new wrappers from the parent's unmodified immutable XmlNode tree — all interpolated values are lost.
Trace:
getChildren()populates achildrenCachewith wrapperssetValue()replaces the wrapper's internalxmlNodebut does NOT update the parent'sxmlNode.children()(XmlNode is immutable)getChild(int)does NOT use the cache — it creates a fresh wrapper fromxmlNode.children().get(i), which still holds the original uninterpolated child
Suggested approach: Reconstruct the XmlNode tree bottom-up with interpolated values and wrap it in a fresh XmlPlexusConfiguration, rather than mutating transient wrapper objects.
2. Tests don't cover the actual failure scenario (high severity)
The tests use POM-defined properties (test.version=1.2.3) and CLI properties (-Dcli.version=2.0.0), both of which are already resolved during model interpolation — before interpolateConfiguration runs. The tests pass with or without the fix. The actual MNG-8765 scenario (properties set dynamically at runtime via project.properties.setProperty() by Groovy/GMaven scripts) is not tested.
3. Fix only in loadV3Mojo (medium severity)
The interpolateConfiguration call is only added to loadV3Mojo. loadV4Mojo has the same pomConfiguration → populateMojoExecutionFields flow but no pre-interpolation, leaving V4 mojos with URI-typed parameters unprotected.
4. Javadoc inaccuracy (low severity)
The Javadoc says @return a new PlexusConfiguration but the method returns the same object mutated in place.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of gnodet
gnodet
left a comment
There was a problem hiding this comment.
Review: [MNG-8765] Pre-interpolate plugin configuration before type conversion
The intent of this fix is sound — runtime properties set by scripts (e.g., Groovy calling project.properties.setProperty(...)) need resolution before URI type converters parse the value. However, the implementation has a structural issue that makes it ineffective.
Confirmed findings:
-
[high] Pre-interpolation has no effect on type converters —
interpolateConfigurationmodifies child wrappers obtained viagetChildren(), but theComponentConfigurator(both standard plexusObjectWithFieldsConverterand Maven'sEnhancedConfigurationConverter) accesses children viagetChild(int i), which creates new wrappers from the parent's unchanged immutableXmlNode. SinceXmlNodeis@Immutable,setValue()on a child wrapper replaces only that wrapper'sxmlNodereference — the parent'sxmlNode.children()list is never updated. The interpolated values are invisible to type converters.A possible fix: build a new
XmlNodetree with interpolated values (usingXmlNode.newBuilder()recursively) and wrap the result in a freshXmlPlexusConfiguration, or fixXmlPlexusConfiguration.getChild(int i)to consult thechildrenCachewhen populated. -
[medium] Missing from
loadV4Mojo— The pre-interpolation is only added toloadV3Mojobut not toloadV4Mojo(line 598), which has the identical structure. If V4 mojos use URI-typed parameters with runtime properties, they would have the same issue. -
[medium] Integration tests don't cover the actual scenario — Both test methods use properties that model interpolation already resolves:
${test.version}(POM property) and${cli.version}(system property from-D). By the timeloadV3Mojoruns, these values are already resolved in the DOM. The actual MNG-8765 scenario — a property set at runtime viaproject.properties.setProperty()by a prior plugin — is not covered. -
[low] Silent exception swallowing — Empty
catch (ExpressionEvaluationException e)blocks. Alogger.debug()call would aid troubleshooting.
This review was generated by an AI agent (Claude Code) and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
gnodet
left a comment
There was a problem hiding this comment.
The pre-interpolation approach is sound in principle, but the implementation has a structural issue that may render the fix ineffective:
High severity:
-
Interpolated values invisible to downstream type converters:
interpolateConfiguration()modifies child wrappers obtained viagetChildren(), which populateschildrenCache. However, the downstream Plexus configurators (BasicComponentConfiguratorandEnhancedConfigurationConverter) access children viagetChild(int i), which inXmlPlexusConfiguration(line 165-171) creates new wrappers directly fromxmlNode.children().get(i)— completely bypassingchildrenCache. SinceXmlNodeis immutable andsetValue()only replaces a wrapper's internalxmlNodereference (not the parent's child list), all interpolated values are invisible to type converters.Additionally, the existing expression evaluation path in
AbstractBasicConverter.fromExpression()already resolves${...}expressions viaPluginParameterExpressionEvaluatorbefore type conversion, andUriConverter.fromString()then converts the resolved string. This may make pre-interpolation redundant even if it worked. -
Tests don't cover the actual MNG-8765 scenario: Both test methods use properties already resolved during model interpolation —
${test.version}(POM<properties>) and${cli.version}(-DCLI). These values are fully resolved beforeloadV3Mojoruns, so the tests pass with or without theinterpolateConfigurationcall. The actual scenario (properties set dynamically at runtime viaproject.properties.setProperty()) is not tested.
Medium severity:
- V4 mojos unprotected:
interpolateConfigurationis only added toloadV3Mojo. TheloadV4Mojomethod has the identical flow but no pre-interpolation.
Low severity:
- Javadoc says "@return a new PlexusConfiguration" but the method mutates and returns the same object.
- Two
catch (ExpressionEvaluationException e)blocks silently swallow exceptions — consider addinglogger.debug()for troubleshooting.
Suggested approach: either reconstruct the XmlNode tree bottom-up with interpolated values using XmlNode.newBuilder(), or fix XmlPlexusConfiguration.getChild(int i) to consult childrenCache, or move interpolation to a point where values are consumed directly.
This review was generated by an AI agent (Claude Code) and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Summary
PlexusConfigurationvalues using the expression evaluator inDefaultMavenPluginManagerbefore passing them to theComponentConfigurator, ensuring${...}property references are fully resolved before type converters (likeUriConverter) process the valuesproject.properties.setProperty()) are not available during model interpolation and reach type converters unresolved, causingURISyntaxExceptionfor URI-typed parametersRegression found in CloudStack (gnodet/maven4-testing#34733) where a URI parameter with
${cs.version}set by a Groovy script at runtime causedURISyntaxException.Test plan
impl/maven-core)MavenITmng8765UriPropertyInterpolationTestpasses:-D) in URI parameters🤖 Generated with Claude Code