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

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kit.git

commit 79ff4f9411447322b8ed7f6d13192e14a0a8a61e
Author: Jinal Sarvaiya <[email protected]>
AuthorDate: Wed Nov 11 21:36:37 2026 +0000

    Fix Spring Boot version detection to handle parent/import uncertainty
---
 .../apache/camel/kit/graph/ProjectDiscovery.java   | 49 +++++++++++++++-------
 .../camel/kit/graph/ProjectDiscoveryTest.java      | 47 ++++++++++++++++++---
 2 files changed, 75 insertions(+), 21 deletions(-)

diff --git 
a/kit/camel-kit-graph/src/main/java/org/apache/camel/kit/graph/ProjectDiscovery.java
 
b/kit/camel-kit-graph/src/main/java/org/apache/camel/kit/graph/ProjectDiscovery.java
index 6b0c4eda..88064a45 100644
--- 
a/kit/camel-kit-graph/src/main/java/org/apache/camel/kit/graph/ProjectDiscovery.java
+++ 
b/kit/camel-kit-graph/src/main/java/org/apache/camel/kit/graph/ProjectDiscovery.java
@@ -186,43 +186,60 @@ public final class ProjectDiscovery {
     /**
      * The Spring Boot framework version: an imported {@code 
spring-boot-dependencies}, otherwise the
      * {@code spring-boot-starter-parent} parent. This is a different artifact 
from the Camel BOM and is kept apart so
-     * the two are never mixed up. Returns null if modules disagree on the 
version.
+     * the two are never mixed up. Returns null if modules disagree on the 
version or if the effective version cannot be
+     * established from source-only evidence.
      * <p>
-     * Import-over-parent precedence is applied per module first, then 
effective versions are compared. A module that
-     * imports a version explicitly uses that version even if it also inherits 
a parent; modules without imports use
-     * their parent version. If effective versions disagree across modules, 
the project-wide constraint remains
-     * unresolved.
+     * Maven assembles inheritance before importing dependency management, and 
its importer preserves already-present
+     * management keys when processing imported BOMs. Therefore, when both a 
parent and an import are present with
+     * different versions, the effective framework version cannot be 
determined from POM source alone without executing
+     * Maven's model builder. In such cases, the version remains unresolved 
and discovery records a gap.
      */
     private static String detectSpringBootVersion(ProjectGraph graph) {
         Map<String, Set<String>> bomVersions = collectManagedVersions(graph, 
"spring-boot-dependencies");
         Map<String, Set<String>> parentVersions = collectParentVersions(graph, 
"spring-boot-starter-parent");
 
-        // Compute effective version per module: imports override parents
+        // Compute effective version per module, recognizing when source-only 
evidence is insufficient
         Map<String, String> effectiveVersions = new TreeMap<>();
         Set<String> allModules = new TreeSet<>();
         bomVersions.values().forEach(allModules::addAll);
         parentVersions.values().forEach(allModules::addAll);
 
         for (String module : allModules) {
-            // Check if this module has an explicit import
             String importVersion = null;
+            String parentVersion = null;
+
+            // Check if this module has an import
             for (Map.Entry<String, Set<String>> entry : 
bomVersions.entrySet()) {
                 if (entry.getValue().contains(module)) {
                     importVersion = entry.getKey();
                     break;
                 }
             }
-            if (importVersion != null) {
-                effectiveVersions.put(module, importVersion);
-            } else {
-                // No import, use parent if present
-                for (Map.Entry<String, Set<String>> entry : 
parentVersions.entrySet()) {
-                    if (entry.getValue().contains(module)) {
-                        effectiveVersions.put(module, entry.getKey());
-                        break;
-                    }
+
+            // Check if this module has a parent
+            for (Map.Entry<String, Set<String>> entry : 
parentVersions.entrySet()) {
+                if (entry.getValue().contains(module)) {
+                    parentVersion = entry.getKey();
+                    break;
                 }
             }
+
+            // Determine effective version for this module
+            if (importVersion != null && parentVersion != null) {
+                // Both present: can only establish version if they agree
+                if (importVersion.equals(parentVersion)) {
+                    effectiveVersions.put(module, importVersion);
+                } else {
+                    // Different versions: cannot determine effective version 
from source alone
+                    return null;
+                }
+            } else if (importVersion != null) {
+                // Only import present
+                effectiveVersions.put(module, importVersion);
+            } else if (parentVersion != null) {
+                // Only parent present
+                effectiveVersions.put(module, parentVersion);
+            }
         }
 
         // If all modules agree on the effective version, return it; otherwise 
return null
diff --git 
a/kit/camel-kit-graph/src/test/java/org/apache/camel/kit/graph/ProjectDiscoveryTest.java
 
b/kit/camel-kit-graph/src/test/java/org/apache/camel/kit/graph/ProjectDiscoveryTest.java
index ef4966cf..9ad1a52b 100644
--- 
a/kit/camel-kit-graph/src/test/java/org/apache/camel/kit/graph/ProjectDiscoveryTest.java
+++ 
b/kit/camel-kit-graph/src/test/java/org/apache/camel/kit/graph/ProjectDiscoveryTest.java
@@ -829,9 +829,11 @@ class ProjectDiscoveryTest {
     }
 
     @Test
-    void importOverridesParentInSameModule() {
-        // Single module inherits spring-boot-starter-parent:3.4.0 but 
explicitly imports
-        // spring-boot-dependencies:3.3.4 -> import wins
+    void cannotDetermineVersionWhenParentAndImportDisagree() {
+        // Single module inherits spring-boot-starter-parent:3.4.0 and also 
imports
+        // spring-boot-dependencies:3.3.4. Maven processes inheritance before 
imports
+        // and preserves existing management keys, so the effective version 
cannot be
+        // determined from POM source alone without executing Maven's model 
builder.
         ProjectGraph graph = new ProjectGraph();
         graph.addNode(springBootStarter("pom.xml"));
 
@@ -845,7 +847,42 @@ class ProjectDiscoveryTest {
                         "version", "3.4.0",
                         "file", "pom.xml")));
 
-        // But imports 3.3.4
+        // Also imports 3.3.4
+        graph.addNode(new GraphNode(
+                
"maven-managed:pom.xml:org.springframework.boot:spring-boot-dependencies",
+                NodeType.CONFIG_PROPERTY,
+                Map.of("kind", "managed",
+                        "groupId", "org.springframework.boot",
+                        "artifactId", "spring-boot-dependencies",
+                        "version", "3.3.4",
+                        "type", "pom",
+                        "scope", "import",
+                        "file", "pom.xml")));
+
+        ProjectDiscovery.DiscoveryResult result = 
ProjectDiscovery.discover(graph);
+
+        assertNull(result.springBootVersion(),
+                "Cannot determine effective version when parent and import 
disagree (source-only evidence insufficient)");
+        assertEquals("spring-boot", result.runtime());
+    }
+
+    @Test
+    void resolvesSameVersionWhenParentAndImportAgree() {
+        // When both parent and import declare the same version, that version 
can be established
+        ProjectGraph graph = new ProjectGraph();
+        graph.addNode(springBootStarter("pom.xml"));
+
+        // Inherits parent 3.3.4
+        graph.addNode(new GraphNode(
+                
"maven-parent:pom.xml:org.springframework.boot:spring-boot-starter-parent",
+                NodeType.CONFIG_PROPERTY,
+                Map.of("kind", "parent",
+                        "groupId", "org.springframework.boot",
+                        "artifactId", "spring-boot-starter-parent",
+                        "version", "3.3.4",
+                        "file", "pom.xml")));
+
+        // Also imports 3.3.4
         graph.addNode(new GraphNode(
                 
"maven-managed:pom.xml:org.springframework.boot:spring-boot-dependencies",
                 NodeType.CONFIG_PROPERTY,
@@ -860,7 +897,7 @@ class ProjectDiscoveryTest {
         ProjectDiscovery.DiscoveryResult result = 
ProjectDiscovery.discover(graph);
 
         assertEquals("3.3.4", result.springBootVersion(),
-                "Import should take precedence over parent in the same 
module");
+                "When parent and import agree on the same version, that 
version is established");
         assertEquals("spring-boot", result.runtime());
     }
 }

Reply via email to