Thread1 cmap.get(“key”) => null Thread2 cmap.get(“key”) => null Thread1 cmap.put(“key”, new Value()) Thread2 cmap.put(“key”, new Value())
Get Started
- CodeAnt AI
- Control Center
- Pull Request Review
- IDE
- Compliance
- Anti-Patterns
- Code Governance
- Infrastructure Security Database
- Application Security Database
Java - 2
Learn about Java Anti-Patterns and How they help you write better code, and avoid common pitfalls.
Since Java 7, `Strings can be used as switch arguments. So when a single String is tested against three or more values in an if/else if structure, it should be converted to a switch instead for greater readability.
Note that this rule is automatically disabled when the project’s sonar.java.source is lower than 7`.
if ("red".equals(choice)) { // Noncompliant
dispenseRed();
} else if ("blue".equals(choice)) {
dispenseBlue();
} else if ("yellow".equals(choice)) {
dispenseYellow();
} else {
promptUser();
}
Comparisons of dissimilar types will always return false. The comparison and all its dependent code can simply be removed. This includes:
comparing an object with null
comparing an object with an unrelated primitive (E.G. a string with an int)
comparing unrelated classes
comparing an unrelated `class and interface
comparing unrelated interface types
comparing an array to a non-array
comparing two arrays
Specifically in the case of arrays, since arrays don’t override Object.equals(), calling equals on two arrays is the same as comparing their addresses. This means that array1.equals(array2) is equivalent to array1==array2.
However, some developers might expect Array.equals(Object obj) to do more than a simple memory address comparison, comparing for instance the size and content of the two arrays. Instead, the == operator or Arrays.equals(array1, array2)` should always be used with arrays.
interface KitchenTool { ... };
interface Plant {...}
public class Spatula implements KitchenTool { ... }
public class Tree implements Plant { ...}
//...
Spatula spatula = new Spatula();
KitchenTool tool = spatula;
KitchenTool [] tools = {tool};
Tree tree = new Tree();
Plant plant = tree;
Tree [] trees = {tree};
if (spatula.equals(tree)) { // Noncompliant; unrelated classes
// ...
}
else if (spatula.equals(plant)) { // Noncompliant; unrelated class and interface
// ...
}
else if (tool.equals(plant)) { // Noncompliant; unrelated interfaces
// ...
}
else if (tool.equals(tools)) { // Noncompliant; array & non-array
// ...
}
else if (trees.equals(tools)) { // Noncompliant; incompatible arrays
// ...
}
else if (tree.equals(null)) { // Noncompliant
// ...
}
Using a type parameter when you don’t have to simply obfuscates the code. Qualifying an inner type with a type parameter will compile, but confuse maintainers.
<T extends Map> T doTheThing(T.Entry type) { // Noncompliant
//...
}
This rule allows you to track the use of the Checkstyle suppression comment mechanism.
// CHECKSTYLE:OFF
HttpSession s are managed by web servers and can be serialized and stored on disk as the server manages its memory use in a process called “passivation” (and later restored during “activation”).
Even though HttpSession does not extend Serializable, you must nonetheless assume that it will be serialized. If non-serializable objects are stored in the session, serialization might fail.
public class Address {
//...
}
HttpSession session = request.getSession();
session.setAttribute("address", new Address()); // Noncompliant; Address isn't serializable
A cache is a long-lived object that holds references to shorter-lived objects. To prevent a cache from growing indefinitely, old objects the cache should be removed when they’re no longer used. This can be done with the use of soft references, which allow the garbage collector to remove unused cache entries when memory needs to be freed.
This rule raises an issue when a `static collection does not use SoftReference.
Note that this rule is automatically disabled when the project’s sonar.java.source` is lower than 7.
public class MyClass {
private static List<MyClass> cache = new ArrayList<>(); // Noncompliant
The Object#equals(Object obj) method is used to compare two objects to see if they are equal.
The obj parameter’s type is Object, this means that an object of any type can be passed as a parameter to this method.
Any class overriding Object#equals(Object obj) should respect this contract, accept any object as an argument, and return false when the argument’s type differs from the expected type. The obj parameter’s type can be checked using instanceof or by comparing the getClass() value:
@Override
public boolean equals(Object obj) {
// ...
if (this.getClass() != obj.getClass()) {
return false;
}
// ...
}
The readObject method is implemented when a Serializable object requires special handling to be reconstructed from a file. The object created by readObject is accessed only by the thread that called the method, thus using the synchronized keyword in this context is unnecessary and causes confusion.
private synchronized void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException { // Noncompliant
//...
}
In Java 8, underscore (_
) cannot be used as a parameter to a lambda, and by Java 9, it’s a keyword. To ensure future portability (not to mention current readability), it should not be used now as an identifier.
private String _; // Noncompliant
According to the Java `Comparable.compareTo(T o) documentation:
public class Foo implements Comparable<Foo> {
@Override
public int compareTo(Foo foo) { /* ... */ } // Noncompliant as the equals(Object obj) method is not overridden
}
notify and notifyAll both wake up sleeping threads waiting on the object’s monitor, but notify only wakes up one single thread, while notifyAll wakes them all up. Unless you do not care which specific thread is woken up, notifyAll should be used instead.
class MyThread implements Runnable {
Object lock = new Object();
@Override
public void run() {
synchronized(lock) {
// ...
lock.notify(); // Noncompliant
}
}
}
The `java.util.function package provides a large array of functional interface definitions for use in lambda expressions and method references. In general it is recommended to use the more specialised form to avoid auto-boxing. For instance IntFunction<Foo> should be preferred over Function<Integer, Foo>.
This rule raises an issue when any of the following substitution is possible:
Current Interface | Preferred Interface |
---|---|
Function<Integer, R> | IntFunction<R> |
Function<Long, R> | LongFunction<R> |
Function<Double, R> | DoubleFunction<R> |
Function<Double,Integer> | DoubleToIntFunction |
Function<Double,Long> | DoubleToLongFunction |
Function<Long,Double> | LongToDoubleFunction |
Function<Long,Integer> | LongToIntFunction |
Function<R,Integer> | ToIntFunction<R> |
Function<R,Long> | ToLongFunction<R> |
Function<R,Double> | ToDoubleFunction<R> |
Function<T,T> | UnaryOperator<T> |
BiFunction<T,T,T> | BinaryOperator<T> |
Consumer<Integer> | IntConsumer |
Consumer<Double> | DoubleConsumer |
Consumer<Long> | LongConsumer |
BiConsumer<T,Integer> | ObjIntConsumer<T> |
BiConsumer<T,Long> | ObjLongConsumer<T> |
BiConsumer<T,Double> | ObjDoubleConsumer<T> |
Predicate<Integer> | IntPredicate |
Predicate<Double> | DoublePredicate |
Predicate<Long> | LongPredicate |
Supplier<Integer> | IntSupplier |
Supplier<Double> | DoubleSupplier |
Supplier<Long> | LongSupplier |
Supplier<Boolean> | BooleanSupplier |
UnaryOperator<Integer> | IntUnaryOperator |
UnaryOperator<Double> | DoubleUnaryOperator |
UnaryOperator<Long> | LongUnaryOperator |
BinaryOperator<Integer> | IntBinaryOperator |
BinaryOperator<Long> | LongBinaryOperator |
BinaryOperator<Double> | DoubleBinaryOperator |
Function<T, Boolean> | Predicate<T> |
BiFunction<T,U,Boolean> | BiPredicate<T,U>` |
public class Foo implements Supplier<Integer> { // Noncompliant
@Override
public Integer get() {
// ...
}
}
By accepting persistent entities as method arguments, the application allows clients to manipulate the object’s properties directly.
import javax.persistence.Entity;
@Entity
public class Wish {
Long productId;
Long quantity;
Client client;
}
@Entity
public class Client {
String clientId;
String name;
String password;
}
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PurchaseOrderController {
@RequestMapping(path = "/saveForLater", method = RequestMethod.POST)
public String saveForLater(Wish wish) { // Noncompliant
session.save(wish);
}
}
Validation is the first line of defense against injection, cross-site scripting, and many other attacks. Omitting it in modern web applications is simply negligent.
When creating a Struts ActionForm, you have the choice of extending something from the org.apache.struts.action package, or extending something from the org.apache.struts.validator package. Since you can’t use the Struts validator capabilities without extending something from the validator
package, that should always be your choice.
public class MyForm extends org.apache.struts.action.ActionForm { // Noncompliant
// ...
If you go to the trouble of importing a symbol statically, then you should make use of it, and you should do so consistently. Similarly, there’s no reason to both import a class and then refer to it in code by its fully-qualified name. Otherwise, maintainers could be confused by the difference between qualified and unqualified references.
import java.util.*;
import java.math.BigInteger;
import static java.lang.String.format;
//...
String s1 = format("%cello %cellow", 'h','f'); // Compliant
String s2 = String.format("%cello %cellow", 'm','y'); // Noncompliant; is this a different format function than on the previous line?
java.util.List<String> list = new java.util.ArrayList<String>(); // Noncompliant; both classes included in java.util.* import
java.math.BigInteger myBigI = BigInteger.ZERO; // Noncompliant. This mixed usage is particularly confusing
By contract, the NullCipher
class provides an “identity cipher” - one that does not transform or encrypt the plaintext in any way. As a consequence, the ciphertext is identical to the plaintext. So this class should be used for testing, and never in production code.
NullCipher nc = new NullCipher();
Both `FixedSizeList from the Commons library, and the list returned from Arrays.asList offer add and remove methods (as required by the List interface they implement), but neither truly supports their use. Both list types have fixed lengths and will throw errors if an add or remove method, or any of their variations, is called.
This rule raises an issue when one of the following methods is invoked on a FixedSizeList instance:
add
addAll
clear
remove
removeAll`
List<String> strings = Arrays.asList("Hello");
strings.add("world"); // Noncompliant
When verifying that code raises a runtime exception, a good practice is to avoid having multiple method calls inside the tested code, to be explicit about which method call is expected to raise the exception.
It increases the clarity of the test, and avoid incorrect testing when another method is actually raising the exception.
@Test
public void testToString() {
// Do you expect get() or toString() throwing the exception?
org.junit.Assert.assertThrows(IndexOutOfBoundsException.class, () -> get().toString());
}
@Test
public void testToStringTryCatchIdiom() {
try {
// Do you expect get() or toString() throwing the exception?
get().toString();
Assert.fail("Expected an IndexOutOfBoundsException to be thrown");
} catch (IndexOutOfBoundsException e) {
// Test exception message...
}
}
Fields marked as transient in a Serializable class will be ignored during serialization and consequently not written out to a file (or stream).
This can be useful in situations such as where the content of a field can be recomputed from other fields. To reduce the output size, this field can be marked as transient and recomputed when a given object is deserialized.
Since transient is very specific to classes that implement Serializable, it is superfluous in classes that do not.
This rule raises an issue when a field is marked as transient, even though the containing class does not implement Serializable.
class Vegetable {
private transient Season ripe; // Noncompliant, the "Vegetable" class does not implement "Serializable" but the field is marked as "transient"
// ...
}
If you’ve gone to the trouble of writing an iterator method in a class that doesn’t implement Iterable, that trivial omission is costing you half the benefit of the method because you can’t use the class in enhanced for
loops.
public class MyList { // Noncompliant
public Iterator iterator() {
//...
}
}
public class MyClass {
public void doSomething(MyList myList) {
Iterator itr = myList.iterator();
while (itr.hasNext() {
Object obj = itr.next();
processObj(obj);
}
}
}
A Spring `singleton bean may be used by many threads at once, and the use of instance (non-static) variables could cause concurrency issues.
This rule applies to classes with the following annotations: @Service, @Component, @Repository, @Scope(“singleton”)`
@Service("animalService")
public class AnimalService {
private int age = 1; // Noncompliant
private static int count = 0; // Compliant; static
@Inject
private AnimalDAO animalDAO; // Compliant; managed by Spring
...
}
Using boxed values in a ternary operator does not simply return one operand or the other based on the condition. Instead, the values are unboxed and coerced to a common type, which can result in a loss of precision when converting one operand from int to float or from long to double.
While this behavior is expected for arithmetic operations, it may be unexpected for the ternary operator. To avoid confusion or unexpected behavior, cast to a compatible type explicitly.
Integer i = 123456789;
Float f = 1.0f;
Number n1 = condition ? i : f; // Noncompliant, unexpected precision loss, n1 = 1.23456792E8
Once a value is known to be null or non-null
, there’s no reason to re-check it unless it has been changed (or potentially changed) in the interim. Doing so anyway may may just be an over-abundance of caution, but it could indicate a bug.
public void assignCoach(Team team, Person person) {
if (team.hasCoach()) { // team is dereferenced
return;
}
if (team != null) { // Noncompliant; if we got this far, team is not null
//...
}
if (person != null) {
// ...
if (disqualified) {
person = getAlternate();
}
}
if (person != null) { // Compliant; person may have changed since last check
team.setCoach(person);
}
if (person != null) { // Noncompliant; no changes to person since last check
// ...
There’s no valid reason to test this with instanceof. The only plausible explanation for such a test is that you’re executing code in a parent class conditionally based on the kind of child class this
is. But code that’s specific to a child class should be in that child class, not in the parent.
public class JunkFood{
public void doSomething() {
if (this instanceof Pizza) { // Noncompliant
// ...
} else if (...
}
}
The old, much-derided Date and Calendar classes have always been confusing and difficult to use properly, particularly in a multi-threaded context. JodaTime
has long been a popular alternative, but now an even better option is built-in. Java 8’s JSR 310 implementation offers specific classes for:
Class | Use for |
---|---|
LocalDate | a date, without time of day, offset, or zone |
LocalTime | the time of day, without date, offset, or zone |
LocalDateTime | the date and time, without offset, or zone |
OffsetDate | a date with an offset such as +02:00, without time of day, or zone |
OffsetTime | the time of day with an offset such as +02:00, without date, or zone |
OffsetDateTime | the date and time with an offset such as +02:00, without a zone |
ZonedDateTime | the date and time with a time zone and offset |
YearMonth | a year and month |
MonthDay | month and day |
Year/MonthOfDay/DayOfWeek/… | classes for the important fields |
DateTimeFields | stores a map of field-value pairs which may be invalid |
Calendrical | access to the low-level API |
Period | a descriptive amount of time, such as “2 months and 3 days” |
Date now = new Date(); // Noncompliant
DateFormat df = new SimpleDateFormat("dd.MM.yyyy");
Calendar christmas = Calendar.getInstance(); // Noncompliant
christmas.setTime(df.parse("25.12.2020"));
A for loop termination condition should test the loop counter against an invariant value that does not change during the execution of the loop. Invariant termination conditions make the program logic easier to understand and maintain.
This rule tracks three types of non-invariant termination conditions:
When the loop counters are updated in the body of the for loop
When the termination condition depends on a method call
When the termination condition depends on an object property since such properties could change during the execution of the loop.
for (int i = 0; i < foo(); i++) { // Noncompliant, "foo()" is not an invariant
// ...
}
Even if it is technically possible, Restricted Identifiers should not be used as identifiers. This is only possible for compatibility reasons, using it in Java code is confusing and should be avoided.
Note that this applies to any version of Java, including the one where these identifiers are not yet restricted, to avoid future confusion.
This rule reports an issue when restricted identifiers:
var
yield
record
are used as identifiers.
var var = "var"; // Noncompliant: compiles but this code is confusing
var = "what is this?";
int yield(int i) { // Noncompliant
return switch (i) {
case 1: yield(0); // This is a yield from switch expression, not a recursive call.
default: yield(i-1);
};
}
String record = "record"; // Noncompliant
Collection.removeIf is more readable and less verbose than using the Iterator.remove idiom. It might also be more performant in some cases, particularly for ArrayList
instances.
for (Iterator it = items.iterator(); it.hasNext();) {
if (this.predicate(it.next())) {
it.remove();
}
}
If the Service Provider does not manage to properly validate the incoming SAML response message signatures, attackers might be able to manipulate the response content without the application noticing. Especially, they might be able to alter the authentication-targeted user.
import org.opensaml.xml.parse.StaticBasicParserPool;
import org.opensaml.xml.parse.ParserPool;
public ParserPool parserPool() {
StaticBasicParserPool staticBasicParserPool = new StaticBasicParserPool();
staticBasicParserPool.setIgnoreComments(false); // Noncompliant
return staticBasicParserPool;
}
JDK7 introduced the class `java.nio.charset.StandardCharsets. It provides constants for all charsets that are guaranteed to be available on every implementation of the Java platform.
ISO_8859_1
US_ASCII
UTF_16
UTF_16BE
UTF_16LE
UTF_8
These constants should be preferred to:
the use of a String such as “UTF-8” which has the drawback of requiring the catch/throw of an UnsupportedEncodingException that will never actually happen
the use of Guava’s Charsets` class, which has been obsolete since JDK7
try {
byte[] bytes = string.getBytes("UTF-8"); // Noncompliant; use a String instead of StandardCharsets.UTF_8
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
// ...
byte[] bytes = string.getBytes(Charsets.UTF_8); // Noncompliant; Guava way obsolete since JDK7
The processHttpRequest method and methods called from it can be executed by multiple threads within the same servlet instance, and state changes to the instance caused by these methods are, therefore, not threadsafe.
This is due to the servlet container creating only one instance of each servlet (javax.servlet.http.HttpServlet) and attaching a dedicated thread to each incoming HTTP request. The same problem exists for org.apache.struts.action.Action but with different methods.
To prevent unexpected behavior, avoiding mutable states in servlets is recommended. Mutable instance fields should either be refactored into local variables or made immutable by declaring them final.
public class MyServlet extends HttpServlet {
String apiVersion = "0.9.1"; // Noncompliant, field changes are not thread-safe
}
In Switch Expressions, an arrow label consisting of a block with a single `yield can be simplified to directly return the value, resulting in cleaner code.
Similarly, for Switch Statements and arrow labels, a break in a block is always redundant and should not be used. Furthermore, if the resulting block contains only one statement, the curly braces of that block can also be omitted.
This rule reports an issue when a case of a Switch Expression contains a block with a single yield or when a Switch Statement contains a block with a break`.
int i = switch (mode) {
case "a" -> { // Noncompliant: Remove the redundant block and yield.
yield 1;
}
default -> { // Noncompliant: Remove the redundant block and yield.
yield 2;
}
};
switch (mode) {
case "a" -> { // Noncompliant: Remove the redundant block and break.
result = 1;
break;
}
default -> { // Noncompliant: Remove the redundant break.
doSomethingElse();
result = 2;
break;
}
}
In a multi-threaded situation, un-`synchronized lazy initialization of static fields could mean that a second thread has access to a half-initialized object while the first thread is still creating it. Allowing such access could cause serious bugs. Instead. the initialization block should be synchronized.
Similarly, updates of such fields should also be synchronized.
This rule raises an issue whenever a lazy static initialization is done on a class with at least one synchronized` method, indicating intended usage in multi-threaded applications.
private static Properties fPreferences = null;
private static Properties getPreferences() {
if (fPreferences == null) {
fPreferences = new Properties(); // Noncompliant
fPreferences.put("loading", "true");
fPreferences.put("filterstack", "true");
readPreferences();
}
return fPreferences;
}
}
There’s no need to null-test a variable before an instanceof test because instanceof tests for null
. Similarly, there’s no need to null-test a variable before dereferencing some other object.
if (myVar != null && myVar instanceof MyClass) { // Noncompliant
// ...
} else if (myVar != null && myOtherVar.equals(myVar) { // Noncompliant
// ...
}
Denoted by the ”@” symbol, annotations are metadata that can be added to classes, methods, and variables for various purposes such as documentation, code analysis, and runtime processing.
Annotations have retention policies that determine in which context they are retained and available for use. There are three retention policies for annotations:
RetentionPolicy.SOURCE - Annotations are only available during compilation and code analysis. They are not included in the compiled class file and are not available at runtime. E.G. @Override, @SuppressWarnings
RetentionPolicy.CLASS - Annotations are included in the compiled class file providing information to the compiler, but they are not retained by the JVM at runtime. This is the default retention policy. E.G. @PreviewFeature
RetentionPolicy.RUNTIME - Annotations are included in the compiled class file and available at runtime. They can be accessed and used by the program through reflection. E.G. @FunctionalInterface, @Deprecated
It is important to understand that only annotations having the RUNTIME retention policy can be accessed at runtime using reflection. For example, the following if condition is true when the method argument is the java.util.function.Function class:
void execute(Class<?> cls) {
if (cls.isAnnotationPresent(FunctionalInterface.class)) {
// ...
}
}
Before Java 8, a container annotation was required as wrapper to use multiple instances of the same annotation. As of Java 8, this is no longer necessary. Instead, these annotations should be used directly without a wrapper, resulting in cleaner and more readable code.
This rule is automatically disabled when the project’s sonar.java.source is lower than 8 as repeating annotations were introduced in Java 8.
@SomeAnnotations({ // Noncompliant, wrapper annotations are not necessary in Java 8+
@SomeAnnotation(..a..),
@SomeAnnotation(..b..),
@SomeAnnotation(..c..),
})
public class SomeClass {
...
}
Java 21 virtual threads allow the JVM to optimize the usage of OS threads, by mounting and unmounting them on an OS thread when needed, and making them more efficient when dealing with blocking operations such as HTTP requests or I/O.
However, when code is executed inside a synchronized block or synchronized method, the virtual thread stays pinned to the underlying OS thread and cannot be unmounted during a blocking operation. This will cause the OS thread to be blocked, which can impact the scalability of the application.
Therefore, virtual threads should not execute code that contains synchronized blocks or invokes synchronized methods. Platform threads should be used in these cases.
This rule raises an issue when a virtual thread contains synchronized blocks or invokes synchronized methods.
void enqueue(){
Thread.startVirtualThread(() -> { // Noncompliant; use a platform thread instead
setupOperations();
dequeLogic();
}
});
}
According to the Java documentation, any implementation of the `InputSteam.read() method is supposed to read the next byte of data from the input stream. The value byte must be an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned.
But in Java, the byte primitive data type is an 8-bit signed two’s complement integer. It has a minimum value of -128 and a maximum value of 127. So by contract, the implementation of an InputSteam.read() method should never directly return a byte` primitive data type. A conversion into an unsigned byte must be done before by applying a bitmask.
@Override
public int read() throws IOException {
if (pos == buffer.length()) {
return -1;
}
return buffer.getByte(pos++); // Noncompliant, a signed byte value is returned
}
Setting the wrong Content-Type for a response can leave an application vulnerable to cross-site scripting attacks. Specifically, JSON should always be served with the `application/json Content-Type.
This rule checks the Content-Type of responses containing classes in the org.json and javax.json` packages.
public void doGet(HttpServletRequest request, HttpServletResponse response) {
JSONObject jsonRespone = getJsonResponse(request);
try {
response.setContentType("text/html"); // Noncompliant; wrong type
PrintWriter out = response.getWriter();
out.println(jsonResponse.toJSONString());
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) { // Noncompliant; response type not set
JSONObject jsonRespone = getJsonResponse(request);
try {
PrintWriter out = response.getWriter();
out.println(jsonResponse.toJSONString());
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Hibernate’s lazy loading allows you to retrieve just the data of the current class without being forced to load all its related classes. For instance with lazy loading, you can pull up an instance of a `Lecture @Entity without being forced to load all its Students.
But that’s only if you’re storing the Students in a collection. Store them in an array instead, and the benefits of lazy loading are no longer available.
This rule raises an issue on each array in @Entity` classes.
@Entity
public class Lecture {
@OneToMany
private Student [] attendees; // Noncompliant
// ...
}
Configured URL matchers are considered in the order they are declared. Especially, for a given resource, if a looser filter is defined before a stricter one, only the less secure configuration will apply. No request will ever reach the stricter rule.
This rule raises an issue when:
A URL pattern ending with ** precedes another one having the same prefix. E.g. /admin/** is defined before /admin/example/**
A pattern without wildcard characters is preceded by another one that matches it. E.g.:
/page-index/db is defined after /page*/**
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/admin/login").permitAll() // Noncompliant
.antMatchers("/**", "/home").permitAll()
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // Noncompliant
.and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}
`ThreadLocal variables are supposed to be garbage collected once the holding thread is no longer alive. Memory leaks can occur when holding threads are re-used which is the case on application servers using pool of threads.
To avoid such problems, it is recommended to always clean up ThreadLocal variables using the remove() method to remove the current thread’s value for the ThreadLocal variable.
In addition, calling set(null) to remove the value might keep the reference to this pointer in the map, which can cause memory leak in some scenarios. Using remove` is safer to avoid this issue.
public class ThreadLocalUserSession implements UserSession {
private static final ThreadLocal<UserSession> DELEGATE = new ThreadLocal<>();
public UserSession get() {
UserSession session = DELEGATE.get();
if (session != null) {
return session;
}
throw new UnauthorizedException("User is not authenticated");
}
public void set(UserSession session) {
DELEGATE.set(session);
}
public void incorrectCleanup() {
DELEGATE.set(null); // Noncompliant
}
// some other methods without a call to DELEGATE.remove()
}
Shared naming conventions allow teams to collaborate efficiently.
This rule raises an issue when a method name does not match a provided regular expression.
For example, with the default provided regular expression ^[a-z][a-zA-Z0-9]*$
, the method:
public int DoSomething(){...} // Noncompliant
The Reader.read() and the BufferedReader.readLine() are used for reading data from a data source. The return value of these methods is the data read from the data source, or null when the end of the data source is reached. If the return value is ignored, the data read from the source is thrown away and may indicate a bug.
This rule raises an issue when the return values of Reader.read() and BufferedReader.readLine() and their subclasses are ignored or merely null-checked.
public void doSomethingWithFile(String fileName) {
try(BufferedReader buffReader = new BufferedReader(new FileReader(fileName))) {
while (buffReader.readLine() != null) { // Noncompliant
// ...
}
} catch (IOException e) {
// ...
}
}
Unlike similar AssertJ methods testing exceptions (`assertThatCode(), assertThatExceptionOfType(), …), the assertThatThrownBy() method can be used alone, failing if the code did not raise any exception.
Still, only testing that an exception was raised is not enough to guarantee that it was the expected one, and you should test the exception type or content further. In addition, it will make explicit what you are expecting, without relying on side-effects.
This rule raises an issue when assertThatThrownBy` is used, without testing the exception further.
assertThatThrownBy(() -> shouldThrow()); // Noncompliant, is it really the exception you expected?
JUnit assertions should not be made from the run method of a Runnable, because their failure may not be detected in the test that initiated them. Failed assertions throw assertion errors. However, if the error is thrown from another thread than the one that initiated the test, the thread will exit but the test will not fail.
class RunnableWithAnAssertion extends Thread {
@Override
public void run() {
Assert.assertEquals(expected, actual); // Noncompliant
}
@Test
void test() {
RunnableWithAnAssertion otherThread = new RunnableWithAnAssertion();
otherThread.start(); // The assertion in the run method above will be executed by other thread than the current one
// ...
// Perform some actions that do not make the test fail
// ...
Assert.assertTrue(true);
}
}
Having too many return statements in a method increases the method’s essential complexity because the flow of execution is broken each time a return statement is encountered. This makes it harder to read and understand the logic of the method.
public boolean myMethod() { // Noncompliant; there are 4 return statements
if (condition1) {
return true;
} else {
if (condition2) {
return false;
} else {
return true;
}
}
return false;
}
Java 7’s try-with-resources structure automatically handles closing the resources that the try itself opens. Thus, adding an explicit close()
call is redundant and potentially confusing.
try (PrintWriter writer = new PrintWriter(process.getOutputStream())) {
String contents = file.contents();
writer.write(new Gson().toJson(new MyObject(contents)));
writer.flush();
writer.close(); // Noncompliant
}
In records, introduced in Java 16, there are 2 ways to write a custom constructor: canonical and compact.
A canonical constructor is an ordinary constructor with arguments for all private fields. The default implementation just provides initialization for all private fields and there is no need to write it manually. You might want to write it yourself when you need to customize the constructor logic.
A compact constructor doesn’t have parameters defined explicitly, parentheses are omitted and access to private fields is not possible (even via this
). The compact constructor has access to the constructor’s arguments and its body is executed right before the field initialization. It’s a perfect place to provide validation.
This rule reports an issue when a canonical constructor can be easily replaced by a compact version when these requirements are met:
the last statements are trivial field initializations
no statement reads from fields or components
there are other statements in the constructor (case covered by S6207: redundant constructors in records)
record Person(String name, int age) {
Person(String name, int age) { // Noncompliant
if (age < 0) {
throw new IllegalArgumentException("Negative age");
}
this.name = name;
this.age = age;
}
}
The repetition of a unary operator is usually a typo. The second operator invalidates the first one in most cases:
int i = 1;
int j = - - -i; // Noncompliant: equivalent to "-i"
int k = ~~~i; // Noncompliant: equivalent to "~i"
int m = + +i; // Noncompliant: equivalent to "i"
boolean b = false;
boolean c = !!!b; // Noncompliant
Non final classes shouldn’t use a hardcoded class name in the equals
method. Doing so breaks the method for subclasses. Instead, make the comparison dynamic.
public class Fruit {
private Season ripe;
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (Fruit.class == obj.class) { // Noncompliant
return false;
}
// ...
In Records, serialization is not done the same way as for ordinary serializable or externalizable classes. The serialized representation of a record object will be a sequence of values (record components). During the deserialization of records, the stream of components is read and components are constructed. Then the record object is recreated by invoking the record’s canonical constructor with the component values serving as arguments (or default values for absent arguments).
This process cannot be customized, so any class-specific `writeObject, readObject, readObjectNoData, writeExternal, and readExternal methods or serialPersistentFields fields in record classes are ignored during serialization and deserialization.
However, there is a way to substitute serialized/deserialized objects in writeReplace and readResolve.
This rule raises an issue when any of writeObject, readObject, readObjectNoData, writeExternal, readExternal or serialPersistentFields` are present as members in a Record class.
record Record() implements Serializable {
@Serial
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; // Noncompliant
@Serial
private void writeObject(ObjectOutputStream out) throws IOException { // Noncompliant
...
}
}
record Record() implements Externalizable {
@Override
public void writeExternal(ObjectOutput out) throws IOException { // Noncompliant
...
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // Noncompliant
...
}
}
Java 21 introduces case null for switch. It is a more concise and readable way to handle nullability compared to an if statement before a switch.
switch (s) {
case null: /* code if null */
// ...
}
When the application does not implement controls over the JMS object types, its clients could be able to force the deserialization of arbitrary objects. This may lead to deserialization injection attacks.
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
factory.setTrustAllPackages(true); // Noncompliant
StringBuffer and StringBuilder instances that are appended but never toStringed needlessly clutter the code, and worse are a drag on performance. Either they should be removed, or the missing toString
call added.
public void doSomething(List<String> strings) {
StringBuilder sb = new StringBuilder(); // Noncompliant
sb.append("Got: ");
for (String str : strings) {
sb.append(str).append(", ");
// ...
}
}
When using the `Stream API, call chains should be simplified as much as possible. Not only does it make the code easier to read, it also avoid creating unnecessary temporary objects.
This rule raises an issue when one of the following substitution is possible:
Original | Preferred |
---|---|
stream.filter(predicate).findFirst().isPresent() | stream.anyMatch(predicate) |
stream.filter(predicate).findAny().isPresent() | stream.anyMatch(predicate) |
!stream.anyMatch(predicate) | stream.noneMatch(predicate) |
!stream.anyMatch(x -> !(…)) | stream.allMatch(…) |
stream.map(mapper).anyMatch(Boolean::booleanValue) | stream.anyMatch(predicate)` |
boolean hasRed = widgets.stream().filter(w -> w.getColor() == RED).findFirst().isPresent(); // Noncompliant
java.lang.Error and its subclasses represent abnormal conditions, such as OutOfMemoryError
, which should only be encountered by the Java Virtual Machine.
public class MyException extends Error { /* ... */ } // Noncompliant
A common reason for a poorly performant query is because it’s processing more data than required.
Querying unnecessary data demands extra work on the server, adds network overhead, and consumes memory and CPU resources on the application server. The effect is amplified when the query includes multiple joins.
The rule flags an issue when a SELECT * query is provided as an argument to methods in java.sql.Connection and java.sql.Statement.
public class OrderRepository {
public record OrderSummary(String name, String orderId, BigDecimal price) { }
public List<OrderSummary> queryOrderSummaries(Connection conn) {
String sql = "SELECT * " + // Noncompliant
"FROM Orders JOIN Customers ON Orders.customerId = Customers.id ";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
return convertResultToOrderSummaryList(rs);
}
}
Objects annotated with Mockito annotations `@Mock, @Spy, @Captor, or @InjectMocks need to be initialized explicitly.
There are several ways to do this:
Call MockitoAnnotations.openMocks(this) or MockitoAnnotations.initMocks(this) in a setup method
Annotate test class with @RunWith(MockitoJUnitRunner.class) (JUnit 4)
Annotate test class with @ExtendWith(MockitoExtension.class) (JUnit 5 Jupiter)
Use @Rule public MockitoRule rule = MockitoJUnit.rule();
Test using uninitialized mocks will fail.
Note that this only applies to annotated Mockito objects. It is not necessary to initialize objects instantiated via Mockito.mock() or Mockito.spy()`.
This rule raises an issue when a test class uses uninitialized mocks.
public class FooTest { // Noncompliant: Mockito initialization missing
@Mock private Bar bar;
@Spy private Baz baz;
@InjectMocks private Foo fooUnderTest;
@Test
void someTest() {
// test something ...
}
@Nested
public class Nested {
@Mock
private Bar bar;
}
Some mathematical operations are unnecessary and should not be performed because their results are predictable.
For instance, anyValue % 1 will always return 0, as any integer value can be divided by 1 without remainder.
Similarly, casting a non-floating-point to a floating-point value and then passing it to Math.round, Math.ceil, or Math.floor is also unnecessary, as the result will always be the original value.
The following operations are unnecessary when given any constant value: Math.abs, Math.ceil, Math.floor, Math.rint, Math.round. Instead, use the result of the operation directly.
The following operations are unnecessary with certain constants and can be replaced by the result of the operation directly:
Operation | Value |
---|---|
acos | 0.0 or 1.0 |
asin | 0.0 or 1.0 |
atan | 0.0 or 1.0 |
atan2 | 0.0 |
cbrt | 0.0 or 1.0 |
cos | 0.0 |
cosh | 0.0 |
exp | 0.0 or 1.0 |
expm1 | 0.0 |
log | 0.0 or 1.0 |
log10 | 0.0 or 1.0 |
sin | 0.0 |
sinh | 0.0 |
sqrt | 0.0 or 1.0 |
tan | 0.0 |
tanh | 0.0 |
toDegrees | 0.0 or 1.0 |
toRadians | 0.0 |
public void doMath(int a) {
double res1 = Math.floor((double)a); // Noncompliant, the result will always be equal to '(double) a'
double res2 = Math.ceil(4.2); // Noncompliant, the result will always be 5.0
double res3 = Math.atan(0.0); // Noncompliant, the result will always be 0.0
}
The Spring framework’s @RestController annotation is equivalent to using the @Controller and @ResponseBody annotations together. As such, it is redundant to add a @ResponseBody annotation when the class is already annotated with @RestController.
@RestController
public class MyController {
@ResponseBody // Noncompliant, the @RestController annotation already implies @ResponseBody
@RequestMapping("/hello")
public String hello() {
return "Hello World!";
}
}
Passing single null or primitive array argument to the variable arity method may not work as expected. In the case of null, it is not passed as array with single element, but the argument itself is null. In the case of a primitive array, if the formal parameter is Object…
, it is passed as a single element array. This may not be obvious to someone not familiar with such corner cases, and it is probably better to avoid such ambiguities by explicitly casting the argument to the desired type.
class A {
public static void main(String[] args) {
vararg(null); // Noncompliant, prints "null"
int[] arr = {1,2,3};
vararg(arr); // Noncompliant, prints "length: 1"
}
static void vararg(Object... s) {
if (s == null) {
System.out.println("null");
} else {
System.out.println("length: " + s.length);
}
}
}
@VisibleForTesting can be used to mark methods, fields and classes whose visibility restrictions have been relaxed more than necessary for the API to allow for easier unit testing.
Access to such methods, fields and classes only possible thanks to this relaxed visibility is fine for test code, but it should be avoided in production code. In production code these methods should be treated as if they are private.
Supported framework:
Guava: `com.google.common.annotations.VisibleForTesting
AssertJ: org.assertj.core.util.VisibleForTesting
Android: androidx.annotation.VisibleForTesting
Apache Flink: org.apache.flink.annotation.VisibleForTesting
or any other annotation named VisibleForTesting`
/** src/main/java/MyObject.java */
@VisibleForTesting String foo;
/** src/main/java/Service.java */
new MyObject().foo; // Noncompliant, foo is accessed from production code
Java 15 introduced feature of `sealed classes. With sealed classes and interfaces you can specify a strict hierarchy of types and restrict possible inheritance.
Although this feature can help to make code safer, it is not applicable everywhere. Functional interfaces can not be sealed. This means that if an interface with a single abstract method is declared with a sealed keyword, its implementation can’t be replaced with a lambda.
This rule reports an issue when an interface with a single abstract method is marked sealed`.
public sealed interface F permits ... { // Noncompliant
void f();
}
When List.remove() is called, the list shrinks, and the indices of all elements following the removed element are decremented by one. If this operation is performed within a loop that iterates through the elements in ascending order, it will cause the loop to skip the element immediately following the removed element.
void removeFrom(List<String> list) {
// expected: iterate over all list elements
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isEmpty()) {
list.remove(i); // Noncompliant, next element is skipped
}
}
}
According to the EJB specification, EJB’s:
This rule raises an issue each time an EJB obtains a class loader.
ClassLoader loader = this.getClass().getClassLoader(); // Noncompliant
ClassLoader loader = new MyClassLoader(); // Noncompliant
Overriding a parent class’ method implementation with an `abstract method is a terrible practice for a number of reasons:
it blocks invocation of the original class’ method by children of the abstract class.
it requires the abstract` class’ children to re-implement (copy/paste?) the original class’ logic.
it violates the inherited contract.
public class Parent {
public int getNumber() {
return 1;
}
}
public abstract class AbstractChild {
abstract public int getNumber(); // Noncompliant
}
In Java, the Thread class represents a thread of execution. Synchronization between threads is typically achieved using objects or shared resources.
The methods wait(…), notify(), and notifyAll() are related to the underlying object’s monitor and are designed to be called on objects that act as locks or monitors for synchronization. These methods are available on Java Object and, therefore, automatically inherited by all objects, including Thread.
Calling these methods on a Thread may corrupt the behavior of the JVM, which relies on them to change the state of the thread (BLOCKED, WAITING,…).
Thread myThread = new Thread(new RunnableJob());
...
myThread.wait(); // Noncompliant
An equals
method that unconditionally returns the same answer is an error likely to cause many bugs.
public class Fruit extends Food {
private Season ripe;
public boolean equals(Object obj) {
return ripe.equals(this); // Noncompliant
}
When using null-related annotations at global scope level, for instance using `javax.annotation.ParametersAreNonnullByDefault (from JSR-305) at package level, it means that all the parameters to all the methods included in the package will, or should, be considered Non-null. It is equivalent to annotating every parameter in every method with non-null annotations (such as @Nonnull).
The rule raises an issue every time a parameter could be null` for a method invocation, where the method is annotated as forbidding null parameters.
@javax.annotation.ParametersAreNonnullByDefault
class A {
void foo() {
bar(getValue()); // Noncompliant - method 'bar' do not expect 'null' values as parameter
}
void bar(Object o) { // 'o' is by contract expected never to be null
// ...
}
@javax.annotation.CheckForNull
abstract Object getValue();
}
Calling an overridable method from a constructor could result in failures or strange behaviors when instantiating a subclass which overrides the method.
For example:
The subclass class constructor starts by contract by calling the parent class constructor.
The parent class constructor calls the method, which has been overridden in the child class.
If the behavior of the child class method depends on fields that are initialized in the child class constructor, unexpected behavior (like a NullPointerException) can result, because the fields aren’t initialized yet.
public class Parent {
public Parent () {
doSomething(); // Noncompliant
}
public void doSomething () { // not final; can be overridden
...
}
}
public class Child extends Parent {
private String foo;
public Child(String foo) {
super(); // leads to call doSomething() in Parent constructor which triggers a NullPointerException as foo has not yet been initialized
this.foo = foo;
}
public void doSomething () {
System.out.println(this.foo.length());
}
}
`Optional value can hold either a value or not. The value held in the Optional can be accessed using the get() method, but it will throw a
NoSuchElementException if there is no value present. To avoid the exception, calling the isPresent() or ! isEmpty() method should always be done before any call to get().
Alternatively, note that other methods such as orElse(…), orElseGet(…) or orElseThrow(…) can be used to specify what to do with an empty Optional`.
Optional<String> value = this.getOptionalValue();
// ...
String stringValue = value.get(); // Noncompliant
Throwing generic exceptions such as `Error, RuntimeException, Throwable, and Exception will have a negative impact on any code trying to catch these exceptions.
From a consumer perspective, it is generally a best practice to only catch exceptions you intend to handle. Other exceptions should ideally be let to propagate up the stack trace so that they can be dealt with appropriately. When a generic exception is thrown, it forces consumers to catch exceptions they do not intend to handle, which they then have to re-throw.
Besides, when working with a generic type of exception, the only way to distinguish between multiple exceptions is to check their message, which is error-prone and difficult to maintain. Legitimate exceptions may be unintentionally silenced and errors may be hidden.
For instance, when a Throwable is caught and not re-thrown, it may mask errors such as OutOfMemoryError` and prevent the program from terminating gracefully.
When throwing an exception, it is therefore recommended to throw the most specific exception possible so that it can be handled intentionally by consumers.
@Override
public void myMethod() throws Exception {...}
Well-named functions can allow the users of your code to understand at a glance what to expect from the function - even before reading the documentation. Toward that end, methods returning a boolean should have names that start with “is” or “has” rather than with “get”.
public boolean getFoo() { // Noncompliant
// ...
}
public boolean getBar(Bar c) { // Noncompliant
// ...
}
public boolean testForBar(Bar c) { // Compliant - The method does not start by 'get'.
// ...
}
The ability to map a class to a database table has made database interaction in Java a lot easier. But map multiple classes to the same table and you’ll end up with a classic case of the left hand not knowing what the right hand is doing. In the worse case scenario, it could lead to serious data corruption.
This rule raises an issue when multiple classes are mapped to the same table with Hibernate or JPA annotations.
@Entity // implicitly mapped to "point" table
public class Point {
// ..
}
@Entity
@Table(name = "point") // Noncompliant
public class Spot {
// ...
}
When using POSIX classes like `\p{Alpha} without the UNICODE_CHARACTER_CLASS flag or when using hard-coded character classes like “[a-zA-Z]”, letters outside of the ASCII range, such as umlauts, accented letters or letter from non-Latin languages, won’t be matched. This may cause code to incorrectly handle input containing such letters.
To correctly handle non-ASCII input, it is recommended to use Unicode classes like \p{IsAlphabetic}. When using POSIX classes, Unicode support should be enabled by either passing Pattern.UNICODE_CHARACTER_CLASS as a flag to Pattern.compile or by using (?U)` inside the regex.
Pattern.compile("[a-zA-Z]");
Pattern.compile("\\p{Alpha}");
Testing equality or nullness with JUnit’s assertTrue() or assertFalse()
should be simplified to the corresponding dedicated assertion.
Assert.assertTrue(a.equals(b));
Assert.assertTrue(a == b);
Assert.assertTrue(a == null);
Assert.assertTrue(a != null);
Assert.assertFalse(a.equals(b));
Using `File.createTempFile as the first step in creating a temporary directory causes a race condition and is inherently unreliable and insecure. Instead, Files.createTempDirectory (Java 7+) or a library function such as Guava’s similarly-named Files.createTempDir should be used.
This rule raises an issue when the following steps are taken in immediate sequence:
call to File.createTempFile
delete resulting file
call mkdir on the File object
Note that this rule is automatically disabled when the project’s sonar.java.source is lower than 7`.
File tempDir;
tempDir = File.createTempFile("", ".");
tempDir.delete();
tempDir.mkdir(); // Noncompliant
It is not uncommon, for instance when dealing with SQL requests, to have repeated calls to StringBuilder.append()
to create a long (sometimes really long) String that will be then passed to the appropriate subsystem (e.g. jdbc.Statement()). This is very undesirable because it makes it more difficult to read, and maintain, the statement in the String due to overlapping syntaxes.
It is highly recommended to address such a case with an external text file loaded as a resource.
sb = new StringBuilder()
.append("SELECT CASE ")
.append("WHEN year = 'FR' THEN 'FR'")
.append("WHEN year = 'SO' THEN 'SO'")
.append("WHEN year = 'JR' THEN 'JR'")
.append("WHEN year = 'SR' THEN 'SR'")
.append("ELSE 'No Year Data' END AS year_group,")
.append("COUNT(1) AS count")
.append("FROM benn.college_football_players")
.append("GROUP BY CASE WHEN year = 'FR' THEN 'FR'")
.append("WHEN year = 'SO' THEN 'SO'")
.append("WHEN year = 'JR' THEN 'JR'")
.append("WHEN year = 'SR' THEN 'SR'")
.append("ELSE 'No Year Data' END");
The purpose of the @Value annotation in org.springframework.beans.factory.annotation is to inject a value into a field or method based on the Spring context after it has been established.
If the annotation does not include an expression (either Spring Expression Language or a property injection), the injected value is a simple constant that does not depend on the Spring context, making the annotation replaceable with a standard field initialization statement.
This not only implies the redundant use of @Value, but could also indicate an error where the expression indicators (#, $) were omitted by mistake.
@Value("catalog.name") // Noncompliant, this will not inject the property
String catalog;
For maximum reusability, methods should accept parameters with as little specialization as possible. So unless specific features from a child class are required by a method, a type higher up the class hierarchy should be used instead.
public void printSize(ArrayList<Object> list) { // Collection can be used instead
System.out.println(list.size());
}
public static void loop(List<Object> list) { // java.lang.Iterable can be used instead
for (Object o : list) {
o.toString();
}
}
Because printf-style format strings are interpreted at runtime, rather than validated by the Java compiler, they can contain errors that lead to unexpected behavior or runtime errors. This rule statically validates the good behavior of printf-style formats when calling the format(…) methods of java.util.Formatter, java.lang.String, java.io.PrintStream, MessageFormat, and java.io.PrintWriter classes and the printf(…) methods of java.io.PrintStream or java.io.PrintWriter
classes.
String.format("The value of my integer is %d", "Hello World"); // Noncompliant; an 'int' is expected rather than a String
String.format("Duke's Birthday year is %tX", c); //Noncompliant; X is not a supported time conversion character
String.format("Display %0$d and then %d", 1); //Noncompliant; arguments are numbered starting from 1
String.format("Not enough arguments %d and %d", 1); //Noncompliant; the second argument is missing
String.format("%< is equals to %d", 2); //Noncompliant; the argument index '<' refers to the previous format specifier but there isn't one
MessageFormat.format("Result {1}.", value); // Noncompliant; Not enough arguments. (first element is {0})
MessageFormat.format("Result {{0}.", value); // Noncompliant; Unbalanced number of curly brace (single curly braces should be escaped)
MessageFormat.format("Result ' {0}", value); // Noncompliant; Unbalanced number of quotes (single quote must be escaped)
java.util.logging.Logger logger;
logger.log(java.util.logging.Level.SEVERE, "Result {1}!", 14); // Noncompliant - Not enough arguments.
org.slf4j.Logger slf4jLog;
org.slf4j.Marker marker;
slf4jLog.debug(marker, "message {}"); // Noncompliant - Not enough arguments.
org.apache.logging.log4j.Logger log4jLog;
log4jLog.debug("message {}"); // Noncompliant - Not enough arguments.
ThreadPoolExecutor is an object that efficiently manages and controls the execution of multiple tasks in a thread pool. A thread pool is a collection of pre-initialized threads ready to execute tasks. Instead of creating a new thread for each task, which can be costly in terms of system resources, a thread pool reuses existing threads.
java.util.concurrent.ScheduledThreadPoolExecutor is an extension of ThreadPoolExecutor that can additionally schedule commands to run after a given delay or to execute periodically.
ScheduledThreadPoolExecutor ‘s pool is sized with corePoolSize, so setting corePoolSize to zero means the executor will have no threads and run nothing. corePoolSize should have a value greater than zero and valid for your tasks.
This rule detects instances where corePoolSize is set to zero via its setter or the object constructor.
public void do(){
int poolSize = 5; // value greater than 0
ScheduledThreadPoolExecutor threadPool1 = new ScheduledThreadPoolExecutor(0); // Noncompliant
ScheduledThreadPoolExecutor threadPool2 = new ScheduledThreadPoolExecutor(poolSize);
threadPool2.setCorePoolSize(0); // Noncompliant
}
The request handler function in a Controller should set the appropriate HTTP status code based on the operation’s success or failure. This is done by returning a Response object with the appropriate status code.
If an exception is thrown during the execution of the handler, the status code should be in the range of 4xx or 5xx. Examples of such codes are BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, INTERNAL_SERVER_ERROR, BAD_GATEWAY, SERVICE_UNAVAILABLE, etc.
The status code should be 1xx, 2xx, or 3xx if no exception is thrown and the operation is considered successful. Such codes include OK, CREATED, MOVED_PERMANENTLY, FOUND, etc.
@Controller
public class UserController {
public ResponseEntity<User> getUserById(Long userId) {
try {
User user = userService.getUserById(userId);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(user); // Noncompliant: Setting 500 for a successful operation
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.OK).build(); // Noncompliant: Setting 200 for exception
}
}
}
Java offers a built-in serialization mechanism for classes that implement the Serializable interface. The developer can either rely on Java’s default serialization and deserialization logic or implement custom methods for these tasks. The JVM will use methods such as readObject and writeObject to execute custom behavior. This only works, however, if these methods match exactly the expected signatures. If they do not, the JVM will fall back to the default logic, resulting in unexpected behavior at runtime, while the developer believes that the default logic has been overidden.
This rule raises an issue if an implementation of writeObject, readObject, readObjectNoData, writeReplace, or readResolve has an incorrect access modifier, return type, or is not static when it should be (and vice-versa).
public class Watermelon implements Serializable {
void writeObject(java.io.ObjectOutputStream out) // Noncompliant, "writeObject" needs to be private, which it is not here
throws IOException
{...}
static Object readResolve() throws ObjectStreamException // Noncompliant, "readResolve" should not be static
{...}
Watermelon writeReplace() throws ObjectStreamException // Noncompliant, "writeReplace" must return "java.lang.Object"
{...}
}
In certain Android methods, calls to the `super version of the method should always come first. Otherwise, you risk leaving the job half-done.
This rule raises an issue when the following Activity methods do not begin with a call to super:
onCreate
onConfigurationChanged
onPostCreate
onPostResume
onRestart
onRestoreInstanceState
onResume
onStart`
public void onCreate(Bundle bundle) { // Noncompliant; super call missing
doSomething();
}
public void onPostCreate(Bundle bundle) {
doSomethingElse();
super.onPostCreate(bundle); // Noncompliant; should be first statement
}
Classes annotated as @Controller in Spring are responsible for handling incoming web requests. When annotating methods or the entire controller with @ResponseBody, the return value of said methods will be serialized and set as the response body. In other words, it tells the Spring framework that this method does not produce a view. This mechanism is commonly used to create API endpoints.
Spring provides @RestController as a convenient annotation to replace the combination of @Controller and @ResponseBody. The two are functionally identical, so the single annotation approach is preferred.
This rule will raise an issue on a class that is annotated with @Controller if:
the class is also annotated with @ResponseBody or
all methods in said class are annotated with @ResponseBody.
@Controller
@ResponseBody
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello World!";
}
}
Calling System.exit(int status) or Rutime.getRuntime().exit(int status) calls the shutdown hooks and shuts downs the entire Java virtual machine. Calling Runtime.getRuntime().halt(int)
does an immediate shutdown, without calling the shutdown hooks, and skipping finalization.
Each of these methods should be used with extreme care, and only when the intent is to stop the whole Java process. For instance, none of them should be called from applications running in a J2EE container.
System.exit(0);
Runtime.getRuntime().exit(0);
Runtime.getRuntime().halt(0);
This rule is not really a rule, but a demonstration of the features from Asciidoc that can appear in a rule description.
More specifically, its “How to fix it” section contains several frameworks.
FIXME
By default case insensitivity only affects letters in the ASCII range. This can be changed by either passing Pattern.UNICODE_CASE or Pattern.UNICODE_CHARACTER_CLASS as an argument to Pattern.compile or using (?u) or (?U)
within the regex.
If not done, regular expressions involving non-ASCII letters will still handle those letters as being case sensitive.
Pattern.compile("söme pättern", Pattern.CASE_INSENSITIVE);
str.matches("(?i)söme pättern");
str.matches("(?i:söme) pättern");
Most checks against an indexOf value compare it with -1 because 0 is a valid index. Checking against > 0 ignores the first element, which is likely a bug.
String name = "ishmael";
if (name.indexOf("ish") > 0) { // Noncompliant
// ...
}
Generic types (types with type parameters) have been introduced into Java with language version 1.5. If type parameters are specified for a class or method, it is still possible to ignore them to keep backward compatibility with older code, which is called the raw type of the class or interface.
Using raw type expressions is highly discouraged because the compiler cannot perform static type checking on them. This means that the compiler will not report typing errors about them at compile time, but a ClassCastException will be thrown during runtime.
In Java 1.5, generics were also added to the Java collections API, and the data structures in java.util, such as List, Set, or Map, now feature type parameters. Collections.EMPTY_LIST, Collections.EMPTY_SET, and Collections.EMPTY_MAP are relics from before generics, and they return raw lists, sets, or maps, with the limitations mentioned above.
List<String> collection1 = Collections.EMPTY_LIST; // Noncompliant, raw List
Set<Float> collection2 = Collections.EMPTY_SET; // Noncompliant, raw Set
Map<Int, String> collection3 = Collections.EMPTY_MAP; // Noncompliant, raw Map
Iterating over a collection using a for-each loop in Java relies on iterators.
An iterator is an object that allows you to traverse a collection of elements, such as a list or a dictionary. Iterators are used in for-each loops to iterate over the elements of a collection one at a time.
It is important to note that iterators are designed to be read-only. Modifying a collection while iterating over it can cause unexpected behavior, as the iterator may skip over or repeat elements. Therefore, it is important to avoid modifying a collection while iterating over it to ensure that your code behaves as expected.
Most JDK collection implementations don’t support such modification and may throw a ConcurrentModificationException. Even if no such exception is thrown, attempting to modify a collection during iteration could be the source of incorrect or unspecified behaviors in the code.
If you still want to modify the collection, it is best to refactor the code and use a second collection (e.g by using streams and filter operations).
public static void foo(List<String> lst) {
for (String element : lst) {
if (element.startsWith("x")) {
lst.remove(element); // Noncompliant: lst size has been modified by "remove" call while it's iterated.
}
}
}
The BigDecimal is used to represents immutable, arbitrary-precision signed decimal numbers.
Differently from the BigDecimal, the double primitive type and the Double type have limited precision due to the use of double-precision 64-bit IEEE 754 floating point. Because of floating point imprecision, the BigDecimal(double) constructor can be somewhat unpredictable.
For example writing new BigDecimal(0.1) doesn’t create a BigDecimal which is exactly equal to 0.1, but it is equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length).
double d = 1.1;
BigDecimal bd1 = new BigDecimal(d); // Noncompliant
BigDecimal bd2 = new BigDecimal(1.1); // Noncompliant
Primitives can be read and written to atomically. Except for `long and double, that is. These 64-bit primitives must be marked volatile in multi-threaded environments, or swapped out for their atomic counterparts: AtomicLong, and AtomicDouble to guarantee that their updates are always visible to other threads.
Similarly, to ensure that updates to 32-bit primitives are visible to all threads, they should also be marked volatile`.
long m = 0; // Noncompliant
public void increment() {
m++;
}
In regular expressions the escape sequence `\cX, where the X stands for any character that’s either @, any capital ASCII letter, [, , ], ^ or _, represents the control character that “corresponds” to the character following \c, meaning the control character that comes 64 bytes before the given character in the ASCII encoding.
In some other regex engines (for example in that of Perl) this escape sequence is case insensitive and \cd produces the same control character as \cD. Further using \c with a character that’s neither @, any ASCII letter, [, , ], ^ nor _, will produce a warning or error in those engines. Neither of these things is true in Java, where the value of the character is always XORed with 64 without checking that this operation makes sense. Since this won’t lead to a sensible result for characters that are outside of the @ to _ range, using \c` with such characters is almost certainly a mistake.
Pattern.compile("\\ca"); // Noncompliant, 'a' is not an upper case letter
Pattern.compile("\\c!"); // Noncompliant, '!' is outside of the '@'-'_' range
This rule raises an issue when:
a JavaMail’s `javax.mail.Session is created with a Properties object having no mail.smtp.ssl.checkserveridentity or mail.smtps.ssl.checkserveridentity not configured to true
a Apache Common Emails’s org.apache.commons.mail.SimpleEmail is used with setSSLOnConnect(true) or setStartTLSEnabled(true) or setStartTLSRequired(true) without a call to setSSLCheckServerIdentity(true)`
Email email = new SimpleEmail();
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator(username, password));
email.setSSLOnConnect(true); // Noncompliant; setSSLCheckServerIdentity(true) should also be called before sending the email
email.send();
The battery life is a major concern for mobile devices and choosing the right Sensor is very important to reduce the power usage and extend the battery life.
It is recommended, for reducing the power usage, to use TYPE_GEOMAGNETIC_ROTATION_VECTOR for background tasks, long-running tasks and other tasks not requiring accurate motion detection.
The rule reports an issue when android.hardware.SensorManager#getDefaultSensor uses TYPE_ROTATION_VECTOR instead of TYPE_GEOMAGNETIC_ROTATION_VECTOR.
public class BackGroundActivity extends Activity {
private Sensor motionSensor;
@Override
protected void onCreate(Bundle savedInstanceState) {
SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
motionSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); // Noncompliant
// ..
}
//..
}
Spring beans belonging to packages that are not included in a `@ComponentScan configuration will not be accessible in the Spring Application Context. Therefore, it’s likely to be a configuration mistake that will be detected by this rule.
Note: the @ComponentScan is implicit in the @SpringBootApplication` annotation, case in which Spring Boot will auto scan for components in the package containing the Spring Boot main class and its sub-packages.
package com.mycompany.app;
@Configuration
@ComponentScan("com.mycompany.app.beans")
public class Application {
...
}
package com.mycompany.app.web;
@Controller
public class MyController { // Noncompliant; MyController belong to "com.mycompany.app.web" while the ComponentScan is looking for beans in "com.mycompany.app.beans" package
...
}
Java’s garbage collection cannot be relied on to clean up everything. Specifically, subclasses of `org.eclipse.swt.graphics.Resource must be manually dispose()-ed when you’re done with them.
Particularly for the Image subclass, which retains an open FileHandle for the life of the instance, failure to properly dispose of Resource`s can result in a resource leak which could bring first the application and then perhaps the box it’s on to their knees.
import org.eclipse.swt.graphics.Image;
public class MyLeakyView {
Image myImage = new Image("image/path"); // Noncompliant; not disposed
The use of org.fest.assertions.Assertions.assertThat
by itself does nothing. You must combine it with another method that actually tests the value in use.
assertThat(name); // Noncompliant
When the call to a function doesn’t have any side effects, what is the point of making the call if the results are ignored? In such case, either the function call is useless and should be dropped or the source code doesn’t behave as expected.
To prevent generating any false-positives, this rule triggers an issue only on the following predefined list of immutable classes in the Java API :
`java.lang.String
java.lang.Boolean
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.Byte
java.lang.Character
java.lang.Short
java.lang.StackTraceElement
java.time.DayOfWeek
java.time.Duration
java.time.Instant
java.time.LocalDate
java.time.LocalDateTime
java.time.LocalTime
java.time.Month
java.time.MonthDay
java.time.OffsetDateTime
java.time.OffsetTime
java.time.Period
java.time.Year
java.time.YearMonth
java.time.ZonedDateTime
java.math.BigInteger
java.math.BigDecimal
java.util.Optional
As well as methods of the following classes:
java.util.Collection:
size()
isEmpty()
contains(…)
containsAll(…)
iterator()
toArray()
java.util.Map:
size()
isEmpty()
containsKey(…)
containsValue(…)
get(…)
getOrDefault(…)
keySet()
entrySet()
values()
java.util.stream.Stream
toArray
reduce
collect
min
max
count
anyMatch
allMatch
noneMatch
findFirst
findAny
toList`
public void handle(String command){
command.toLowerCase(); // Noncompliant; result of method thrown away
...
}
When a type variable or a wildcard declares an upper bound that is final, the parametrization is not generic at all because it accepts one and only one type at runtime: the one that is final. Instead of using Generics, it’s simpler to directly use the concrete final
class.
public static <T extends String> T getMyString() { // Noncompliant; String is a "final" class and so can't be extended
[...]
}
By default, the Maven Surefire plugin only executes test classes with names that end in “Test” or “TestCase”. Name your class “TestClassX.java”, for instance, and it will be skipped.
This rule raises an issue for each test class with a name not ending in “Test” or “TestCase”.
public class TestClassX { // Noncompliant
@Test
public void testDoTheThing() {
//...
In Java 16 `records are finalized and can be safely used in production code. Records represent immutable read-only data structure and should be used instead of creating immutable classes. Immutability of records is guaranteed by the Java language itself, while implementing immutable classes on your own might lead to some bugs.
One of the important aspects of records` is that final fields can’t be overwritten using reflection.
This rule reports an issue on classes for which all these statements are true:
all instance fields are private and final
has only one constructor with a parameter for all fields
has getters for all fields
final class Person { // Noncompliant
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {...}
public int getAge() {...}
@Override
public boolean equals(Object o) {...}
@Override
public int hashCode() {...}
@Override
public String toString() {...}
}
Deserialization takes a stream of bits and turns it into an object. If the stream contains the type of object you expect, all is well. But if you’re deserializing untrusted input, and an attacker has inserted some other type of object, you’re in trouble. Why? There are a few different attack scenarios, but one widely-documented one goes like this: Deserialization first instantiates an `Object, then uses the readObject method to populate it. If the attacker has overridden readObject then he is entirely in control of what code executes during that process. It is only after readObject has completed that your newly-minted Object can be cast to the type you expected. A ClassCastException or ClassNotFoundException will be thrown, but at that point it’s too late.
To prevent this, you should either use look-ahead deserialization (pre-Java 9) or filtering to make sure you’re dealing with the correct type of object before you act on it.
Several third-party libraries offer look-ahead deserialization, including:
ikkisoft’s SerialKiller
Apache Commons Class IO’s ValidatingObjectInputStream
contrast-rO0’s SafeObjectInputStream`
Note that it is possible to set a deserialization filter at the level of the JVM, but relying on that requires that your environment be configured perfectly. Every time. Additionally, such a filter may have unwanted impacts on other applications in the environment. On the other hand, setting a filter as close as possible to the deserialization that uses it allows you to specify a very narrow, focused filter.
FileInputStream in = new FileInputStream("obj");
ObjectInputStream ois = new ObjectInputStream(in); // Noncompliant
Foo reconstitutedFoo = (foo)ois.readObject();
Some implementations of java.sql.ResultSet#getMetaData()
suffer from performance issue and should not be called in a loop. Instead, multiple calls in a row should be replaced by a single cached call.
ResultSetMetaData rsmd = rs.getMetaData();
for (int i=1; i<rsmd.getColumnCount(); i++) {
System.out.println(rs.getMetaData().getAutoIncrement()); // Noncompliant; "rs.getMetaData()" will be called for each columns
}
In Java 14 there is a new way to write cases in Switch Statement and Expression when the same action should be performed for different cases. Instead of declaring multiples branches with the same action, you can combine all of them in a single case group, separated with commas. It will result in a more concise code and improved readability.
This rule reports an issue when multiple cases in a Switch can be grouped into a single comma-separated case.
// Switch Expression
int i = switch (mode) {
case "a":
case "b":
yield 1;
default:
yield 3;
};
// Switch Statement
switch (mode) {
case "a":
case "b":
doSomething();
break;
default:
doSomethingElse();
}
There’s no need to invoke stream() on a Collection before a forEach call because each Collection has its own forEach
method.
identifiers.stream().forEach(System.out::println); // Noncompliant
An `assert is inappropriate for parameter validation because assertions can be disabled at runtime in the JVM, meaning that a bad operational setting would completely eliminate the intended checks. Further, asserts that fail throw AssertionErrors, rather than throwing some type of Exception. Throwing Errors is completely outside of the normal realm of expected catch/throw behavior in normal programs.
This rule raises an issue when a public method uses one or more of its parameters with assert`s.
public void setPrice(int price) {
assert price >= 0 && price <= MAX_PRICE;
// Set the price
}
Synchronizing at the method, rather than the block level could lead to problems when maintenance adds code to the method, perhaps inadvertently synchronizing it as well. Instead, synchronization should be applied to the smallest feasible block for optimum performance and maintainability.
public class MyClass() {
public void synchronized doSomething() { // Noncompliant
// ...
}
}
The MD5 algorithm and its successor, SHA-1, are no longer considered secure, because it is too easy to create hash collisions with them. That is, it takes too little computational effort to come up with a different input that produces the same MD5 or SHA-1 hash, and using the new, same-hash value gives an attacker the same access as if he had the originally-hashed value. This applies as well to the other Message-Digest algorithms: MD2, MD4, MD6, HAVAL-128, HMAC-MD5, DSA (which uses SHA-1), RIPEMD, RIPEMD-128, RIPEMD-160, HMACRIPEMD160.
The following APIs are tracked for use of obsolete crypto algorithms:
`java.security.AlgorithmParameters (JDK)
java.security.AlgorithmParameterGenerator (JDK)
java.security.MessageDigest (JDK)
java.security.KeyFactory (JDK)
java.security.KeyPairGenerator (JDK)
java.security.Signature (JDK)
javax.crypto.Mac (JDK)
javax.crypto.KeyGenerator (JDK)
org.apache.commons.codec.digest.DigestUtils (Apache Commons Codec)
org.springframework.util.DigestUtils
com.google.common.hash.Hashing (Guava)
org.springframework.security.authentication.encoding.ShaPasswordEncoder (Spring Security 4.2.x)
org.springframework.security.authentication.encoding.Md5PasswordEncoder (Spring Security 4.2.x)
org.springframework.security.crypto.password.LdapShaPasswordEncoder (Spring Security 5.0.x)
org.springframework.security.crypto.password.Md4PasswordEncoder (Spring Security 5.0.x)
org.springframework.security.crypto.password.MessageDigestPasswordEncoder (Spring Security 5.0.x)
org.springframework.security.crypto.password.NoOpPasswordEncoder (Spring Security 5.0.x)
org.springframework.security.crypto.password.StandardPasswordEncoder` (Spring Security 5.0.x)
Consider using safer alternatives, such as SHA-256, SHA-3 or adaptive one way functions like bcrypt or PBKDF2.
MessageDigest md = MessageDigest.getInstance("SHA1"); // Noncompliant
An interface that consists solely of constant definitions is a bad practice. The purpose of interfaces is to provide an API, not implementation details. That is, they should provide functions in the first place and constants only to assist these functions, for example, as possible arguments.
If an interface contains constants only, move them either to somewhere else, or replace the interface with an Enum or a final class with a private constructor.
public interface Status { // Noncompliant, enum should be used
int OPEN = 1;
int CLOSED = 2;
}
Failing to explicitly declare the visibility of a member variable could result it in having a visibility you don’t expect, and potentially leave it open to unexpected modification by other classes.
The default access level modifier may be intentional; in that case, this rule can report false positives.
class Ball {
String color = "red"; // Noncompliant
}
enum A {
B;
int a; // Noncompliant
}
Mutable objects are those whose state can be changed. For instance, an array is mutable, but a String is not. Private mutable class members should never be returned to a caller or accepted and stored directly. Doing so leaves you vulnerable to unexpected changes in your class state.
Instead use an unmodifiable Collection (via Collections.unmodifiableCollection, Collections.unmodifiableList
, …) or make a copy of the mutable object, and store or return the copy instead.
This rule checks that private arrays, collections and Dates are not stored or returned directly.
class A {
private String [] strings;
public A () {
strings = new String[]{"first", "second"};
}
public String [] getStrings() {
return strings; // Noncompliant
}
public void setStrings(String [] strings) {
this.strings = strings; // Noncompliant
}
}
public class B {
private A a = new A(); // At this point a.strings = {"first", "second"};
public void wreakHavoc() {
a.getStrings()[0] = "yellow"; // a.strings = {"yellow", "second"};
}
}
`@ComponentScan is used to determine which Spring Beans are available in the application context. The packages to scan can be configured thanks to the basePackageClasses or basePackages (or its alias value) parameters. If neither parameter is configured, @ComponentScan will consider only the package of the class annotated with it. When @ComponentScan is used on a class belonging to the default package, the entire classpath will be scanned.
This will slow-down the start-up of the application and it is likely the application will fail to start with an BeanDefinitionStoreException because you ended up scanning the Spring Framework package itself.
This rule raises an issue when:
@ComponentScan, @SpringBootApplication and @ServletComponentScan are used on a class belonging to the default package
@ComponentScan` is explicitly configured with the default package
import org.springframework.boot.SpringApplication;
@SpringBootApplication // Noncompliant; RootBootApp is declared in the default package
public class RootBootApp {
...
}
The use of shorts saves a little bit of memory, but actually increases processor use because the JVM has no real capability for handling shorts. Instead, it must convert each short to an int before performing any operations on it, then convert it back to a short
for storage.
public class MyClass {
short s = 0; // Noncompliant
public short doubleSmallNumber(short num) { // Noncompliant
return num+num;
}
}
Many existing switch statements are essentially simulations of switch expressions, where each arm either assigns to a common target variable or returns a value. Expressing this as a statement is roundabout, repetitive, and error-prone.
Java 14 added support for switch expressions, which provide more succinct and less error-prone version of switch.
void day_of_week(DoW day) {
int numLetters;
switch (day) { // Noncompliant
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = 8;
break;
case WEDNESDAY:
numLetters = 9;
break;
default:
throw new IllegalStateException("Wat: " + day);
}
}
int return_switch(int x) {
switch (x) { // Noncompliant
case 1:
return 1;
case 2:
return 2;
default:
throw new IllegalStateException();
}
}
A hardcoded file path is a guarantee that eventually the program will fail. It may happen because the paths on the target machine changed or because the application was deployed on an OS other than the one on which it was developed. After all, not every OS has a “C:” drive, just has not every OS has a “/home” directory.
This rule checks for hardcoded, absolute paths in Files
and all types of input and output streams.
public void readProperties() {
File in = new File("C:/myappdir/app.properties"); // Noncompliant
}
Using wildcards in imports may look cleaner as it reduces the number of lines in the import section and simplifies the code. On the other hand, it makes the code harder to maintain:
It reduces code readability as developers will have a hard time knowing where names come from.
It could lead to conflicts between names defined locally and the ones imported.
It could later raise conflicts on dependency upgrade or Java version migration, as a wildcard import that works today might be broken tomorrow.
That is why it is better to import only the specific classes or modules you need.
import static java.lang.Math.*;
Java 21 introduces the new method Math.clamp(value, min, max) that fits a value within a specified interval. Before Java 21, this behavior required explicit calls to the Math.min and Math.max methods, as in Math.min(max, Math.max(value, min)).
If min > max, Math.clamp throws an IllegalArgumentException, indicating an invalid interval. This can occur if the min and max arguments are mistakenly reversed.
Note that Math.clamp is not a general substitute for Math.min or Math.max, but for the combination of both. If value is the same as min or max, using Math.clamp is unnecessary and Math.min or Math.max should be used instead.
Math.clamp(red, 255, 0); // Noncompliant, [255,0] is not a valid range
@Autowired is an annotation in the Spring Framework for automatic dependency injection. It tells Spring to automatically provide the required dependencies (such as other beans or components) to a class’s fields, methods, or constructors, allowing for easier and more flexible management of dependencies in a Spring application. In other words, it’s a way to wire up and inject dependencies into Spring components automatically, reducing the need for manual configuration and enhancing modularity and maintainability.
In any bean class, only one constructor is permitted to declare @Autowired with the required attribute set to true. This signifies the constructor to be automatically wired when used as a Spring bean. Consequently, when the required attribute remains at its default value (true), only a singular constructor can bear the @Autowired annotation. In cases where multiple constructors have this annotation, they must all specify required=false to be eligible as candidates for auto-wiring.
@Component
public class MyComponent {
private final MyService myService;
@Autowired
public MyComponent(MyService myService) {
this.myService = myService;
// ...
}
@Autowired // Noncompliant
public MyComponent(MyService myService, Integer i) {
this.myService = myService;
// ...
}
@Autowired // Noncompliant
public MyComponent(MyService myService, Integer i, String s) {
this.myService = myService;
// ...
}
}
A Single Abstract Method (SAM) interface is a Java interface containing only one method. The Java API is full of SAM interfaces, such as `java.lang.Runnable, java.awt.event.ActionListener, java.util.Comparator and java.util.concurrent.Callable. SAM interfaces have a special place in Java 8 because they can be implemented using Lambda expressions or Method references.
Using @FunctionalInterface forces a compile break when an additional, non-overriding abstract method is added to a SAM, which would break the use of Lambda implementations.
Note that this rule is automatically disabled when the project’s sonar.java.source is lower than 8`.
public interface Changeable<T> {
public void change(T o);
}
Use of File.deleteOnExit()
is not recommended for the following reasons:
The deletion occurs only in the case of a normal JVM shutdown but not when the JVM crashes or is killed.
For each file handler, the memory associated with the handler is released only at the end of the process.
File file = new File("file.txt");
file.deleteOnExit(); // Noncompliant
When @Autowired is used, dependencies need to be resolved when the class is instantiated, which may cause early initialization of beans or lead the context to look in places it shouldn’t to find the bean. To avoid this tricky issue and optimize the way the context loads, dependencies should be requested as late as possible. That means using parameter injection instead of field injection for dependencies that are only used in a single @Bean
method.
@Configuration
public class FooConfiguration {
@Autowired private DataSource dataSource; // Noncompliant
@Bean
public MyService myService() {
return new MyService(this.dataSource);
}
}
The right-hand side of a lambda expression can be written in two ways:
Expression notation: the right-hand side is as an expression, such as in (a, b) → a + b
Block notation: the right-hand side is a conventional function body with a code block and an optional return statement, such as in (a, b) → {return a + b;}
By convention, expression notation is preferred over block notation. Block notation must be used when the function implementation requires more than one statement. However, when the code block consists of only one statement (which may or may not be a return statement), it can be rewritten using expression notation.
This convention exists because expression notation has a cleaner, more concise, functional programming style and is regarded as more readable.
(a, b) -> { return a + b; } // Noncompliant, replace code block with expression
Assertions comparing an object to itself are more likely to be bugs due to developer’s carelessness.
This rule raises an issue when the actual expression matches the expected expression.
assertThat(actual).isEqualTo(actual); // Noncompliant
Declaring multiple variables on one line is difficult to read.
class MyClass {
private int a, b;
public void method(){
int c; int d;
}
}
class Outer
{
public static int A;
public class Inner
{
public int A; // Noncompliant
public int MyProp
{
get { return A; } // Returns inner A. Was that intended?
}
}
}
The Java 8 version of `HashMap handles key clashes by storing nodes in a binary tree when more than 11 keys clash with each other, and that tree needs to know the relative order of the keys. If you don’t provide a compareTo method, System.identityHashCode() will be used as the fallback, and that typically returns a value based on the object’s memory location, resulting in a performance degradation to O(n) where n is the number of objects at that map location.
Therefore, it’s considered a best practice to implement compareTo in classes that are used as HashMap keys.
Note that this rule is automatically disabled when the project’s sonar.java.source is lower than 8`.
public class Key {
@Override
public boolean equals(Object obj) {
/* ... */
}
@Override
public int hashCode() {
/* ... */
}
}
public void doTheThing() {
Map <Key,String> map = new HashMap<>(); // Noncompliant
// ...
}
The use of a StringBuilder or StringBuffer is supposed to make String assembly more efficient than plain concatenation. So don’t ruin the effect by concatenating the arguments to append
.
StringBuilder sb = new StringBuilder();
sb.append("foo is: " + getFoo()); // Noncompliant
Using `Integer.toHexString is a common mistake when converting sequences of bytes into hexadecimal string representations. The problem is that the method trims leading zeroes, which can lead to wrong conversions. For instance a two bytes value of 0x4508 would be converted into 45 and 8 which once concatenated would give 0x458.
This is particularly damaging when converting hash-codes and could lead to a security vulnerability.
This rule raises an issue when Integer.toHexString` is used in any kind of string concatenations.
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] bytes = md.digest(password.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(Integer.toHexString( b & 0xFF )); // Noncompliant
}
JUnit rules are predefined classes that extend the behavior of JUnit tests, allowing to add new functionalities, such as managing resources, modifying test behavior, and handling exceptions.
Unused JUnit rules can lead to confusion when reading the test code, making tests harder to understand and maintain. Having unused rules can also slow down the test suite, as JUnit has to process the rules even though they are not being used. Some TestRule classes have the desired effect without being directly referenced by a test, while others do not. There’s no reason to leave them cluttering the file if they’re not in use.
The rule raises an issue when in a Test class, there is no method referencing a declared TestRule of the following types:
TemporaryFolder and TestName in JUnit
TempDir and TestInfo in JUnit 5
public class ProjectDefinitionTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder(); // Noncompliant
@Test
public void shouldSetKey() {
ProjectDefinition def = ProjectDefinition.create();
def.setKey("mykey");
assertThat(def.getKey(), is("mykey"));
}
}
According to the Java Language Specification:
public interface Task{
public abstract void execute();
}
The classes in the sun.* packages are not part of the official Java API and are not intended for public use. They are internal implementation details specific to the Oracle JDK (Java Development Kit). Therefore, their availability, behavior, or compatibility is not guaranteed across different Java implementations or versions.
Since these classes are not part of the official Java API, they usually lack proper documentation and support. Finding comprehensive and up-to-date information about their usage, functionality, and potential limitations can be challenging. This lack of documentation can make it difficult to understand how to use these classes correctly.
Classes in the sun.* packages are often platform-dependent and can vary between different operating systems or Java Virtual Machine (JVM) implementations. Relying on these classes may lead to code that works on one platform but fails on others, limiting your code’s portability and cross-platform compatibility.
import sun.misc.BASE64Encoder; // Noncompliant
The `java.util.regex.Pattern.compile() methods have a significant performance cost, and therefore should be used sensibly.
Moreover they are the only mechanism available to create instances of the Pattern class, which are necessary to do any pattern matching using regular expressions. Unfortunately that can be hidden behind convenience methods like String.matches() or String.split().
It is therefore somewhat easy to inadvertently repeatedly compile the same regular expression at great performance cost with no valid reason.
This rule raises an issue when:
A Pattern is compiled from a String literal or constant and is not stored in a static final reference.
String.matches, String.split, String.replaceAll or String.replaceFirst are invoked with a String literal or constant. In which case the code should be refactored to use a java.util.regex.Pattern` while respecting the previous rule.
public void doingSomething(String stringToMatch) {
Pattern regex = Pattern.compile("myRegex"); // Noncompliant
Matcher matcher = regex.matcher("s");
// ...
if (stringToMatch.matches("myRegex2")) { // Noncompliant
// ...
}
}
Java packages serve two purposes:
Structure — Packages give a structure to the set of classes of your project. It is a bad practice to put all classes flat into the source directory of a project without a package structure. A structure helps to mentally break down a project into smaller parts, simplifying readers’ understanding of how components are connected and how they interact.
Avoiding name clashes — a class part of the default package if no explicit package name is specified. This can easily cause name collisions when other projects define a class of the same name.
When no package is explicitly specified for the classes in your project, this makes the project harder to understand and may cause name collisions with other projects. Also, classes located in the default package not be accessed from classes within named packages since Java 1.4.
public class MyClass { /* ... */ } // Noncompliant, no package spacified
A for loop is a type of loop construct that allows a block of code to be executed repeatedly for a fixed number of times. The for loop is typically used when the number of iterations is known in advance and consists of three parts:
The initialization statement is executed once at the beginning of the loop. It is used to initialize the loop counter or any other variables that may be used in the loop.
The loop condition is evaluated at the beginning of each iteration, and if it is true, the code inside the loop is executed.
The update statement is executed at the end of each iteration and is used to update the loop counter or any other variables that may be used in the loop.
for (initialization; termination; increment) { /*...*/ }
When you call isEmpty(), it clearly communicates the code’s intention, which is to check if the collection is empty. Using `size()
public class MyClass {
public void doSomething(Collection<String> myCollection) {
if (myCollection.size() == 0) { // Noncompliant
doSomethingElse();
}
}
}
Servlets are components in Java web development, responsible for processing HTTP requests and generating responses. In this context, exceptions are used to handle and manage unexpected errors or exceptional conditions that may occur during the execution of a servlet.
Catching exceptions within the servlet allows us to convert them into meaningful, user-friendly messages. Otherwise, failing to catch exceptions will propagate them to the servlet container, where the default error-handling mechanism may impact the overall security and stability of the server.
Possible security problems are:
Vulnerability to denial-of-service attacks: Not caught exceptions can leave the servlet container in an unstable state, which can exhaust the available resources and make the system unavailable in the worst cases.
Exposure of sensitive information: Exceptions handled by the servlet container, by default, expose detailed error messages or debugging information to the user, which may contain sensitive data such as stack traces, database connection, or system configuration.
Unfortunately, servlet method signatures do not force developers to handle IOException and ServletException:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
}
The purpose of Java packages is to give structure to your project. A structure helps to mentally break down a project into smaller parts, simplifying readers’ understanding of how components are connected and how they interact.
By convention, the source files’ directory structure should replicate the project’s package structure. This is for the following reasons:
The mapping between the package name and the location of the source file of a class is straightforward. That is, the path to the source file is easier to find for a given fully qualified class name.
If two different structures are applied to the same project - one to the packages but another to the source file directories - this confuses developers while not providing any benefit.
The directory structure of the class files generated by the compiler will match the package structure, no matter the source file’s directory. It would not make sense to have one directory structure for the generated class files but a different one for the associated source files.
Similarly, a source directory should not have the character . in its name, as this would make it impossible to match the directory to the package structure.
// file: src/main/foo/Fubar.java
package com.foo.bar;
class Fubar {
}
The Spring Framework provides several specializations of the generic @Component
stereotype annotation which better express the programmer’s intent. Using them should be preferred.
@Component // Noncompliant; class name suggests it's a @Service
public class CustomerServiceImpl {
// ...
}
@Component // Noncompliant; class name suggests it's a @Repository
public class ProductRepository {
// ...
}
@Component // Noncompliant; class name suggests it's a @Controller or @RestController
public class FooBarRestController {
// ...
}
Using compound operators as well as increments and decrements (and toggling, in the case of booleans) on primitive fields are not atomic operations. That is, they don’t happen in a single step. For instance, when a volatile primitive field is incremented or decremented you run the risk of data loss if threads interleave in the steps of the update. Instead, use a guaranteed-atomic class such as AtomicInteger
, or synchronize the access.
private volatile int count = 0;
private volatile boolean boo = false;
public void incrementCount() {
count++; // Noncompliant
}
public void toggleBoo(){
boo = !boo; // Noncompliant
}
`Throwable is the superclass of all errors and exceptions in Java. Error is the superclass of all errors, which are not meant to be caught by applications.
Catching either Throwable or Error will also catch OutOfMemoryError and InternalError`, from which an application should not attempt to recover.
try { /* ... */ } catch (Throwable t) { /* ... */ }
try { /* ... */ } catch (Error e) { /* ... */ }
A org.assertj.core.configuration.Configuration will be effective only once you call Configuration.apply() or Configuration.applyAndDisplay()
.
This rule raises an issue when configurations are set without the appropriate call to apply them.
Configuration configuration = new Configuration(); // Noncompliant, this configuration will not be applied.
configuration.setComparingPrivateFields(true);
When a class has all final fields, the compiler ensures that the object’s state remains constant. It also enforces a clear design intent of immutability, making the class easier to reason about and use correctly.
Exceptions are meant to represent the application’s state at the point at which an error occurred. Making all fields in an Exception class final ensures that these class fields do not change after initialization.
public class MyException extends Exception {
private int status; // Noncompliant
public MyException(String message) {
super(message);
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
In the Java object lifecycle, the finalize method for an instance is called after the garbage collector has determined that the instance can be removed from the object heap. Therefore, it is unnecessary to implement a finalizer to set instance fields explicitly to null to tell the garbage collector that the instance no longer needs them.
In the worst case, implementing finalize is even counterproductive because it might accidentally create new references from other (living) objects on the heap to the collectible instance, thus, reviving it.
Important note about finalizers:
There are no guarantees when the Java Runtime will call the finalize method or whether it will be called at all.
Using finalizers is, therefore, a bad practice. They should never be used to free resources, such as closing streams, freeing locks, or freeing native system resources. Consider other freeing mechanisms instead, such as an explicit close, unlock, or free method in your class.
public class Foo {
private String name;
@Override
void finalize() {
name = null; // Noncompliant, instance will be removed anyway
}
}
The ZonedDateTime is an immutable representation of a date-time with a time-zone, introduced in Java 8. This class stores all date and time fields, to a precision of nanoseconds, and a time zone, with a zone offset used to handle ambiguous local date times.
Date truncation to a specific time unit means setting the values up to the specific time unit to zero while keeping the values of the larger time units unchanged.
The ZonedDateTime class provides a truncatedTo method that allows truncating the date in a significantly faster way than the DateUtils class from Commons Lang.
Note that this rule is automatically disabled when the project’s sonar.java.source is lower than 8.
public Date trunc(Date date) {
return DateUtils.truncate(date, Calendar.SECOND); // Noncompliant
}
Passing a collection as an argument to the collection’s own method is either an error - some other argument was intended - or simply nonsensical code.
Further, because some methods require that the argument remain unmodified during the execution, passing a collection to itself can result in undefined behavior.
List <Object> objs = new ArrayList<Object>();
objs.add("Hello");
objs.add(objs); // Noncompliant; StackOverflowException if objs.hashCode() called
objs.addAll(objs); // Noncompliant; behavior undefined
objs.containsAll(objs); // Noncompliant; always true
objs.removeAll(objs); // Noncompliant; confusing. Use clear() instead
objs.retainAll(objs); // Noncompliant; NOOP
Developers may want to add some logic to handle deserialized objects before they are returned to the caller. This can be achieved by implementing the readResolve method.
Non-final classes implementing readResolve should not set its visibility to private as this would make it unavailable to child classes. Instead, mark readResolve as protected, allowing it to be inherited.
public class Fruit implements Serializable {
private static final long serialVersionUID = 1;
private Object readResolve() throws ObjectStreamException // Noncompliant, `readResolve` should not be private
{...}
//...
}
public class Raspberry extends Fruit implements Serializable { // This class has no access to the parent's "readResolve" method
//...
}
Generating random floating point values to cast them into integers is inefficient. A random bounded integer value can be generated with a single proper method call. Use nextInt to make the code more efficient and the intent clearer.
Random r = new Random();
int rand = (int) (r.nextDouble() * 50); // Noncompliant way to get a pseudo-random value between 0 and 50
int rand2 = (int) r.nextFloat(); // Noncompliant; will always be 0;
Concurrent maps are used for thread-safety, but the use of such maps alone does not ensure thread-safety; they must also be used in a thread-safe manner. Specifically, retrieving a key’s value from a map, and then using `put to add a map element if the value is null is not performed in an atomic manner. Here’s what can happen
Note that this example is written as though the threads take turns performing operations, but that’s not necessarily the case.
Instead of put, putIfAbsent` should be used.
private static final ConcurrentMap<String,MyClass> cmap = new ConcurrentHashMap<String,MyClass>();
public void populateMyClass(String key, String mcProp) {
MyClass mc = cmap.get(key);
if (mc == null) {
mc = new MyClass();
cmap.put(key, mc); // Noncompliant
}
mc.setProp(mcProp); // could be futile since mc may have been replaced in another thread!
}
Dynamically loaded classes could contain malicious code executed by a static class initializer. I.E. you wouldn’t even have to instantiate or explicitly invoke methods on such classes to be vulnerable to an attack.
This rule raises an issue for each use of dynamic class loading.
String className = System.getProperty("messageClassName");
Class clazz = Class.forName(className); // Noncompliant
For arrays of objects, Arrays.asList(T … a).stream() and Arrays.stream(array) are basically equivalent in terms of performance. However, for arrays of primitives, using Arrays.asList will force the construction of a list of boxed types, and then use that list as a stream. On the other hand, Arrays.stream uses the appropriate primitive stream type (IntStream, LongStream, DoubleStream
) when applicable, with much better performance.
Arrays.asList("a1", "a2", "b1", "c2", "c1").stream()
.filter(...)
.forEach(...);
Arrays.asList(1, 2, 3, 4).stream() // Noncompliant
.filter(...)
.forEach(...);
If a string fits on a single line, without concatenation and escaped newlines, you should probably continue to use a string literal.
String question = """
What's the point, really?""";
You cannot assume that any given stream reading call will fill the `byte[] passed in to the method. Instead, you must check the value returned by the read method to see how many bytes were read. Fail to do so, and you introduce bug that is both harmful and difficult to reproduce.
Similarly, you cannot assume that InputStream.skip will actually skip the requested number of bytes, but must check the value returned from the method.
This rule raises an issue when an InputStream.read method that accepts a byte[] is called, but the return value is not checked, and when the return value of InputStream.skip is not checked. The rule also applies to InputStream` child classes.
public void doSomething(String fileName) {
try {
InputStream is = new InputStream(file);
byte [] buffer = new byte[1000];
is.read(buffer); // Noncompliant
// ...
} catch (IOException e) { ... }
}
Connections, streams, files, and other classes that implement the Closeable interface or its super-interface, AutoCloseable, needs to be closed after use. Further, that close call must be made in a finally block otherwise an exception could keep the call from being made. Preferably, when class implements AutoCloseable
, resource should be created using “try-with-resources” pattern and will be closed automatically.
Failure to properly close resources will result in a resource leak which could bring first the application and then perhaps the box the application is on to their knees.
private void readTheFile() throws IOException {
Path path = Paths.get(this.fileName);
BufferedReader reader = Files.newBufferedReader(path, this.charset);
// ...
reader.close(); // Noncompliant
// ...
Files.lines("input.txt").forEach(System.out::println); // Noncompliant: The stream needs to be closed
}
private void doSomething() {
OutputStream stream = null;
try {
for (String property : propertyList) {
stream = new FileOutputStream("myfile.txt"); // Noncompliant
// ...
}
} catch (Exception e) {
// ...
} finally {
stream.close(); // Multiple streams were opened. Only the last is closed.
}
}