You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/09/15 13:46:40 UTC

(maven) branch master updated: Fix NPE on a recursive property reference in a list field

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 0aaa578f13 Fix NPE on a recursive property reference in a list field
0aaa578f13 is described below

commit 0aaa578f13a3fb87bd54c2aa9f7652271c83a8b8
Author: renechoi <11...@users.noreply.github.com>
AuthorDate: Tue Sep 15 22:46:32 2026 +0900

    Fix NPE on a recursive property reference in a list field
    
    DefaultModelInterpolator records an ERROR and returns null when the
    interpolator throws on a recursive variable reference. The generated
    transformer stores that null in List<String> model fields such as
    build/filters, whose Properties sibling branch already guards against
    it, and the immutable model constructor then copies the list with
    List.copyOf. The build fails with a bare NullPointerException instead
    of the "recursive variable reference" error that was just collected.
    
    Return the original text instead, which is what the Properties branch
    and StringVisitorModelInterpolator (MNG-8174) already do. The returned
    instance is identical, so the transformer's newVal != oldVal check
    stays false and unaffected models are still returned unchanged.
---
 .../maven/impl/model/DefaultModelInterpolator.java   |  6 +++++-
 .../impl/model/DefaultModelInterpolatorTest.java     | 20 ++++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelInterpolator.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelInterpolator.java
index da729b4af6..adc185cc2f 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelInterpolator.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelInterpolator.java
@@ -134,7 +134,11 @@ private InnerInterpolator createInterpolator(
                 return di.interpolate(value, null, cycleMap, cb, postprocessor, false);
             } catch (InterpolatorException e) {
                 problems.add(BuilderProblem.Severity.ERROR, ModelProblem.Version.BASE, e.getMessage(), e);
-                return null;
+                // Keep the original text rather than handing null back to the transformer. A null
+                // ends up as an element of a List<String> model field such as build/filters, and
+                // the immutable model constructor copies that list with List.copyOf, which fails
+                // with a bare NullPointerException that hides the problem just collected above.
+                return value;
             }
         };
     }
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelInterpolatorTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelInterpolatorTest.java
index 4ee3e14c59..c1c35ffd0f 100644
--- a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelInterpolatorTest.java
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelInterpolatorTest.java
@@ -632,6 +632,26 @@ public void testRecursiveExpressionCycleNPE() throws Exception {
         assertTrue(collector.getErrors().get(0).contains("recursive variable reference"));
     }
 
+    @Test
+    public void testRecursiveExpressionCycleInListField() throws Exception {
+        Map<String, String> props = new HashMap<>();
+        props.put("aa", "${bb}");
+        props.put("bb", "${aa}");
+
+        Model model = Model.newBuilder()
+                .properties(props)
+                .build(Build.newBuilder().filters(List.of("${aa}")).build())
+                .build();
+
+        SimpleProblemCollector collector = new SimpleProblemCollector();
+
+        ModelBuilderRequest request = createModelBuildingRequest(Map.of()).build();
+        Model out = interpolator.interpolateModel(model, null, request, collector);
+
+        assertEquals(List.of("${aa}"), out.getBuild().getFilters());
+        assertTrue(collector.getErrors().get(0).contains("recursive variable reference"));
+    }
+
     @Disabled("per def cannot be recursive: ${basedir} is immediately going for project.basedir")
     @Test
     public void testRecursiveExpressionCycleBaseDir() throws Exception {