diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1244.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1244.html index 6aba2d8a9e0..c549c774f5c 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1244.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1244.html @@ -45,4 +45,8 @@

Exceptions

// ... } +

Related rules

+ 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 3ef379f8f9e..a3b732ea094 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,6 +1,17 @@

Why is this an issue?

-

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

+

The Spring Framework provides several specializations of the generic @Component stereotype annotation: @Service, +@Repository, @Controller, and @RestController. Using the appropriate specialization instead of the generic +@Component has concrete benefits:

+ +

This rule raises an issue when a class is annotated with @Component and its name ends with a suffix that suggests a more specific +stereotype: Service, ServiceImpl, Repository, Controller, or RestController.

Noncompliant code example

 @Component // Noncompliant; class name suggests it's a @Service
@@ -40,9 +51,30 @@ 

Compliant solution

// ... }
+

Exceptions

+

This rule does not raise an issue when the class name does not end with one of the recognized suffixes (Service, +ServiceImpl, Repository, Controller, RestController). For example, a class named +EventProcessor annotated with @Component does not trigger this rule, even if it could arguably be a +@Service.

+

The rule does not suggest @Controller or @RestController unless the class contains at least one method annotated with a +request mapping annotation (@RequestMapping, @GetMapping, @PostMapping, @PutMapping, +@DeleteMapping, @PatchMapping). Classes named "Controller" that do not handle HTTP requests are not flagged.

+

The rule does not suggest @Controller or @RestController for classes that belong to non-web Spring infrastructure:

+ +

The rule does not raise an issue when the class already carries a specialized stereotype annotation (@Controller, +@RestController, @Service, @Repository) alongside @Component.

+

If your class intentionally uses @Component despite its name (for example, a multi-role bean or a class whose name coincidentally +contains a suffix), mark the issue as "Won’t Fix". A genuine false positive would be a case where the rule suggests a stereotype that does not match +the class’s actual role.

Resources

+

Documentation

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.html index 8b183173d42..c448c70bffe 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.html @@ -1,11 +1,24 @@ +

This rule raises an issue when a bitwise operation (& or |) is used in a comparison where the bit mask and compared +value are incompatible, making the comparison always true or always false regardless of the input.

Why is this an issue?

When performing bitwise operations in comparisons, the relationship between the bit mask and the compared value determines what results are possible. If this relationship makes certain outcomes impossible, the comparison becomes a constant expression.

For bitwise AND operations (&), the result can only have bits set where the mask has bits set. For example, x & 1 can only produce values 0 or 1, never 2. Comparing this result to an impossible value like 2 creates dead code.

-

For bitwise OR operations (|), the result always includes all bits set in the mask. If the compared value doesn't include all mask +

For bitwise OR operations (|), the result always includes all bits set in the mask. If the compared value doesn’t include all mask bits, the comparison can never be equal.

-

These constant comparisons indicate logical errors in the code.

+

These constant comparisons indicate logical errors in the code. They waste processing time on checks that always have the same outcome, create +confusion for developers reading the code, and may indicate incomplete or incorrect implementation of bit flag checking logic. In security-sensitive +contexts, such errors might bypass intended validation checks.

+

What is the potential impact?

+

The impact depends on the context where the faulty comparison appears:

+

How to fix it

Review the bit mask and comparison value to ensure they are logically compatible. For AND operations, verify that the compared value only has bits that exist in the mask. For OR operations, verify that the compared value includes all bits from the mask.

@@ -29,4 +42,7 @@

Documentation

+ diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.json index 82f20de063b..d74d50baf07 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7438.json @@ -1,23 +1,21 @@ { "title": "Incompatible bit masks should not be used in comparisons", "type": "BUG", - "code": { - "impacts": { - "RELIABILITY": "HIGH" - }, - "attribute": "LOGICAL" - }, "status": "ready", "remediation": { "func": "Constant\/Issue", "constantCost": "5min" }, - "tags": [ - "suspicious" - ], + "tags": [], "defaultSeverity": "Blocker", "ruleSpecification": "RSPEC-7438", "sqKey": "S7438", "scope": "All", - "quickfix": "unknown" + "quickfix": "unknown", + "code": { + "impacts": { + "RELIABILITY": "HIGH" + }, + "attribute": "LOGICAL" + } } 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 9c26daf2292..eebf0eeab97 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 @@ -46,6 +46,14 @@

Business Logic Violations

Difficult Debugging

