From 83fa5fb811fe66d868300edccd1468f3681624f6 Mon Sep 17 00:00:00 2001 From: daniel-teuchert-sonarsource Date: Thu, 16 Jul 2026 14:01:01 +0000 Subject: [PATCH 1/2] Update rule metadata --- .../org/sonar/l10n/java/rules/java/S1110.json | 24 +++++++------- .../org/sonar/l10n/java/rules/java/S2068.json | 3 +- .../org/sonar/l10n/java/rules/java/S2115.json | 3 +- .../org/sonar/l10n/java/rules/java/S5673.html | 31 ++++++++++--------- .../org/sonar/l10n/java/rules/java/S5673.json | 6 ++-- .../org/sonar/l10n/java/rules/java/S6418.json | 5 +-- .../org/sonar/l10n/java/rules/java/S6437.json | 3 +- .../org/sonar/l10n/java/rules/java/S8989.html | 17 +++++++--- .../org/sonar/l10n/java/rules/java/S8989.json | 2 +- .../org/sonar/l10n/java/rules/java/S9021.html | 23 +++++++++----- .../org/sonar/l10n/java/rules/java/S9021.json | 10 +++--- .../main/resources/profiles/Sonar_way/S9021 | 0 sonarpedia.json | 2 +- 13 files changed, 75 insertions(+), 54 deletions(-) create mode 100644 sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9021 diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1110.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1110.json index 87cbe8691bb..2b607b5003f 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1110.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1110.json @@ -1,25 +1,23 @@ { - "title": "Unnecessary parentheses should be removed", + "title": "Redundant pairs of parentheses should be removed", "type": "CODE_SMELL", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "CLEAR" + }, "status": "ready", "remediation": { "func": "Constant\/Issue", - "constantCost": "2 min" + "constantCost": "1min" }, "tags": [ - "clippy", - "redundant", - "readability" + "confusing" ], - "defaultSeverity": "Minor", + "defaultSeverity": "Major", "ruleSpecification": "RSPEC-1110", "sqKey": "S1110", "scope": "All", - "quickfix": "unknown", - "code": { - "impacts": { - "MAINTAINABILITY": "LOW" - }, - "attribute": "CLEAR" - } + "quickfix": "unknown" } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2068.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2068.json index fc12ceb2ead..bd8ee22ae12 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2068.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2068.json @@ -16,7 +16,8 @@ "tags": [ "cwe", "cert", - "former-hotspot" + "former-hotspot", + "secret" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-2068", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2115.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2115.json index 38369e62a20..c7eb38ce575 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2115.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2115.json @@ -13,7 +13,8 @@ "constantCost": "45min" }, "tags": [ - "cwe" + "cwe", + "secret" ], "defaultSeverity": "Blocker", "ruleSpecification": "RSPEC-2115", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.html index 74c51da93b2..3ef379f8f9e 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.html @@ -1,28 +1,25 @@ -

The Spring Framework provides several specializations of the generic @Component stereotype annotation which better express the programmer's intent. Using them should be preferred.

Why is this an issue?

-

Spring provides specialized stereotype annotations (@Service, @Repository, @Controller, and @RestController) that make code more expressive and provide additional semantics. When a class name suggests it should use one of these specialized annotations but uses @Component instead, it reduces code clarity.

-

How to fix it

-

Replace @Component with the appropriate specialized annotation based on the class's role in the application.

-

Code examples

-

Noncompliant code example

-
-@Component // Noncompliant
+

The Spring Framework provides several specializations of the generic @Component stereotype annotation which better express the +programmer’s intent. Using them should be preferred.

+

Noncompliant code example

+
+@Component // Noncompliant; class name suggests it's a @Service
 public class CustomerServiceImpl {
   // ...
 }
 
-@Component // Noncompliant
+@Component // Noncompliant; class name suggests it's a @Repository
 public class ProductRepository {
     // ...
 }
 
-@Component // Noncompliant
+@Component // Noncompliant; class name suggests it's a @Controller or @RestController
 public class FooBarRestController {
     // ...
 }
 
-

Compliant solution

-
+

Compliant solution

+
 @Service // Compliant
 public class CustomerServiceImpl {
   // ...
@@ -37,9 +34,15 @@ 

Compliant solution

public class FooBarRestController { // ... } + +@Component // Compliant +public class SomeOtherComponent { + // ... +}

Resources

-

Documentation

+ diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.json index 66e17c3344f..2070e52a0f0 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5673.json @@ -3,14 +3,14 @@ "type": "CODE_SMELL", "code": { "impacts": { - "MAINTAINABILITY": "LOW" + "MAINTAINABILITY": "MEDIUM" }, "attribute": "CLEAR" }, "status": "ready", "remediation": { - "func": "Constant/Issue", - "constantCost": "2min" + "func": "Constant\/Issue", + "constantCost": "5min" }, "tags": [ "spring" diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6418.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6418.json index 6c5dda39b59..ae2a46a6ef9 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6418.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6418.json @@ -14,9 +14,10 @@ }, "quickfix": "infeasible", "tags": [ - "cwe", "cert", - "former-hotspot" + "cwe", + "former-hotspot", + "secret" ], "defaultSeverity": "Blocker", "ruleSpecification": "RSPEC-6418", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6437.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6437.json index 757d768d07a..70c5fa9904b 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6437.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6437.json @@ -13,7 +13,8 @@ "constantCost": "60min" }, "tags": [ - "cwe" + "cwe", + "secret" ], "defaultSeverity": "Blocker", "ruleSpecification": "RSPEC-6437", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.html index a69c9b41f48..9c26daf2292 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.html @@ -49,6 +49,14 @@

Difficult Debugging

How to fix it in Spring

Explicitly specify rollbackFor to include the checked exceptions that should trigger a rollback. This is the most common fix, as most checked exceptions represent error conditions that should prevent the transaction from committing.

+

Choose your approach based on the exception’s meaning:

+
    +
  • Use rollbackFor with specific exception types when you know exactly which exceptions represent failures requiring rollback
  • +
  • Use rollbackFor = Exception.class when the method throws Exception or multiple checked exception types that all + represent failures
  • +
  • Use noRollbackFor only when a checked exception represents an expected, recoverable condition where you intentionally want the + transaction to commit (such as a notification failure after successfully saving core data)
  • +

Code examples

Noncompliant code example

@@ -107,10 +115,9 @@ 

Compliant solution

Resources

Documentation

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.json index 30a5819853d..85e109a98f6 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8989.json @@ -15,7 +15,7 @@ "ruleSpecification": "RSPEC-8989", "sqKey": "S8989", "scope": "Main", - "quickfix": "unknown", + "quickfix": "partial", "code": { "impacts": { "RELIABILITY": "MEDIUM", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.html index 3ade16fe3cd..9da81884b9e 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.html @@ -1,12 +1,14 @@ +

This is an issue when a Spring @Configuration class is declared final. Spring needs to create CGLIB proxies for +configuration classes that contain @Bean methods, and the final modifier prevents the necessary subclassing.

Why is this an issue?

Spring Framework uses CGLIB proxies to enforce singleton semantics for beans defined in @Configuration classes. When you call a @Bean method from within another @Bean method, Spring intercepts the call through a proxy to return the singleton instance rather than creating a new object.

The Java final keyword prevents class inheritance, which blocks CGLIB from creating the necessary subclass proxy. Without this proxy, -inter-bean method calls create new instances instead of retrieving the singleton, breaking Spring's container management.

+inter-bean method calls create new instances instead of retrieving the singleton, breaking Spring’s container management.

This typically manifests as a ConfigurationClassPostProcessor exception during application startup, preventing the Spring context from initializing.

-

What is the potential impact?

+

What is the potential impact?

When Spring @Configuration classes are marked final, the application fails to start. The ConfigurationClassPostProcessor throws an exception because CGLIB cannot create the required proxy subclass.

If this check were bypassed, the impact would be more subtle: inter-bean method calls would create duplicate instances instead of using singletons, @@ -16,7 +18,11 @@

What is the potential impact?

  • Inconsistent state: Different parts of the application working with different object instances
  • Configuration drift: Bean initialization logic executing multiple times with potentially different results
  • -

    How to fix it

    +

    If you see this issue but your configuration class genuinely doesn’t call other @Bean methods directly, consider using +@Configuration(proxyBeanMethods = false) instead of suppressing the issue. This makes the intent explicit and improves startup +performance. Mark this as a false positive only if the class is not actually a @Configuration class or if the final modifier +is required by a framework constraint you cannot control.

    +

    How to fix it in Spring

    Remove the final modifier from the @Configuration class. This allows Spring to create the CGLIB proxy needed to enforce singleton semantics for inter-bean method calls.

    Code examples

    @@ -52,7 +58,7 @@

    Compliant solution

    } }
    -

    If you don't need inter-bean method calls and want to optimize startup performance, use @Configuration(proxyBeanMethods = false). This +

    If you don’t need inter-bean method calls and want to optimize startup performance, use @Configuration(proxyBeanMethods = false). This disables CGLIB proxying, allowing the class to be final. However, you must use dependency injection instead of calling @Bean methods directly.

    Noncompliant code example

    @@ -90,8 +96,9 @@

    Compliant solution

    Resources

    Documentation

    + diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.json index cdca057e4e8..7081d055d83 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9021.json @@ -3,20 +3,22 @@ "type": "BUG", "status": "ready", "remediation": { - "func": "Constant/Issue", - "constantCost": "5min" + "func": "Constant\/Issue", + "constantCost": "5 min" }, "tags": [ - "spring" + "spring", + "pitfall" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-9021", "sqKey": "S9021", "scope": "Main", + "quickfix": "unknown", "code": { "impacts": { "RELIABILITY": "HIGH" }, - "attribute": "LOGICAL" + "attribute": "MODULAR" } } diff --git a/sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9021 b/sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9021 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/sonarpedia.json b/sonarpedia.json index edaf45100e4..c027d245f6b 100644 --- a/sonarpedia.json +++ b/sonarpedia.json @@ -4,7 +4,7 @@ "JAVA" ], "profiles-path": "./sonar-java-plugin/src/main/resources/profiles", - "latest-update": "2026-07-07T08:51:35.551104566Z", + "latest-update": "2026-07-16T14:00:59.595637664Z", "options": { "no-language-in-filenames": true, "preserve-filenames": false From 9ae34a9f8769a723a0853394f89aab439eba2936 Mon Sep 17 00:00:00 2001 From: Daniel Teuchert Date: Thu, 16 Jul 2026 16:30:28 +0200 Subject: [PATCH 2/2] Document known autoscan false negatives for S9021 S9021 uses symbolType().is() for annotation resolution which requires semantic analysis not available in autoscan mode. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../src/test/resources/autoscan/diffs/diff_S9021.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 its/autoscan/src/test/resources/autoscan/diffs/diff_S9021.json diff --git a/its/autoscan/src/test/resources/autoscan/diffs/diff_S9021.json b/its/autoscan/src/test/resources/autoscan/diffs/diff_S9021.json new file mode 100644 index 00000000000..34beddc3026 --- /dev/null +++ b/its/autoscan/src/test/resources/autoscan/diffs/diff_S9021.json @@ -0,0 +1,6 @@ +{ + "ruleKey": "S9021", + "hasTruePositives": false, + "falseNegatives": 6, + "falsePositives": 0 +}