Why is this an issue?
A reference to null
should never be dereferenced/accessed. Doing so will cause a NullPointerException
to be thrown. At
best, such an exception will cause abrupt program termination. At worst, it could expose debugging information that would be useful to an attacker, or
it could allow an attacker to bypass security measures.
Note that when they are present, this rule takes advantage of nullability annotations, like @CheckForNull
or @Nonnull
,
defined in JSR-305 to understand which values can be null or not. @Nonnull
will be
ignored if used on the parameter of the equals
method, which by contract should always work with null.
How to fix it
Code examples
Noncompliant code example
The variable myObject
is equal to null
, meaning it has no value:
public void method() {
Object myObject = null;
System.out.println(myObject.toString()); // Noncompliant: myObject is null
}
The parameter input
might be null
as suggested by the if
condition:
public void method(Object input)
{
if (input == null)
{
// ...
}
System.out.println(input.toString()); // Noncompliant
}
The unboxing triggered in the return statement will throw a NullPointerException
:
public boolean method() {
Boolean boxed = null;
return boxed; // Noncompliant
}
Both conn
and stmt
might be null
in case an exception was thrown in the try{} block:
Connection conn = null;
Statement stmt = null;
try {
conn = DriverManager.getConnection(DB_URL,USER,PASS);
stmt = conn.createStatement();
// ...
} catch(Exception e) {
e.printStackTrace();
} finally {
stmt.close(); // Noncompliant
conn.close(); // Noncompliant
}
As getName()
is annotated with @CheckForNull
, there is a risk of NullPointerException
here:
@CheckForNull
String getName() {...}
public boolean isNameEmpty() {
return getName().length() == 0; // Noncompliant
}
As merge(…)
parameter is annotated with @Nonnull
, passing an identified potential null value (thanks to @CheckForNull)
is not safe:
private void merge(@Nonnull Color firstColor, @Nonnull Color secondColor) {...}
public void append(@CheckForNull Color color) {
merge(currentColor, color); // Noncompliant: color should be null-checked because merge(...) doesn't accept nullable parameters
}
Compliant solution
Ensuring the variable myObject
has a value resolves the issue:
public void method() {
Object myObject = new Object();
System.out.println(myObject.toString()); // Compliant: myObject is not null
}
Preventing the non-compliant code to be executed by returning early:
public void method(Object input)
{
if (input == null)
{
return;
}
System.out.println(input.toString()); // Compliant: if 'input' is null, this is unreachable
}
Ensuring that no unboxing of null
value can happen resolves the issue
public boolean method() {
Boolean boxed = true;
return boxed; // Compliant
}
Ensuring that both conn
and stmt
are not null
resolves the issue:
Connection conn = null;
Statement stmt = null;
try {
conn = DriverManager.getConnection(DB_URL,USER,PASS);
stmt = conn.createStatement();
// ...
} catch(Exception e) {
e.printStackTrace();
} finally {
if (stmt != null) {
stmt.close(); // Compliant
}
if (conn != null) {
conn.close(); // Compliant
}
}
Checking the returned value of getName()
resolves the issue:
@CheckForNull
String getName() {...}
public boolean isNameEmpty() {
String name = getName();
if (name != null) {
return name.length() == 0; // Compliant
} else {
// ...
}
}
Ensuring that the provided color
is not null
resolves the issue:
private void merge(@Nonnull Color firstColor, @Nonnull Color secondColor) {...}
public void append(@CheckForNull Color color) {
if (color != null) {
merge(currentColor, color); // Compliant
}
}
Resources