diff --git a/its/scanner-integration-tests/pom.xml b/its/scanner-integration-tests/pom.xml
index a102f61cac4..aa013a94dbe 100644
--- a/its/scanner-integration-tests/pom.xml
+++ b/its/scanner-integration-tests/pom.xml
@@ -5,7 +5,7 @@
org.sonarsource.java
java-its
- 8.31.0-SNAPSHOT
+ 8.32.0-SNAPSHOT
it-java-scanner-integration-tests
diff --git a/java-frontend/src/main/java/org/sonar/java/JavaFrontend.java b/java-frontend/src/main/java/org/sonar/java/JavaFrontend.java
index 08530df3dea..b315122b452 100644
--- a/java-frontend/src/main/java/org/sonar/java/JavaFrontend.java
+++ b/java-frontend/src/main/java/org/sonar/java/JavaFrontend.java
@@ -42,6 +42,7 @@
import org.sonar.java.filters.SonarJavaIssueFilter;
import org.sonar.java.model.JParserConfig;
import org.sonar.java.model.VisitorsBridge;
+import org.sonar.java.model.springcontext.SpringContextModelGatherers;
import org.sonar.java.telemetry.Telemetry;
import org.sonar.java.telemetry.TelemetryKey;
import org.sonar.plugins.java.api.JavaCheck;
@@ -82,6 +83,9 @@ public JavaFrontend(JavaVersion javaVersion, SonarComponents sonarComponents, Me
List commonVisitors = new ArrayList<>();
commonVisitors.add(javaResourceLocator);
commonVisitors.add(new Java25FeaturesTelemetryVisitor(telemetry));
+ if (sonarComponents.getSpringContextModel() != null) {
+ commonVisitors.addAll(SpringContextModelGatherers.getAllGatherers());
+ }
if (postAnalysisIssueFilter != null) {
commonVisitors.add(postAnalysisIssueFilter);
}
diff --git a/java-frontend/src/main/java/org/sonar/java/SonarComponents.java b/java-frontend/src/main/java/org/sonar/java/SonarComponents.java
index e12c282caa6..014f230a1df 100644
--- a/java-frontend/src/main/java/org/sonar/java/SonarComponents.java
+++ b/java-frontend/src/main/java/org/sonar/java/SonarComponents.java
@@ -66,6 +66,7 @@
import org.sonar.java.model.GeneratedFile;
import org.sonar.java.model.JProblem;
import org.sonar.java.model.LineUtils;
+import org.sonar.java.model.springcontext.SpringContextModel;
import org.sonar.java.reporting.AnalyzerMessage;
import org.sonar.java.reporting.JavaIssue;
import org.sonar.java.utils.ModuleMetadataUtils;
@@ -136,12 +137,13 @@ public class SonarComponents extends CheckRegistrar.RegistrarContext {
private SensorContext context;
private UnaryOperator> checkFilter = UnaryOperator.identity();
private final Set additionalAutoScanCompatibleRuleKeys;
+ private SpringContextModel springContextModel;
private boolean alreadyLoggedSkipStatus = false;
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
- ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath,
- CheckFactory checkFactory, ActiveRules activeRules) {
+ ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath,
+ CheckFactory checkFactory, ActiveRules activeRules) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, null, null, null);
}
@@ -149,8 +151,8 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* Can be called in SonarLint context when custom rules are present.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
- ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
- ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars) {
+ ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
+ ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, checkRegistrars, null, null);
}
@@ -164,8 +166,8 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* Thus, for this constructor, we can also assume the presence of {@code CheckRegistrar} instances.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
- ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
- ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars, SonarLintCache sonarLintCache) {
+ ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
+ ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars, SonarLintCache sonarLintCache) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, checkRegistrars, null, sonarLintCache);
}
@@ -174,8 +176,8 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* May be called in some SonarLint contexts, but not others, since ProjectDefinition might not be available.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
- ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
- ActiveRules activeRules, @Nullable ProjectDefinition projectDefinition) {
+ ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
+ ActiveRules activeRules, @Nullable ProjectDefinition projectDefinition) {
this(fileLinesContextFactory, fs, javaClasspath, javaTestClasspath, checkFactory, activeRules, null, projectDefinition, null);
}
@@ -183,9 +185,9 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* May be called in some SonarLint contexts, but not others, since ProjectDefinition might not be available.
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
- ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
- ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
- @Nullable ProjectDefinition projectDefinition) {
+ ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
+ ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
+ @Nullable ProjectDefinition projectDefinition) {
this(
fileLinesContextFactory,
fs,
@@ -208,9 +210,9 @@ public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSyst
* (because ProjectDefinition can be available in recent SonarLint versions, and DBD provides a CheckRegistrar.)
*/
public SonarComponents(FileLinesContextFactory fileLinesContextFactory, FileSystem fs,
- ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
- ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
- @Nullable ProjectDefinition projectDefinition, @Nullable SonarLintCache sonarLintCache) {
+ ClasspathForMain javaClasspath, ClasspathForTest javaTestClasspath, CheckFactory checkFactory,
+ ActiveRules activeRules, @Nullable CheckRegistrar[] checkRegistrars,
+ @Nullable ProjectDefinition projectDefinition, @Nullable SonarLintCache sonarLintCache) {
this.fileLinesContextFactory = fileLinesContextFactory;
this.fs = fs;
this.javaClasspath = javaClasspath;
@@ -293,7 +295,7 @@ public void registerMainChecks(String repositoryKey, Collection> javaCheckClas
}
@Override
- public void registerMainChecks(Checks checks, Collection> javaCheckClassesAndInstances){
+ public void registerMainChecks(Checks checks, Collection> javaCheckClassesAndInstances) {
registerCheckClasses(mainChecks, checks, javaCheckClassesAndInstances);
}
@@ -339,7 +341,7 @@ private boolean hasAtLeastOneActiveRule(Collection ruleKeys) {
return ruleKeys.stream().anyMatch(ruleKey -> activeRules.find(ruleKey) != null);
}
- private Checks getCreatedCheckFromFactory(String repositoryKey, Collection> javaCheckClassesAndInstances){
+ private Checks getCreatedCheckFromFactory(String repositoryKey, Collection> javaCheckClassesAndInstances) {
return checkFactory.create(repositoryKey).addAnnotatedChecks(javaCheckClassesAndInstances);
}
@@ -646,7 +648,7 @@ private void logUndefinedTypes(int maxLines) {
}
private static void logParserMessages(Stream>> messages, int maxProblems, String warningMessage,
- String debugMessage) {
+ String debugMessage) {
String problemDelimiter = System.lineSeparator() + "- ";
List> messagesList = messages
.sorted(Comparator.comparing(entry -> entry.getKey().toString()))
@@ -692,4 +694,12 @@ public Configuration getConfiguration() {
return context.config();
}
+ public void setSpringContextModel(SpringContextModel springContextModel) {
+ this.springContextModel = springContextModel;
+ }
+
+ public SpringContextModel getSpringContextModel() {
+ return springContextModel;
+ }
+
}
diff --git a/java-frontend/src/main/java/org/sonar/java/model/DefaultModuleScannerContext.java b/java-frontend/src/main/java/org/sonar/java/model/DefaultModuleScannerContext.java
index 96b33879f2a..4f55991212e 100644
--- a/java-frontend/src/main/java/org/sonar/java/model/DefaultModuleScannerContext.java
+++ b/java-frontend/src/main/java/org/sonar/java/model/DefaultModuleScannerContext.java
@@ -25,6 +25,7 @@
import org.sonar.api.config.Configuration;
import org.sonar.java.SonarComponents;
import org.sonar.java.caching.CacheContextImpl;
+import org.sonar.java.model.springcontext.SpringContextModel;
import org.sonar.java.reporting.AnalyzerMessage;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.plugins.java.api.JavaVersion;
@@ -115,5 +116,8 @@ public Configuration getConfiguration() {
return sonarComponents.getConfiguration();
}
+ public SpringContextModel getSpringContextModel() {
+ return sonarComponents.getSpringContextModel();
+ }
}
diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModel.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModel.java
index d9ee0e64cce..c25706c762c 100644
--- a/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModel.java
+++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModel.java
@@ -16,6 +16,9 @@
*/
package org.sonar.java.model.springcontext;
+import org.sonar.api.scanner.ScannerSide;
+import org.sonarsource.api.sonarlint.SonarLintSide;
+
/**
* Aggregates all Spring context information collected during project scanning.
*
@@ -28,48 +31,35 @@
* {@link EntityClassToPropertiesIndex} — JPA {@code @Entity} class properties
*
*/
+@ScannerSide
+@SonarLintSide
public class SpringContextModel {
/** Registry of all bean definitions discovered during scanning. */
- private BeanDefinitionRegistry beanDefinitionRegistry;
+ private final BeanDefinitionRegistry beanDefinitionRegistry = new BeanDefinitionRegistry();
/** Packages registered for Spring component scanning, grouped by module. */
- private ProjectPackageScan projectPackageScan;
+ private final ProjectPackageScan projectPackageScan = new ProjectPackageScan();
/** Index for resolving bean names by their fully-qualified type. */
- private TypeToBeanNamesIndex typeToBeanNamesIndex;
+ private final TypeToBeanNamesIndex typeToBeanNamesIndex = new TypeToBeanNamesIndex();
/** Index of properties associated with Spring Data / Hibernate {@code @Entity} classes. */
- private EntityClassToPropertiesIndex entityClassToPropertiesIndex;
+ private final EntityClassToPropertiesIndex entityClassToPropertiesIndex = new EntityClassToPropertiesIndex();
public BeanDefinitionRegistry getBeanDefinitionRegistry() {
return beanDefinitionRegistry;
}
- public void setBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) {
- this.beanDefinitionRegistry = beanDefinitionRegistry;
- }
-
public ProjectPackageScan getProjectPackageScan() {
return projectPackageScan;
}
- public void setProjectPackageScan(ProjectPackageScan projectPackageScan) {
- this.projectPackageScan = projectPackageScan;
- }
-
public TypeToBeanNamesIndex getTypeToBeanNamesIndex() {
return typeToBeanNamesIndex;
}
- public void setTypeToBeanNamesIndex(TypeToBeanNamesIndex typeToBeanNamesIndex) {
- this.typeToBeanNamesIndex = typeToBeanNamesIndex;
- }
-
public EntityClassToPropertiesIndex getEntityClassToPropertiesIndex() {
return entityClassToPropertiesIndex;
}
- public void setEntityClassToPropertiesIndex(EntityClassToPropertiesIndex entityClassToPropertiesIndex) {
- this.entityClassToPropertiesIndex = entityClassToPropertiesIndex;
- }
-}
\ No newline at end of file
+}
diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModelGatherer.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModelGatherer.java
new file mode 100644
index 00000000000..71204364628
--- /dev/null
+++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModelGatherer.java
@@ -0,0 +1,42 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.java.model.springcontext;
+
+import org.sonar.java.ast.visitors.SubscriptionVisitor;
+import org.sonar.java.model.DefaultModuleScannerContext;
+import org.sonar.plugins.java.api.ModuleScannerContext;
+import org.sonar.plugins.java.api.internal.EndOfAnalysis;
+
+/**
+ * Base class for visitors that need to gather data in the SpringContextModel at the end of the analysis.
+ * Extending classes will have to implement the AST visitor pattern, gather relevant spring-related data, and store it
+ * in the SpringContextModel at the of a module analysis.
+ */
+public abstract class SpringContextModelGatherer extends SubscriptionVisitor implements EndOfAnalysis {
+
+ @Override
+ public final void endOfAnalysis(ModuleScannerContext context) {
+ var defaultModuleContext = (DefaultModuleScannerContext) context;
+ gatherSpringContextData(context, defaultModuleContext.getSpringContextModel());
+ }
+
+ /**
+ * Method called at the end of the analysis of a module, allowing to store gathered data in the SpringContextModel.
+ */
+ public abstract void gatherSpringContextData(ModuleScannerContext context, SpringContextModel springContextModel);
+
+}
diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModelGatherers.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModelGatherers.java
new file mode 100644
index 00000000000..8d012038d34
--- /dev/null
+++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModelGatherers.java
@@ -0,0 +1,34 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.java.model.springcontext;
+
+import java.util.List;
+import org.sonar.plugins.java.api.JavaCheck;
+
+public class SpringContextModelGatherers {
+
+ private SpringContextModelGatherers() {
+ // utility class, should not be instantiated
+ }
+
+ public static List getAllGatherers() {
+ return List.of(
+ // example: new SampleSpringContextModelGatherer()
+ );
+ }
+
+}
diff --git a/java-frontend/src/test/java/org/sonar/java/model/springcontext/SpringContextModelGathererTest.java b/java-frontend/src/test/java/org/sonar/java/model/springcontext/SpringContextModelGathererTest.java
new file mode 100644
index 00000000000..bc2c879fd15
--- /dev/null
+++ b/java-frontend/src/test/java/org/sonar/java/model/springcontext/SpringContextModelGathererTest.java
@@ -0,0 +1,73 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.java.model.springcontext;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+import org.sonar.java.SonarComponents;
+import org.sonar.java.TestUtils;
+import org.sonar.java.model.JParserTestUtils;
+import org.sonar.java.model.VisitorsBridge;
+import org.sonar.plugins.java.api.JavaCheck;
+import org.sonar.plugins.java.api.ModuleScannerContext;
+import org.sonar.plugins.java.api.tree.Tree;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class SpringContextModelGathererTest {
+
+ private final SpringContextModel model = new SpringContextModel();
+
+ @Test
+ void testGatherSpringContextData() {
+ getSpringModelAfterVisitingFile("src/test/files/model/SimpleClass.java", new SampleGatherer());
+ assertThat(model.getTypeToBeanNamesIndex().getNamesForType("com.example.MyService")).containsExactly("myServiceBean");
+ }
+
+ private void getSpringModelAfterVisitingFile(String filePath, JavaCheck check) {
+ File file = new File(filePath);
+ InputFile inputFile = TestUtils.inputFile(file);
+ var compilationUnit = JParserTestUtils.parse(file);
+ SensorContextTester sensorContextTester = SensorContextTester.create(new File(""));
+ var sonarComponents = new SonarComponents(null, null, null, null, null, null);
+ sonarComponents.setSensorContext(sensorContextTester);
+ sonarComponents.setSpringContextModel(model);
+
+ VisitorsBridge visitorsBridge = new VisitorsBridge(List.of(check), new ArrayList<>(), sonarComponents);
+ visitorsBridge.setCurrentFile(inputFile);
+ visitorsBridge.visitFile(compilationUnit, false);
+ visitorsBridge.endOfAnalysis();
+ }
+
+ class SampleGatherer extends SpringContextModelGatherer {
+
+ @Override
+ public void gatherSpringContextData(ModuleScannerContext context, SpringContextModel springContextModel) {
+ springContextModel.getTypeToBeanNamesIndex().addBeanForType("com.example.MyService", "myServiceBean");
+ }
+
+ @Override
+ public List nodesToVisit() {
+ return List.of();
+ }
+ }
+
+}
diff --git a/java-frontend/src/test/java/org/sonar/java/model/springcontext/SpringContextModelTest.java b/java-frontend/src/test/java/org/sonar/java/model/springcontext/SpringContextModelTest.java
new file mode 100644
index 00000000000..b207ce9f29e
--- /dev/null
+++ b/java-frontend/src/test/java/org/sonar/java/model/springcontext/SpringContextModelTest.java
@@ -0,0 +1,35 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.java.model.springcontext;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class SpringContextModelTest {
+
+ @Test
+ void testInitialization() {
+ SpringContextModel model = new SpringContextModel();
+
+ assertNotNull(model.getBeanDefinitionRegistry(), "BeanDefinitionRegistry should be initialized");
+ assertNotNull(model.getProjectPackageScan(), "ProjectPackageScan should be initialized");
+ assertNotNull(model.getTypeToBeanNamesIndex(), "TypeToBeanNamesIndex should be initialized");
+ assertNotNull(model.getEntityClassToPropertiesIndex(), "EntityClassToPropertiesIndex should be initialized");
+ }
+
+}
diff --git a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaPlugin.java b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaPlugin.java
index f013d3e1f67..ed36a74d000 100644
--- a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaPlugin.java
+++ b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaPlugin.java
@@ -37,6 +37,7 @@
import org.sonar.java.classpath.ClasspathProperties;
import org.sonar.java.filters.PostAnalysisIssueFilter;
import org.sonar.java.jsp.Jasper;
+import org.sonar.java.model.springcontext.SpringContextModel;
import org.sonar.java.telemetry.NoOpTelemetry;
import org.sonar.java.telemetry.DefaultTelemetry;
import org.sonar.plugins.java.api.JavaVersion;
@@ -84,6 +85,7 @@ public void define(Context context) {
.onConfigScopes(Set.of(PropertyDefinition.ConfigScope.PROJECT))
.build(),
JavaRulesDefinition.class,
+ SpringContextModel.class,
SonarComponents.class,
DefaultJavaResourceLocator.class,
PropertyDefinition.builder(JavaVersion.ENABLE_PREVIEW)
@@ -116,6 +118,7 @@ public void define(Context context) {
.defaultValue("False")
.build(),
JavaSensor.class,
+ SpringContextModelSensor.class,
PostAnalysisIssueFilter.class));
list.add(AnalysisWarningsWrapper.class);
diff --git a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaSensor.java b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaSensor.java
index 1bd10a5ac60..0358cc1d842 100644
--- a/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaSensor.java
+++ b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/JavaSensor.java
@@ -43,6 +43,7 @@
import org.sonar.java.jsp.Jasper;
import org.sonar.java.model.GeneratedFile;
import org.sonar.java.model.JavaVersionImpl;
+import org.sonar.java.model.springcontext.SpringContextModel;
import org.sonar.java.telemetry.Telemetry;
import org.sonar.plugins.java.api.JavaCheck;
import org.sonar.plugins.java.api.JavaResourceLocator;
@@ -74,13 +75,14 @@ public class JavaSensor implements Sensor {
private final Telemetry telemetry;
public JavaSensor(SonarComponents sonarComponents, FileSystem fs, JavaResourceLocator javaResourceLocator,
- Configuration settings, NoSonarFilter noSonarFilter, PostAnalysisIssueFilter postAnalysisIssueFilter, Telemetry telemetry) {
- this(sonarComponents, fs, javaResourceLocator, settings, noSonarFilter, postAnalysisIssueFilter, null, telemetry);
+ Configuration settings, NoSonarFilter noSonarFilter, PostAnalysisIssueFilter postAnalysisIssueFilter,
+ Telemetry telemetry, SpringContextModel springContextModel) {
+ this(sonarComponents, fs, javaResourceLocator, settings, noSonarFilter, postAnalysisIssueFilter, null, telemetry, springContextModel);
}
public JavaSensor(SonarComponents sonarComponents, FileSystem fs, JavaResourceLocator javaResourceLocator,
- Configuration settings, NoSonarFilter noSonarFilter,
- PostAnalysisIssueFilter postAnalysisIssueFilter, @Nullable Jasper jasper, Telemetry telemetry) {
+ Configuration settings, NoSonarFilter noSonarFilter, PostAnalysisIssueFilter postAnalysisIssueFilter,
+ @Nullable Jasper jasper, Telemetry telemetry, SpringContextModel springContextModel) {
this.noSonarFilter = noSonarFilter;
this.sonarComponents = sonarComponents;
this.fs = fs;
@@ -91,6 +93,7 @@ public JavaSensor(SonarComponents sonarComponents, FileSystem fs, JavaResourceLo
this.telemetry = telemetry;
this.sonarComponents.registerMainChecks(GeneratedCheckList.REPOSITORY_KEY, GeneratedCheckList.getJavaChecks());
this.sonarComponents.registerTestChecks(GeneratedCheckList.REPOSITORY_KEY, GeneratedCheckList.getJavaTestChecks());
+ this.sonarComponents.setSpringContextModel(springContextModel);
}
@Override
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
new file mode 100644
index 00000000000..0a925a651da
--- /dev/null
+++ b/sonar-java-plugin/src/main/java/org/sonar/plugins/java/SpringContextModelSensor.java
@@ -0,0 +1,44 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.plugins.java;
+
+import org.sonar.api.batch.Phase;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.scanner.sensor.ProjectSensor;
+import org.sonar.java.jsp.Jasper;
+import org.sonar.java.model.springcontext.SpringContextModel;
+
+@Phase(name = Phase.Name.POST)
+public class SpringContextModelSensor implements ProjectSensor {
+
+ private final SpringContextModel springContextModel;
+
+ public SpringContextModelSensor(SpringContextModel springContextModel) {
+ this.springContextModel = springContextModel;
+ }
+
+ @Override
+ public void describe(SensorDescriptor descriptor) {
+ descriptor.onlyOnLanguages(Java.KEY, Jasper.JSP_LANGUAGE_KEY).name("Java SpringContextModelSensor");
+ }
+
+ @Override
+ public void execute(SensorContext context) {
+ // Nothing to do for now
+ }
+}
diff --git a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaPluginTest.java b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaPluginTest.java
index 40dc64634bb..7f36b04670f 100644
--- a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaPluginTest.java
+++ b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaPluginTest.java
@@ -40,7 +40,7 @@ void sonarLint_9_9_extensions() {
Plugin.Context context = new Plugin.Context(runtime);
javaPlugin.define(context);
assertThat(context.getExtensions())
- .hasSize(20)
+ .hasSize(22)
.contains(SonarLintCache.class);
}
@@ -51,7 +51,7 @@ void sonarqube_9_9_extensions() {
Plugin.Context context = new Plugin.Context(sqCommunity);
javaPlugin.define(context);
assertThat(context.getExtensions())
- .hasSize(37)
+ .hasSize(39)
.doesNotContain(Jasper.class);
}
@@ -61,7 +61,7 @@ void sonarqube_9_9_commercial_extensions() {
Plugin.Context context = new Plugin.Context(sqEnterprise);
javaPlugin.define(context);
assertThat(context.getExtensions())
- .hasSize(38)
+ .hasSize(40)
.contains(Jasper.class);
}
diff --git a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaSensorTest.java b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaSensorTest.java
index 76b3573c242..2ba50f5eadf 100644
--- a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaSensorTest.java
+++ b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaSensorTest.java
@@ -113,7 +113,7 @@ class JavaSensorTest {
@Test
void test_toString() throws IOException {
SonarComponents sonarComponents = createSonarComponentsMock(createContext(InputFile.Type.MAIN));
- assertThat(new JavaSensor(sonarComponents, null, null, null, null, null, telemetry)).hasToString("JavaSensor");
+ assertThat(new JavaSensor(sonarComponents, null, null, null, null, null, telemetry, null)).hasToString("JavaSensor");
}
@Test
@@ -181,7 +181,7 @@ private void testIssueCreation(InputFile.Type onType, int expectedIssues) throws
SonarComponents sonarComponents = createSonarComponentsMock(context);
DefaultJavaResourceLocator javaResourceLocator = createDefaultJavaResourceLocator(settings.asConfig(), fs);
- JavaSensor jss = new JavaSensor(sonarComponents, fs, javaResourceLocator, settings.asConfig(), noSonarFilter, null, telemetry);
+ JavaSensor jss = new JavaSensor(sonarComponents, fs, javaResourceLocator, settings.asConfig(), noSonarFilter, null, telemetry, null);
jss.execute(context);
int expectedNoSonarLine = lineNumberOfTheMethodWithNoSonar(fs);
@@ -282,7 +282,7 @@ private void assertJasperIsInvoked(MapSettings settings) throws IOException {
Jasper jasper = mock(Jasper.class);
when(jasper.generateFiles(any(), any())).thenReturn(asList(generatedFile));
JavaSensor jss = new JavaSensor(sonarComponents, context.fileSystem(), mock(JavaResourceLocator.class),
- new MapSettings().asConfig(), mock(NoSonarFilter.class), null, jasper, telemetry);
+ new MapSettings().asConfig(), mock(NoSonarFilter.class), null, jasper, telemetry, null);
jss.execute(context);
ArgumentCaptor scannerContext = ArgumentCaptor.forClass(JavaFileScannerContext.class);
@@ -310,7 +310,7 @@ void should_not_invoke_jasper_jsp_compilation_in_autoscan_for_security_reasons()
Jasper jasper = mock(Jasper.class);
JavaSensor jss = new JavaSensor(sonarComponents, context.fileSystem(), mock(JavaResourceLocator.class),
- context.config(), mock(NoSonarFilter.class), null, jasper, telemetry);
+ context.config(), mock(NoSonarFilter.class), null, jasper, telemetry, null);
jss.execute(context);
verify(jasper, never()).generateFiles(any(), any());
@@ -501,7 +501,7 @@ void custom_file_scanner_is_not_filtered_in_autoscan() throws IOException {
SonarComponents components = new SonarComponents(fileLinesContextFactory, fs,
javaClasspath, javaTestClasspath, specificCheckFactory, context.activeRules(), checkRegistrars, null, null);
- JavaSensor jss = new JavaSensor(components, fs, resourceLocator, context.config(), mock(NoSonarFilter.class), null, telemetry);
+ JavaSensor jss = new JavaSensor(components, fs, resourceLocator, context.config(), mock(NoSonarFilter.class), null, telemetry, null);
jss.execute(context);
assertThat(hook.scanFileCount).as("Custom file scanner should be called even in autoscan mode").isPositive();
@@ -516,7 +516,7 @@ void custom_file_scanner_is_not_filtered_in_autoscan() throws IOException {
void test_describe_sensor() throws IOException {
DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
SonarComponents sonarComponents = createSonarComponentsMock(createContext(InputFile.Type.MAIN));
- var sensor = new JavaSensor(sonarComponents, null, null, null, null, null, telemetry);
+ var sensor = new JavaSensor(sonarComponents, null, null, null, null, null, telemetry, null);
sensor.describe(descriptor);
assertThat(descriptor.name()).isEqualTo("JavaSensor");
assertThat(descriptor.languages()).containsExactly("java", "jsp");
@@ -562,7 +562,7 @@ private SensorContextTester analyzeTwoFilesWithIssues(MapSettings settings) thro
SonarComponents components = new SonarComponents(fileLinesContextFactory, fs,
javaClasspath, javaTestClasspath, specificCheckFactory, context.activeRules(), checkRegistrars, null, null);
- JavaSensor jss = new JavaSensor(components, fs, resourceLocator, context.config(), mock(NoSonarFilter.class), null, telemetry);
+ JavaSensor jss = new JavaSensor(components, fs, resourceLocator, context.config(), mock(NoSonarFilter.class), null, telemetry, null);
jss.execute(context);
return context;
}
@@ -576,7 +576,7 @@ private void executeJavaSensorForPerformanceMeasure(MapSettings settings, Path w
fs.setWorkDir(workDir);
SonarComponents components = createSonarComponentsMock(context);
DefaultJavaResourceLocator resourceLocator = createDefaultJavaResourceLocator(context.config(), fs);
- JavaSensor jss = new JavaSensor(components, fs, resourceLocator, configuration, mock(NoSonarFilter.class), null, telemetry);
+ JavaSensor jss = new JavaSensor(components, fs, resourceLocator, configuration, mock(NoSonarFilter.class), null, telemetry, null);
jss.execute(context);
}
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
new file mode 100644
index 00000000000..d0796f6e08c
--- /dev/null
+++ b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/SpringContextModelSensorTest.java
@@ -0,0 +1,36 @@
+/*
+ * SonarQube Java
+ * Copyright (C) SonarSource Sàrl
+ * mailto:info AT sonarsource DOT com
+ *
+ * You can redistribute and/or modify this program under the terms of
+ * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Sonar Source-Available License for more details.
+ *
+ * You should have received a copy of the Sonar Source-Available License
+ * along with this program; if not, see https://sonarsource.com/license/ssal/
+ */
+package org.sonar.plugins.java;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
+import org.sonar.java.model.springcontext.SpringContextModel;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class SpringContextModelSensorTest {
+
+ @Test
+ void test_toString() {
+ DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
+ SpringContextModelSensor sensor = new SpringContextModelSensor(new SpringContextModel());
+ sensor.describe(descriptor);
+ assertThat(descriptor.name()).isEqualTo("Java SpringContextModelSensor");
+ assertThat(descriptor.languages()).containsExactly("java", "jsp");
+ }
+
+}