From 65264069fda821a7b7daeccf31ba8a85885604ff Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Mon, 1 Jun 2026 13:09:47 +0200 Subject: [PATCH 1/4] Add Spring context model classes with Javadoc Introduce the springcontext package with BeanDefinitionHolder, BeanDefinitionRegistry, BeanLocation, EntityClassToPropertiesIndex, ProjectPackageScan, SpringContextModel, and TypeToBeanNamesIndex. All classes include Javadoc documentation. Co-Authored-By: Claude Sonnet 4.6 --- .../springcontext/BeanDefinitionHolder.java | 155 ++++++++++++++++++ .../springcontext/BeanDefinitionRegistry.java | 48 ++++++ .../model/springcontext/BeanLocation.java | 29 ++++ .../EntityClassToPropertiesIndex.java | 56 +++++++ .../springcontext/ProjectPackageScan.java | 62 +++++++ .../springcontext/SpringContextModel.java | 75 +++++++++ .../springcontext/TypeToBeanNamesIndex.java | 56 +++++++ 7 files changed, 481 insertions(+) create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanLocation.java create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/EntityClassToPropertiesIndex.java create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/ProjectPackageScan.java create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModel.java create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/TypeToBeanNamesIndex.java diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java new file mode 100644 index 00000000000..3867529b013 --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java @@ -0,0 +1,155 @@ +/* + * 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.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +/** + * Immutable representation of a Spring bean definition discovered during project scanning. + * + *

Captures the bean's fully-qualified type, the module and package it belongs to, + * its source {@link BeanLocation location}, and optional metadata such as active profiles, + * dependency names, and whether the bean is marked as {@code @Primary}. + * + *

Use {@link Builder} to construct instances: + *

{@code
+ * BeanDefinitionHolder bean = new BeanDefinitionHolder.Builder(type, module, pkg, location)
+ *     .profiles("prod")
+ *     .primary()
+ *     .build();
+ * }
+ * + * @see BeanDefinitionRegistry + * @see BeanLocation + */ +public class BeanDefinitionHolder { + /** Fully-qualified class name of the bean. */ + private final String type; + + /** Module in which the bean is declared. */ + private final String module; + + /** Package of the bean's declaring class. */ + private final String beanPackage; + + /** Source location where the bean definition appears. */ + private final BeanLocation location; + + /** Names of other beans this bean depends on. */ + private List dependingBeans; + + /** Comma-separated Spring profile expressions under which this bean is active, or {@code null} if unconditional. */ + @Nullable + private String profiles; + + /** Whether the bean is marked as {@code @Primary}, making it the preferred candidate for autowiring. */ + private boolean isPrimary = false; + + private BeanDefinitionHolder(String type, String module, String beanPackage, BeanLocation location) { + this.type = type; + this.module = module; + this.beanPackage = beanPackage; + this.location = location; + } + + private void setDependingBeans(List beansList) { + this.dependingBeans = beansList; + } + + private void setProfiles(@Nullable String profiles) { + this.profiles = profiles; + } + + private void setPrimary() { + this.isPrimary = true; + } + + public String getType() { + return type; + } + + public String getModule() { + return module; + } + + public String getBeanPackage() { + return beanPackage; + } + + public BeanLocation getLocation() { + return location; + } + + public List getDependingBeans() { + return dependingBeans; + } + + @Nullable + public String getProfiles() { + return profiles; + } + + public boolean isPrimary() { + return isPrimary; + } + + public static class Builder { + private final String type; + private final String module; + private final String beanPackage; + private final BeanLocation location; + private List dependingBeans = new ArrayList<>(); + @Nullable + private String profiles; + private boolean isPrimary = false; + + public Builder(String type, String module, String beanPackage, BeanLocation location) { + this.type = type; + this.module = module; + this.beanPackage = beanPackage; + this.location = location; + } + + public Builder dependingBeans(List beansList) { + this.dependingBeans = beansList; + return this; + } + + public Builder profiles(@Nullable String profiles) { + this.profiles = profiles; + return this; + } + + public Builder primary() { + this.isPrimary = true; + return this; + } + + public BeanDefinitionHolder build() { + BeanDefinitionHolder holder = new BeanDefinitionHolder(type, module, beanPackage, location); + holder.setDependingBeans(Collections.unmodifiableList(dependingBeans)); + holder.setProfiles(profiles); + if (isPrimary) { + holder.setPrimary(); + } + return holder; + } + } +} diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java new file mode 100644 index 00000000000..457f2b61fe1 --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java @@ -0,0 +1,48 @@ +/* + * 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.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Tracks {@link BeanDefinitionHolder bean definitions} collected during Spring context scanning, + * indexed by bean name. + * + *

Multiple definitions registered under the same name are preserved rather than overwritten, + * allowing callers to detect and report duplicate bean declarations. + * + * @see BeanDefinitionHolder + */ +public class BeanDefinitionRegistry { + /** + * Maps bean names to their corresponding list of {@link BeanDefinitionHolder} instances. + * A list is used as the value to capture duplicate bean definitions under the same name, + * which is an invalid state that should be reported during analysis. + */ + private final Map> beanDefinitionRegistry = new HashMap<>(); + + public List getByName(String beanName) { + return beanDefinitionRegistry.getOrDefault(beanName, List.of()); + } + + public void addBeanDefinition(String beanName, BeanDefinitionHolder beanDefinition) { + beanDefinitionRegistry.computeIfAbsent(beanName, k -> new ArrayList<>()).add(beanDefinition); + } +} diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanLocation.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanLocation.java new file mode 100644 index 00000000000..34e71de346b --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanLocation.java @@ -0,0 +1,29 @@ +/* + * 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.api.batch.fs.InputFile; +import org.sonar.java.reporting.AnalyzerMessage; + +/** + * Source location of a Spring bean definition within the project. + * + * @param inputFile the file in which the bean is declared + * @param mainLocation the precise text span of the bean declaration, used for reporting issues + */ +public record BeanLocation(InputFile inputFile, AnalyzerMessage.TextSpan mainLocation) { +} diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/EntityClassToPropertiesIndex.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/EntityClassToPropertiesIndex.java new file mode 100644 index 00000000000..7f9e4091fde --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/EntityClassToPropertiesIndex.java @@ -0,0 +1,56 @@ +/* + * 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.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Index mapping JPA / Hibernate {@code @Entity} class names to their associated + * key-value properties collected during scanning. + * + *

Multiple properties can be registered for the same entity class. + * Lookup returns an empty set for entity classes that have no registered properties. + */ +public class EntityClassToPropertiesIndex { + /** Properties indexed by fully-qualified {@code @Entity} class name. */ + private final Map>> propertiesByEntityClass = new HashMap<>(); + + /** + * Registers a property for the given {@code @Entity} class. + * + * @param entityClass fully-qualified name of the {@code @Entity} class + * @param propertyKey the property name + * @param propertyValue the property value + */ + public void addProperty(String entityClass, String propertyKey, String propertyValue) { + propertiesByEntityClass.computeIfAbsent(entityClass, k -> new HashSet<>()).add(Map.entry(propertyKey, propertyValue)); + } + + /** + * Returns an immutable set of all properties registered for the given {@code @Entity} class. + * + * @param entityClass fully-qualified name of the {@code @Entity} class + * @return an unmodifiable set of key-value property entries, or an empty set if none were registered + */ + public Set> getPropertiesForEntity(String entityClass) { + return Collections.unmodifiableSet(propertiesByEntityClass.getOrDefault(entityClass, Set.of())); + } +} \ No newline at end of file diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/ProjectPackageScan.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/ProjectPackageScan.java new file mode 100644 index 00000000000..1bfd45958ec --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/ProjectPackageScan.java @@ -0,0 +1,62 @@ +/* + * 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.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Tracks the packages registered for Spring component scanning, grouped by module. + * + *

Corresponds to packages declared via {@code @ComponentScan} (or equivalent) and + * collected during project analysis. Each module may declare multiple scanned packages. + */ +public class ProjectPackageScan { + /** Scanned package names indexed by module name. */ + private final Map> packagesScannedBySpringPerModule = new HashMap<>(); + + /** + * Registers a package as scanned by Spring for the given module. + * + * @param module the module in which the component scan is configured + * @param packageName the package name declared for scanning + */ + public void addPackage(String module, String packageName) { + packagesScannedBySpringPerModule.computeIfAbsent(module, k -> new HashSet<>()).add(packageName); + } + + /** + * Returns the set of packages scanned by Spring for the given module. + * + * @param module the module name + * @return the scanned package names, or an empty set if none were registered + */ + public Set getPackagesForModule(String module) { + return packagesScannedBySpringPerModule.getOrDefault(module, Set.of()); + } + + /** + * Returns all modules that have at least one registered scanned package. + * + * @return the set of module names + */ + public Set getModules() { + return packagesScannedBySpringPerModule.keySet(); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..d9ee0e64cce --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/SpringContextModel.java @@ -0,0 +1,75 @@ +/* + * 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; + +/** + * Aggregates all Spring context information collected during project scanning. + * + *

Acts as the top-level model passed to rules that need to reason about the Spring + * application context. Each field is a specialized index populated during the scan phase: + *

    + *
  • {@link BeanDefinitionRegistry} — bean definitions indexed by bean name
  • + *
  • {@link ProjectPackageScan} — packages registered for component scanning, per module
  • + *
  • {@link TypeToBeanNamesIndex} — bean names indexed by type
  • + *
  • {@link EntityClassToPropertiesIndex} — JPA {@code @Entity} class properties
  • + *
+ */ +public class SpringContextModel { + /** Registry of all bean definitions discovered during scanning. */ + private BeanDefinitionRegistry beanDefinitionRegistry; + + /** Packages registered for Spring component scanning, grouped by module. */ + private ProjectPackageScan projectPackageScan; + + /** Index for resolving bean names by their fully-qualified type. */ + private TypeToBeanNamesIndex typeToBeanNamesIndex; + + /** Index of properties associated with Spring Data / Hibernate {@code @Entity} classes. */ + private EntityClassToPropertiesIndex 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/TypeToBeanNamesIndex.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/TypeToBeanNamesIndex.java new file mode 100644 index 00000000000..b21e6e561af --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/TypeToBeanNamesIndex.java @@ -0,0 +1,56 @@ +/* + * 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.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Index mapping fully-qualified bean type names to the names of all beans of that type + * discovered during Spring context scanning. + * + *

A single type may have multiple bean names registered (e.g. when the same class is + * declared as several distinct beans). Lookup returns an empty set for types with no + * registered beans. + */ +public class TypeToBeanNamesIndex { + /** Bean names indexed by fully-qualified type name. */ + private final Map> beanNamesByType = new HashMap<>(); + + /** + * Registers a bean name under the given type. + * + * @param beanType fully-qualified class name of the bean's type + * @param beanName the bean name to associate with that type + */ + public void addBeanForType(String beanType, String beanName) { + beanNamesByType.computeIfAbsent(beanType, k -> new HashSet<>()).add(beanName); + } + + /** + * Returns an immutable set of all bean names registered for the given type. + * + * @param beanType fully-qualified class name of the bean's type + * @return an unmodifiable set of bean names, or an empty set if none were registered + */ + public Set getNamesForType(String beanType) { + return Collections.unmodifiableSet(beanNamesByType.getOrDefault(beanType, Set.of())); + } +} \ No newline at end of file From 587b5a4912454af81833f6f748e8f9308fbdb0fe Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Mon, 1 Jun 2026 13:11:48 +0200 Subject: [PATCH 2/4] Add package-info.java for springcontext package Co-Authored-By: Claude Sonnet 4.6 --- .../model/springcontext/package-info.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 java-frontend/src/main/java/org/sonar/java/model/springcontext/package-info.java diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/package-info.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/package-info.java new file mode 100644 index 00000000000..d7f5beee53b --- /dev/null +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/package-info.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/ + */ + +/** + * Model of the Spring application context built during project scanning. + * + *

Classes in this package are populated by visitors that traverse the AST and collect + * Spring-specific metadata. The resulting model is then consumed by rules that reason about + * the application context — for example, detecting duplicate bean definitions or missing + * component-scan coverage. + * + *

The central entry point is {@link org.sonar.java.model.springcontext.SpringContextModel}, + * which aggregates the following indexes: + *

    + *
  • {@link org.sonar.java.model.springcontext.BeanDefinitionRegistry} — bean definitions by name
  • + *
  • {@link org.sonar.java.model.springcontext.TypeToBeanNamesIndex} — bean names by type
  • + *
  • {@link org.sonar.java.model.springcontext.ProjectPackageScan} — component-scan packages by module
  • + *
  • {@link org.sonar.java.model.springcontext.EntityClassToPropertiesIndex} — JPA {@code @Entity} properties
  • + *
+ */ +package org.sonar.java.model.springcontext; \ No newline at end of file From 045a452c11fc95d913c5c5e28b18ad43c8f99de4 Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Mon, 1 Jun 2026 13:34:55 +0200 Subject: [PATCH 3/4] Fixing issues --- .../java/model/springcontext/BeanDefinitionHolder.java | 2 +- .../java/model/springcontext/BeanDefinitionRegistry.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java index 3867529b013..e6e18655eb4 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java @@ -144,7 +144,7 @@ public Builder primary() { public BeanDefinitionHolder build() { BeanDefinitionHolder holder = new BeanDefinitionHolder(type, module, beanPackage, location); - holder.setDependingBeans(Collections.unmodifiableList(dependingBeans)); + holder.setDependingBeans(List.copyOf(dependingBeans)); holder.setProfiles(profiles); if (isPrimary) { holder.setPrimary(); diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java index 457f2b61fe1..8de01d51202 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java @@ -36,13 +36,13 @@ public class BeanDefinitionRegistry { * A list is used as the value to capture duplicate bean definitions under the same name, * which is an invalid state that should be reported during analysis. */ - private final Map> beanDefinitionRegistry = new HashMap<>(); + private final Map> beanDefinitions = new HashMap<>(); public List getByName(String beanName) { - return beanDefinitionRegistry.getOrDefault(beanName, List.of()); + return beanDefinitions.getOrDefault(beanName, List.of()); } public void addBeanDefinition(String beanName, BeanDefinitionHolder beanDefinition) { - beanDefinitionRegistry.computeIfAbsent(beanName, k -> new ArrayList<>()).add(beanDefinition); + beanDefinitions.computeIfAbsent(beanName, k -> new ArrayList<>()).add(beanDefinition); } } From b544e83103b1682ab8f9e4bf542f09a5e943afcf Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Mon, 1 Jun 2026 13:34:55 +0200 Subject: [PATCH 4/4] Fixing issues --- .../java/model/springcontext/BeanDefinitionHolder.java | 3 +-- .../java/model/springcontext/BeanDefinitionRegistry.java | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java index 3867529b013..3cca0218e72 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionHolder.java @@ -17,7 +17,6 @@ package org.sonar.java.model.springcontext; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import javax.annotation.Nullable; @@ -144,7 +143,7 @@ public Builder primary() { public BeanDefinitionHolder build() { BeanDefinitionHolder holder = new BeanDefinitionHolder(type, module, beanPackage, location); - holder.setDependingBeans(Collections.unmodifiableList(dependingBeans)); + holder.setDependingBeans(List.copyOf(dependingBeans)); holder.setProfiles(profiles); if (isPrimary) { holder.setPrimary(); diff --git a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java index 457f2b61fe1..8de01d51202 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java +++ b/java-frontend/src/main/java/org/sonar/java/model/springcontext/BeanDefinitionRegistry.java @@ -36,13 +36,13 @@ public class BeanDefinitionRegistry { * A list is used as the value to capture duplicate bean definitions under the same name, * which is an invalid state that should be reported during analysis. */ - private final Map> beanDefinitionRegistry = new HashMap<>(); + private final Map> beanDefinitions = new HashMap<>(); public List getByName(String beanName) { - return beanDefinitionRegistry.getOrDefault(beanName, List.of()); + return beanDefinitions.getOrDefault(beanName, List.of()); } public void addBeanDefinition(String beanName, BeanDefinitionHolder beanDefinition) { - beanDefinitionRegistry.computeIfAbsent(beanName, k -> new ArrayList<>()).add(beanDefinition); + beanDefinitions.computeIfAbsent(beanName, k -> new ArrayList<>()).add(beanDefinition); } }