Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ <h3>Exceptions</h3>
// ...
}
</pre>
<h3>Related rules</h3>
<ul>
<li>{rule:java:S9147} - "NaN" should not be tested for equality using "==" or "!="</li>
</ul>

Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
<h2>Why is this an issue?</h2>
<p>The Spring Framework provides several specializations of the generic <code>@Component</code> stereotype annotation which better express the
programmer’s intent. Using them should be preferred.</p>
<p>The Spring Framework provides several specializations of the generic <code>@Component</code> stereotype annotation: <code>@Service</code>,
<code>@Repository</code>, <code>@Controller</code>, and <code>@RestController</code>. Using the appropriate specialization instead of the generic
<code>@Component</code> has concrete benefits:</p>
<ul>
<li><code>@Repository</code> enables Spring’s persistence exception translation, which converts database-specific exceptions into Spring’s
<code>DataAccessException</code> hierarchy.</li>
<li>Specialized annotations make the application’s layered architecture visible at a glance, helping developers navigate and understand the
codebase.</li>
<li>Frameworks and tools may apply different behavior based on the stereotype, such as AOP pointcuts that target only <code>@Service</code> or
<code>@Repository</code> beans.</li>
</ul>
<p>This rule raises an issue when a class is annotated with <code>@Component</code> and its name ends with a suffix that suggests a more specific
stereotype: <code>Service</code>, <code>ServiceImpl</code>, <code>Repository</code>, <code>Controller</code>, or <code>RestController</code>.</p>
<h3>Noncompliant code example</h3>
<pre>
@Component // Noncompliant; class name suggests it's a @Service
Expand Down Expand Up @@ -40,9 +51,30 @@ <h3>Compliant solution</h3>
// ...
}
</pre>
<h2>Exceptions</h2>
<p>This rule does not raise an issue when the class name does not end with one of the recognized suffixes (<code>Service</code>,
<code>ServiceImpl</code>, <code>Repository</code>, <code>Controller</code>, <code>RestController</code>). For example, a class named
<code>EventProcessor</code> annotated with <code>@Component</code> does not trigger this rule, even if it could arguably be a
<code>@Service</code>.</p>
<p>The rule does not suggest <code>@Controller</code> or <code>@RestController</code> unless the class contains at least one method annotated with a
request mapping annotation (<code>@RequestMapping</code>, <code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code>,
<code>@DeleteMapping</code>, <code>@PatchMapping</code>). Classes named "Controller" that do not handle HTTP requests are not flagged.</p>
<p>The rule does not suggest <code>@Controller</code> or <code>@RestController</code> for classes that belong to non-web Spring infrastructure:</p>
<ul>
<li>Classes implementing <code>ApplicationRunner</code>, <code>CommandLineRunner</code>, <code>HealthIndicator</code>, or
<code>ReactiveHealthIndicator</code></li>
<li>Classes annotated with <code>@Endpoint</code>, <code>@RestControllerEndpoint</code>, or <code>@ControllerEndpoint</code></li>
</ul>
<p>The rule does not raise an issue when the class already carries a specialized stereotype annotation (<code>@Controller</code>,
<code>@RestController</code>, <code>@Service</code>, <code>@Repository</code>) alongside <code>@Component</code>.</p>
<p>If your class intentionally uses <code>@Component</code> 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.</p>
<h2>Resources</h2>
<h3>Documentation</h3>
<ul>
<li><a href="https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-stereotype-annotations">Spring
documentation - @Component and Further Stereotype Annotations</a></li>
<li>Spring Framework Documentation - <a
href="https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-stereotype-annotations">@Component and Further
Stereotype Annotations</a></li>
</ul>

Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
<p>This rule raises an issue when a bitwise operation (<code>&amp;</code> or <code>|</code>) 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.</p>
<h2>Why is this an issue?</h2>
<p>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.</p>
<p>For bitwise AND operations (<code>&amp;</code>), the result can only have bits set where the mask has bits set. For example, <code>x &amp; 1</code>
can only produce values 0 or 1, never 2. Comparing this result to an impossible value like 2 creates dead code.</p>
<p>For bitwise OR operations (<code>|</code>), the result always includes all bits set in the mask. If the compared value doesn't include all mask
<p>For bitwise OR operations (<code>|</code>), the result always includes all bits set in the mask. If the compared value doesnt include all mask
bits, the comparison can never be equal.</p>
<p>These constant comparisons indicate logical errors in the code.</p>
<p>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.</p>
<h3>What is the potential impact?</h3>
<p>The impact depends on the context where the faulty comparison appears:</p>
<ul>
<li><strong>Reliability</strong>: Dead code branches may indicate incomplete feature implementation or incorrect flag validation logic.</li>
<li><strong>Maintainability</strong>: Developers reading the code may waste time trying to understand why certain branches never execute, or may
incorrectly assume the comparison serves a purpose.</li>
<li><strong>Security</strong>: In permission checks or validation logic, a comparison that always evaluates to false might inadvertently bypass
security controls.</li>
</ul>
<h2>How to fix it</h2>
<p>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.</p>
Expand All @@ -29,4 +42,7 @@ <h3>Documentation</h3>
<ul>
<li>Oracle Java Documentation - <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html">Bitwise and Bit Shift
Operators</a></li>
<li>Java Language Specification - <a href="https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.22.1">Integer Bitwise Operators
&amp;, ^, and |</a></li>
</ul>

Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ <h3>Business Logic Violations</h3>
<h3>Difficult Debugging</h3>
<p>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.</p>
<h2>Exceptions</h2>
<p>The rule does not raise an issue in the following cases:</p>
<ul>
<li><code>@Transactional(propagation = Propagation.NOT_SUPPORTED)</code> - This propagation setting suspends the current transaction and executes
the method without any transaction context, so there is no transaction to roll back.</li>
<li><code>@Transactional(readOnly = true)</code> - Read-only transactions do not perform write operations, so there is no risk of committing partial
or inconsistent data.</li>
</ul>
<h2>How to fix it in Spring</h2>
<p>Explicitly specify <code>rollbackFor</code> 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.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ <h3>What is the potential impact?</h3>
environments</li>
</ul>
<h3>Exceptions</h3>
<p><code>String.split</code> does not compile a regular expression when the argument meets either of these conditions:</p>
<p><code>String.split()</code> does not compile a regular expression when the argument meets either of these conditions:</p>
<ul>
<li>It is a one-char String and this character is not one of the regex metacharacters ".$|()[{^?*+\"</li>
<li>It is a two-char String and the first char is the backslash and the second is not an ASCII digit or letter.</li>
Expand Down Expand Up @@ -132,3 +132,4 @@ <h3>Related rules</h3>
<li>{rule:java:S4248} - Regex patterns should not be created needlessly</li>
<li>{rule:java:S6909} - Constant parameters in a "PreparedStatement" should not be set more than once</li>
</ul>

