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"); + } + +}