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 @@
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:
@Repository enables Spring’s persistence exception translation, which converts database-specific exceptions into Spring’s
+ DataAccessException hierarchy.@Service or
+ @Repository beans.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.
@Component // Noncompliant; class name suggests it's a @Service @@ -40,9 +51,30 @@+Compliant solution
// ... }
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:
ApplicationRunner, CommandLineRunner, HealthIndicator, or
+ ReactiveHealthIndicator@Endpoint, @RestControllerEndpoint, or @ControllerEndpointThe 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.
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.
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.
+The impact depends on the context where the faulty comparison appears:
+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 @@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.
+The rule does not raise an issue in the following cases:
+@Transactional(propagation = Propagation.NOT_SUPPORTED) - This propagation setting suspends the current transaction and executes
+ the method without any transaction context, so there is no transaction to roll back.@Transactional(readOnly = true) - Read-only transactions do not perform write operations, so there is no risk of committing partial
+ or inconsistent data.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.
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:
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.
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:
@RestController is meta-annotated with @Controller and @ResponseBody@Service, @Repository, @Controller, and @Configuration are meta-annotated with
- @Component@SpringBootApplication is meta-annotated with @Configuration, @EnableAutoConfiguration, and
- @ComponentScan@SpringBootTest already include @ExtendWith(SpringExtension.class)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:
+This impacts:
+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.
-@Component // Noncompliant, @Service already implies @Component
+@Component // Noncompliant
@Service
public class UserService {
+ public User findById(Long id) {
+ // service logic
+ }
}
@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.
-@Controller // Noncompliant, @RestController already implies @Controller
+@Controller // Noncompliant
@RestController
public class UserController {
+
+ @ResponseBody // Noncompliant
+ @GetMapping("/users")
+ public List<User> getUsers() {
+ return userService.findAll();
+ }
}
@RestController
public class UserController {
+
+ @GetMapping("/users")
+ public List<User> getUsers() {
+ return userService.findAll();
+ }
}
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.
-@Configuration // Noncompliant
+@Configuration // Noncompliant
+@EnableAutoConfiguration // Noncompliant
+@ComponentScan // Noncompliant
@SpringBootApplication
public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
}
@SpringBootApplication
public class MyApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
}
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.
-@ExtendWith(SpringExtension.class) // Noncompliant
+@ExtendWith(SpringExtension.class) // Noncompliant
@SpringBootTest
class UserServiceIntegrationTest {
+
+ @Test
+ void testUserCreation() {
+ // test logic
+ }
}
@SpringBootTest
class UserServiceIntegrationTest {
+
+ @Test
+ void testUserCreation() {
+ // test logic
+ }
}
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.
When creating archive files (ZIP or JAR), entries are added using a three-step process:
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.
Empty archive entries can cause several problems:
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.
@@ -41,8 +53,9 @@Compliant solution
Resources
Documentation
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.
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.
+This bug can lead to incorrect program behavior because conditions that should vary based on runtime values become constant:
+Replace the 0 with the intended bitmask constant.
+The appropriate fix depends on the root cause:
+
0 with the intended bitmask value. For example, use a hexadecimal constant like
+ 0x01 or a named constant that represents the bit positions you meant to test.& operator with the operator you actually intended, such as == for
+ equality comparison, % for modulo, or | for bitwise OR.
int flags = getFlags();
-if ((flags & 0) == 0) { // Noncompliant - always true
+if ((flags & 0) == 0) { // Noncompliant
+ // This block always executes
doSomething();
}
-+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
+