From 6feb0f135d1a81c7b4964df6e41c6c4cc73b00e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Coet?= Date: Thu, 15 Oct 2026 14:00:35 +0200 Subject: [PATCH 1/4] Log when no Spring context model file is found at the start of an analysis --- .../org/sonar/plugins/java/SpringContextModelPersistence.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java index d2cd0bd4fa0..98d767e7fab 100644 --- a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java +++ b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java @@ -48,6 +48,7 @@ static Path modelPath(SensorContext context, File rootDirectory) { static SpringContextGatheringModel load(Path path) { if (!Files.exists(path)) { + LOG.warn("Spring context model file does not exist: {}. Starting with an empty Spring context.", path); return new SpringContextGatheringModel(); } try (var reader = Files.newBufferedReader(path, UTF_8)) { From eae0c45d5079156fc2b673300005d50f130c0279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Coet?= Date: Thu, 15 Oct 2026 14:15:38 +0200 Subject: [PATCH 2/4] Log on successful load as well --- .../org/sonar/plugins/java/SpringContextModelPersistence.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java index 98d767e7fab..7c1e6a62802 100644 --- a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java +++ b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelPersistence.java @@ -56,6 +56,7 @@ static SpringContextGatheringModel load(Path path) { if (model == null) { throw new IllegalArgumentException("JSON document is empty"); } + LOG.info("Restoring model from file {}.", path); return model; } catch (IOException | RuntimeException e) { LOG.warn("Unable to load Spring context model from {}, starting from an empty model", path, e); From a343f7cba07a66c4c03575a033545344a9370468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Coet?= Date: Thu, 15 Oct 2026 17:07:14 +0200 Subject: [PATCH 3/4] Log info about the restored modules, beans and packages in the Spring context --- .../SpringContextGatheringModel.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextGatheringModel.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextGatheringModel.java index aeb60261e56..e33a5820e35 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextGatheringModel.java +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextGatheringModel.java @@ -24,6 +24,8 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.scanner.ScannerSide; import org.sonar.java.serialization.SpringContextGatheringModelTypeAdapter; @@ -46,6 +48,8 @@ @JsonAdapter(SpringContextGatheringModelTypeAdapter.class) public class SpringContextGatheringModel { + private static final Logger LOG = LoggerFactory.getLogger(SpringContextGatheringModel.class); + public static final class InputFileData { @Nullable private InputFile inputFile; @@ -105,11 +109,19 @@ public void restoreFrom(SpringContextGatheringModel previous) { if (restored) { return; } - previous.filesData.forEach((moduleKey, moduleData) -> { - Map current = filesData.computeIfAbsent(moduleKey, key -> new HashMap<>()); - moduleData.forEach(current::putIfAbsent); - }); + int beanCount = 0; + int packageCount = 0; + for (var moduleEntry : previous.filesData.entrySet()) { + Map current = filesData.computeIfAbsent(moduleEntry.getKey(), key -> new HashMap<>()); + for (var fileEntry : moduleEntry.getValue().entrySet()) { + if (current.putIfAbsent(fileEntry.getKey(), fileEntry.getValue()) == null) { + beanCount += fileEntry.getValue().beans().size(); + packageCount += fileEntry.getValue().packages().size(); + } + } + } restored = true; + LOG.info("Restored Spring context: {} modules, {} beans, {} packages.", previous.filesData.size(), beanCount, packageCount); } /** From 5579739cf100c377f0c015a50c802c8124f296e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Coet?= Date: Fri, 16 Oct 2026 13:47:48 +0200 Subject: [PATCH 4/4] Log when files are removed from the Spring context --- .../sonar/plugins/java/SpringContextModelSensor.java | 11 +++++++++++ .../plugins/java/SpringContextModelSensorTest.java | 2 ++ 2 files changed, 13 insertions(+) diff --git a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelSensor.java b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelSensor.java index 3f15140e577..f826735886f 100644 --- a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelSensor.java +++ b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelSensor.java @@ -17,6 +17,8 @@ package org.sonar.plugins.java; import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.SonarProduct; import org.sonar.api.batch.DependedUpon; import org.sonar.api.batch.Phase; @@ -54,6 +56,8 @@ @DependedUpon(value = "CollectSpringContextBeforeSendingTelemetry") public class SpringContextModelSensor implements ProjectSensor { + private static final Logger LOG = LoggerFactory.getLogger(SpringContextModelSensor.class); + private final Telemetry telemetry; private final SpringContextGatheringModel gatheringModel; @@ -77,7 +81,14 @@ public void describe(SensorDescriptor descriptor) { @Override public void execute(SensorContext context) { if (isFullProjectAnalysis(context)) { + long unvisitedFileCount = gatheringModel.filesData().values().stream() + .flatMap(files -> files.values().stream()) + .filter(data -> data.inputFile() == null) + .count(); gatheringModel.removeUnvisitedFiles(); + if (unvisitedFileCount > 0) { + LOG.warn("Removed {} unvisited files from the Spring context gathering model during full project analysis.", unvisitedFileCount); + } } long buildingStartTime = System.nanoTime(); SpringContextModel springContextModel = SpringContextModel.of(gatheringModel); diff --git a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/SpringContextModelSensorTest.java b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/SpringContextModelSensorTest.java index 3424f8a8387..6a4e29fe382 100644 --- a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/SpringContextModelSensorTest.java +++ b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/SpringContextModelSensorTest.java @@ -166,6 +166,8 @@ void removes_unvisited_files_before_building_and_saving_the_model_on_full_analys assertThat(context.allIssues()).isEmpty(); assertThat(gatheringModel.filesData().get(MODULE_KEY)).containsOnlyKeys("currentService", "consumer"); + assertThat(logTester.logs(Level.WARN)) + .contains("Removed 1 unvisited files from the Spring context gathering model during full project analysis."); assertThat(telemetry.toMap()) .containsEntry("java.spring.bean_count", "2") .containsEntry("java.spring.component_scan_package_count", "0");