Because the transaction commits silently, these bugs are hard to diagnose. The code appears to handle errors correctly (it throws and catches exceptions), but the database state doesn’t match expectations.

+

Exceptions

+

The rule does not raise an issue in the following cases:

+

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.

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9142.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9142.html index 1197214413b..ccf7e0cfc5d 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9142.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9142.html @@ -49,7 +49,7 @@

What is the potential impact?

environments

Exceptions

-

String.split does not compile a regular expression when the argument meets either of these conditions:

+

String.split() does not compile a regular expression when the argument meets either of these conditions:

+ diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.html index 7758173cf8f..a7405c46966 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.html @@ -1,82 +1,156 @@ +

This is an issue when a framework annotation or metadata marker is used alongside another annotation that already includes it through annotation +inheritance or composition mechanisms.

Why is this an issue?

-

Some Spring annotations are composed from other annotations through meta-annotation. When you use an annotation that already includes another -annotation's behavior, explicitly adding the parent annotation is redundant. It creates visual noise and may indicate a misunderstanding of the -framework's annotation composition model.

-

Common examples include:

+

Some frameworks use composed annotations or attribute inheritance to build functionality. A composed annotation is one that is declared to include +another annotation’s behavior. When you use an annotation that composes other annotations, you automatically get all the functionality of those +included annotations.

+

For example, a framework might provide a combined controller annotation that is composed from a basic controller marker and a response formatting +marker. This means when you add the combined annotation to a class, the framework automatically treats it as if it also has both the basic controller +marker and the response formatting marker.

+

When developers explicitly add both annotations, the parent annotation becomes redundant. It has no effect on how the framework processes the +class, but it creates several problems:

+

The most common cases involve framework stereotype annotations. A base component marker is often the foundation, with the framework providing +specialized versions like service markers, data access markers, controller markers, and configuration markers. Each of these specialized annotations +is composed from the base component marker, so adding the base marker explicitly is redundant.

+

Similar redundancies occur with combined controller annotations (which include both basic controller and response formatting markers), application +bootstrap annotations (which include configuration, auto-configuration, and component scanning markers), and various framework test annotations.

+

In Spring Framework, this specifically applies to meta-annotations. Common examples include:

+ +

What is the potential impact?

+

This impacts:

+

How to fix it in Spring

Remove the redundant parent annotation. Keep only the most specific annotation that provides the functionality you need.

+

For stereotype annotations (@Service, @Repository, @Controller, @Configuration), remove +@Component since it’s already included in these specialized annotations.

Code examples

Noncompliant code example

-@Component // Noncompliant, @Service already implies @Component
+@Component  // Noncompliant
 @Service
 public class UserService {
+    public User findById(Long id) {
+        // service logic
+    }
 }
 

Compliant solution

 @Service
 public class UserService {
+    public User findById(Long id) {
+        // service logic
+    }
 }
 
+

For REST controllers, remove @Controller and class-level @ResponseBody since @RestController already +includes both. Also remove method-level @ResponseBody within @RestController classes since it’s already applied to all +methods.

Noncompliant code example

-@Controller // Noncompliant, @RestController already implies @Controller
+@Controller  // Noncompliant
 @RestController
 public class UserController {
+
+    @ResponseBody  // Noncompliant
+    @GetMapping("/users")
+    public List<User> getUsers() {
+        return userService.findAll();
+    }
 }
 

Compliant solution

 @RestController
 public class UserController {
+
+    @GetMapping("/users")
+    public List<User> getUsers() {
+        return userService.findAll();
+    }
 }
 

How to fix it in Spring Boot

-

Remove @Configuration, @EnableAutoConfiguration, and @ComponentScan (when used without custom -attributes) since @SpringBootApplication already includes all of these.

+

For Spring Boot applications, remove @Configuration, @SpringBootConfiguration, @EnableAutoConfiguration, and +@ComponentScan (when used without custom attributes) since @SpringBootApplication already includes all of these.

Code examples

Noncompliant code example

-@Configuration // Noncompliant
+@Configuration  // Noncompliant
+@EnableAutoConfiguration  // Noncompliant
+@ComponentScan  // Noncompliant
 @SpringBootApplication
 public class MyApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(MyApplication.class, args);
+    }
 }
 

Compliant solution

 @SpringBootApplication
 public class MyApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(MyApplication.class, args);
+    }
 }
 

How to fix it in Spring Test

-