Original file line number Diff line number Diff line change
@@ -1,82 +1,156 @@
<p>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.</p>
<h2>Why is this an issue?</h2>
<p>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.</p>
<p>Common examples include:</p>
<p>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.</p>
<p>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.</p>
<p>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:</p>
<ul>
<li><code>@RestController</code> is meta-annotated with <code>@Controller</code> and <code>@ResponseBody</code></li>
<li><code>@Service</code>, <code>@Repository</code>, <code>@Controller</code>, and <code>@Configuration</code> are meta-annotated with
<code>@Component</code></li>
<li><code>@SpringBootApplication</code> is meta-annotated with <code>@Configuration</code>, <code>@EnableAutoConfiguration</code>, and
<code>@ComponentScan</code></li>
<li>Spring test annotations like <code>@SpringBootTest</code> already include <code>@ExtendWith(SpringExtension.class)</code></li>
<li><strong>Code clutter</strong>: Extra annotations make the code harder to read</li>
<li><strong>Confusion</strong>: It suggests the developer doesn’t understand the framework’s annotation composition model</li>
<li><strong>Maintenance burden</strong>: More annotations mean more to maintain and keep consistent</li>
<li><strong>False precision</strong>: It may mislead other developers into thinking both annotations are necessary</li>
</ul>
<p>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.</p>
<p>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.</p>
<p>In Spring Framework, this specifically applies to meta-annotations. Common examples include:</p>
<ul>
<li><strong>@RestController</strong> is meta-annotated with @Controller and @ResponseBody</li>
<li><strong>@Component</strong> is the base stereotype annotation, with specialized versions including @Service, @Repository, @Controller, and
@Configuration</li>
<li><strong>@SpringBootApplication</strong> is meta-annotated with @Configuration, @EnableAutoConfiguration, and @ComponentScan</li>
</ul>
<h3>What is the potential impact?</h3>
<p>This impacts:</p>
<ul>
<li><strong>Readability</strong>: Redundant declarative markers create visual noise that distracts from the class’s actual purpose</li>
<li><strong>Maintainability</strong>: Developers waste time trying to understand why both markers are present</li>
<li><strong>Team knowledge</strong>: The code may propagate misunderstandings about how framework conventions work</li>
</ul>
<h2>How to fix it in Spring</h2>
<p>Remove the redundant parent annotation. Keep only the most specific annotation that provides the functionality you need.</p>
<p>For stereotype annotations (<code>@Service</code>, <code>@Repository</code>, <code>@Controller</code>, <code>@Configuration</code>), remove
<code>@Component</code> since it’s already included in these specialized annotations.</p>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
@Component // Noncompliant, @Service already implies @Component
@Component // Noncompliant
@Service
public class UserService {
public User findById(Long id) {
// service logic
}
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
@Service
public class UserService {
public User findById(Long id) {
// service logic
}
}
</pre>
<p>For REST controllers, remove <code>@Controller</code> and class-level <code>@ResponseBody</code> since <code>@RestController</code> already
includes both. Also remove method-level <code>@ResponseBody</code> within <code>@RestController</code> classes since it’s already applied to all
methods.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="2" data-diff-type="noncompliant">
@Controller // Noncompliant, @RestController already implies @Controller
@Controller // Noncompliant
@RestController
public class UserController {

@ResponseBody // Noncompliant
@GetMapping("/users")
public List&lt;User&gt; getUsers() {
return userService.findAll();
}
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="2" data-diff-type="compliant">
@RestController
public class UserController {

@GetMapping("/users")
public List&lt;User&gt; getUsers() {
return userService.findAll();
}
}
</pre>
<h2>How to fix it in Spring Boot</h2>
<p>Remove <code>@Configuration</code>, <code>@EnableAutoConfiguration</code>, and <code>@ComponentScan</code> (when used without custom
attributes) since <code>@SpringBootApplication</code> already includes all of these.</p>
<p>For Spring Boot applications, remove <code>@Configuration</code>, <code>@SpringBootConfiguration</code>, <code>@EnableAutoConfiguration</code>, and
<code>@ComponentScan</code> (when used without custom attributes) since <code>@SpringBootApplication</code> already includes all of these.</p>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="3" data-diff-type="noncompliant">
@Configuration // Noncompliant
@Configuration // Noncompliant
@EnableAutoConfiguration // Noncompliant
@ComponentScan // Noncompliant
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="3" data-diff-type="compliant">
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
</pre>
<h2>How to fix it in Spring Test</h2>
<p>Remove <code>@ExtendWith(SpringExtension.class)</code> when using specialized test annotations like <code>@SpringBootTest</code>,
<code>@WebMvcTest</code>, <code>@DataJpaTest</code>, or <code>@WebFluxTest</code> since they already include this extension.</p>
<p>For Spring test classes, remove <code>@ExtendWith(SpringExtension.class)</code> when using specialized test annotations like
<code>@SpringBootTest</code>, <code>@WebMvcTest</code>, <code>@DataJpaTest</code>, or <code>@WebFluxTest</code> since they already include this
extension. Also remove <code>@Transactional</code> when using <code>@DataJpaTest</code> since it’s already included.</p>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre data-diff-id="4" data-diff-type="noncompliant">
@ExtendWith(SpringExtension.class) // Noncompliant
@ExtendWith(SpringExtension.class) // Noncompliant
@SpringBootTest
class UserServiceIntegrationTest {

@Test
void testUserCreation() {
// test logic
}
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="4" data-diff-type="compliant">
@SpringBootTest
class UserServiceIntegrationTest {

@Test
void testUserCreation() {
// test logic
}
}
</pre>
<h2>Resources</h2>
<h3>Documentation</h3>
<ul>
<li>Spring Framework Documentation - <a href="https://docs.spring.io/spring-framework/reference/core/beans/classpath-scanning.html#beans-meta-annotations">Meta-Annotations and Composed Annotations</a></li>
<li>Spring Boot Documentation - <a href="https://docs.spring.io/spring-boot/reference/using/using-the-springbootapplication-annotation.html">Using the @SpringBootApplication Annotation</a></li>
<li>Spring Framework Documentation - <a
href="https://docs.spring.io/spring-framework/reference/core/beans/java/composing-configuration-classes.html">Composing Java-based
Configurations</a></li>
<li>Spring Framework Documentation - <a
href="https://docs.spring.io/spring-framework/reference/core/beans/classpath-scanning.html#beans-stereotype-annotations">Stereotype
Annotations</a></li>
<li>Spring Boot Documentation - <a href="https://docs.spring.io/spring-boot/reference/using/using-the-springbootapplication-annotation.html">Using
the @SpringBootApplication Annotation</a></li>
<li>Spring Framework Documentation - <a
href="https://docs.spring.io/spring-framework/reference/core/beans/classpath-scanning.html#beans-meta-annotations">Meta-Annotations and Composed
Annotations</a></li>
</ul>

Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
Loading
Loading