Remove @ExtendWith(SpringExtension.class) when using specialized test annotations like @SpringBootTest, -@WebMvcTest, @DataJpaTest, or @WebFluxTest since they already include this extension.

+

For Spring test classes, remove @ExtendWith(SpringExtension.class) when using specialized test annotations like +@SpringBootTest, @WebMvcTest, @DataJpaTest, or @WebFluxTest since they already include this +extension. Also remove @Transactional when using @DataJpaTest since it’s already included.

Code examples

Noncompliant code example

-@ExtendWith(SpringExtension.class) // Noncompliant
+@ExtendWith(SpringExtension.class)  // Noncompliant
 @SpringBootTest
 class UserServiceIntegrationTest {
+
+    @Test
+    void testUserCreation() {
+        // test logic
+    }
 }
 

Compliant solution

 @SpringBootTest
 class UserServiceIntegrationTest {
+
+    @Test
+    void testUserCreation() {
+        // test logic
+    }
 }
 

Resources

Documentation

+ diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.json index 9fec6709d23..1bac8d3097e 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9341.json @@ -4,19 +4,20 @@ "status": "ready", "remediation": { "func": "Constant\/Issue", - "constantCost": "5min" + "constantCost": "5 min" }, "tags": [ - "spring" + "spring", + "redundant" ], - "defaultSeverity": "Major", + "defaultSeverity": "Minor", "ruleSpecification": "RSPEC-9341", "sqKey": "S9341", "scope": "All", "quickfix": "unknown", "code": { "impacts": { - "MAINTAINABILITY": "MEDIUM" + "MAINTAINABILITY": "LOW" }, "attribute": "CLEAR" } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.html index a570ff91de7..3b1564cdd10 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.html @@ -1,29 +1,41 @@ -

An issue is raised when an operation that closes an archive entry is called immediately after an operation that opens or begins a new -entry in an archive output stream, without writing any content in between.

+

An issue is raised when an operation that closes an archive entry is called immediately after an operation that opens or begins a new entry in an +archive output stream, without writing any content in between.

+

In Java, this specifically refers to calling closeEntry() immediately after putNextEntry() on a +ZipOutputStream or JarOutputStream.

Why is this an issue?

When creating archive files (ZIP or JAR), entries are added using a three-step process:

  1. Call an API method to declare the start of a new entry
  2. -
  3. Write the entry's content using output stream methods
  4. +
  5. Write the entry’s content using output stream methods
  6. Call an API method to finalize the entry

Skipping the second step creates an empty entry in the archive. This is almost always a mistake.

-

Empty archive entries serve no useful purpose. In ZIP files, they waste space by storing metadata for entries with no content. In JAR files, -empty entries can cause runtime errors when the application expects to load classes or resources that don't exist.

-

In Java, this specifically refers to calling closeEntry() immediately after putNextEntry() on a -ZipOutputStream or JarOutputStream.

+

Empty archive entries serve no useful purpose. In ZIP files, they waste space by storing metadata for entries with no content. In JAR files, empty +entries can cause runtime errors when the application expects to load classes or resources that don’t exist.

+

This pattern typically occurs due to:

+ +

Since specialized archive output streams (like those for JAR files) typically extend the base archive stream class, multiple archive types are +subject to this issue.

+

In Java, these operations correspond to putNextEntry() to start an entry, write() methods to add content, and +closeEntry() to finalize it. Both ZipOutputStream and JarOutputStream (which extends +ZipOutputStream) use this API.

What is the potential impact?

+

Empty archive entries can cause several problems:

How to fix it

-

Write content to the archive entry between putNextEntry() and closeEntry() using the write() method. -The content can come from a byte array, file, or any other source.

+

Write content to the archive entry between putNextEntry() and closeEntry() using the write() method. The +content can come from a byte array, file, or any other source.

Code examples

Noncompliant code example

@@ -41,8 +53,9 @@ 

Compliant solution

Resources

Documentation

+ diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.json index 98e578fedd5..ef4bfa3a64d 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9342.json @@ -4,20 +4,20 @@ "status": "ready", "remediation": { "func": "Constant\/Issue", - "constantCost": "5min" + "constantCost": "5 min" }, "tags": [ - "suspicious" + "pitfall" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-9342", "sqKey": "S9342", - "scope": "All", + "scope": "Main", "quickfix": "unknown", "code": { "impacts": { "RELIABILITY": "HIGH" }, - "attribute": "CLEAR" + "attribute": "COMPLETE" } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.html index 6329aefa83d..224520d9dd0 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.html @@ -1,20 +1,64 @@ +

This raises an issue when code performs a bitwise AND operation with the literal value 0, as the result is always 0 +regardless of the other operand.

Why is this an issue?

-

A bitwise AND operation combines two values bit by bit. When one of the operands is 0, every bit in the result will be 0 -because 0 AND anything is always 0. This makes the operation meaningless and any subsequent comparison trivial.

-

This pattern almost always indicates a programming error, such as using the wrong constant, the wrong operator, or a copy-paste mistake.

+

A bitwise AND operation combines two values bit by bit. When one of the operands is 0, every bit in the result will be 0 because 0 AND anything is +always 0. This makes the operation meaningless and any subsequent comparison trivial.

+

For example, an expression that checks whether the result of ANDing a value with 0 equals 0 will always evaluate to true, and an expression +checking whether that result differs from 0 will always evaluate to false, regardless of what the value contains.

+

This pattern almost always indicates a programming error. Common mistakes include:

+ +

Since the operation produces a predictable result that doesn’t depend on the actual value being tested, it serves no useful purpose and should be +corrected.

+

What is the potential impact?

+

This bug can lead to incorrect program behavior because conditions that should vary based on runtime values become constant:

+

How to fix it

-

Replace the 0 with the intended bitmask constant.

-

Noncompliant code example

-
+

The appropriate fix depends on the root cause:

+ +

Code examples

+

Noncompliant code example

+
 int flags = getFlags();
-if ((flags & 0) == 0) { // Noncompliant - always true
+if ((flags & 0) == 0) { // Noncompliant
+    // This block always executes
     doSomething();
 }
 
-

Compliant solution

-
+

Compliant solution

+
 int flags = getFlags();
-if ((flags & 0x01) == 0) { // Compliant - checks if the least significant bit is not set
+if ((flags & 0x01) == 0) {
+    // Now this checks if the least significant bit is not set
     doSomething();
 }
 
+

Resources

+

Documentation

+ +

Related rules

+
    +
  • {rule:java:S7438} - Bitwise AND with zero (Rust)
  • +
+ diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.json index a6b7607c7d5..40a30173c83 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9344.json @@ -7,7 +7,7 @@ "constantCost": "5min" }, "tags": [ - "suspicious" + "pitfall" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-9344", @@ -16,6 +16,7 @@ "quickfix": "unknown", "code": { "impacts": { + "SECURITY": "MEDIUM", "RELIABILITY": "HIGH" }, "attribute": "LOGICAL" diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9351.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9351.json index 7d40226e1d8..f00c665e8f6 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9351.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9351.json @@ -13,7 +13,7 @@ "defaultSeverity": "Major", "ruleSpecification": "RSPEC-9351", "sqKey": "S9351", - "scope": "Main", + "scope": "All", "quickfix": "infeasible", "code": { "impacts": { diff --git a/sonar-java-plugin/src/main/resources/profiles/Sonar_agentic_AI/S9344 b/sonar-java-plugin/src/main/resources/profiles/Sonar_agentic_AI/S9344 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaAgenticWayProfileTest.java b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaAgenticWayProfileTest.java index 738427fa588..705a056568f 100644 --- a/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaAgenticWayProfileTest.java +++ b/sonar-java-plugin/src/test/java/org/sonar/plugins/java/JavaAgenticWayProfileTest.java @@ -60,7 +60,7 @@ void profile_is_registered_as_expected() { BuiltInQualityProfilesDefinition.BuiltInQualityProfile actualProfile = profilesPerLanguages.get("java").get("Sonar agentic AI"); assertThat(actualProfile.isDefault()).isFalse(); assertThat(actualProfile.rules()) - .hasSize(466) + .hasSize(465) .extracting(BuiltInQualityProfilesDefinition.BuiltInActiveRule::ruleKey) .doesNotContainAnyElementsOf(List.of( "S101", diff --git a/sonarpedia.json b/sonarpedia.json index 37e467b69b6..f0cde627ead 100644 --- a/sonarpedia.json +++ b/sonarpedia.json @@ -4,7 +4,7 @@ "JAVA" ], "profiles-path": "./sonar-java-plugin/src/main/resources/profiles", - "latest-update": "2026-08-13T08:56:24.339778521Z", + "latest-update": "2026-08-20T11:55:51.315148260Z", "options": { "no-language-in-filenames": true, "preserve-filenames": false