PMD Version: 7.24.0
Category: CloseResource
Severity: Warning (Error Prone)
Summary
PMD's CloseResource rule reports local AutoCloseable variables that may leave scope without being closed. Its verdict changes depending on whether a closeable local is initialized with the bare null literal null or with a cast null (T) null:
Connection c = null; → no finding.
Connection c = (Connection) null; → false positive on both the connection and statement declarations, reported as 'connection' is reassigned, but the original instance is not closed, even though the "original instance" is the null reference and the variable is later closed in finally.
A cast on the null literal is a no-op per JLS §5.5: both forms initialize the local with the null reference of static type T. The two are runtime-equivalent and should receive the same verdict.
Reproducer
before — bare null (no finding)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class CastNullBefore {
public static void method() {
Connection connection = null;
Statement statement = null;
try {
connection = DriverManager.getConnection("blah");
statement = connection.createStatement();
} catch (SQLException e) {
System.err.println("Error: " + e);
} finally {
if (statement != null) try { statement.close(); } catch (SQLException e) {}
if (connection != null) try { connection.close(); } catch (SQLException e) {}
}
}
}
after — (T) null (false positive)
public class CastNullAfter {
public static void method() {
Connection connection = (Connection) null; // FALSE POSITIVE
Statement statement = (Statement) null;
try {
connection = DriverManager.getConnection("blah");
statement = connection.createStatement();
} catch (SQLException e) {
System.err.println("Error: " + e);
} finally {
if (statement != null) try { statement.close(); } catch (SQLException e) {}
if (connection != null) try { connection.close(); } catch (SQLException e) {}
}
}
}
Expected behavior
CloseResource should produce the same finding set on BEFORE and AFTER, since Connection c = null; and Connection c = (Connection) null; differ only by a no-op cast on a null literal. Both reassign a real resource in try and close it in finally, so neither should be reported.
Actual behavior
Connection c = null; → 0 findings (correct).
Connection c = (Connection) null; → 2 findings: 'connection' is reassigned, but the original instance is not closed and the same for statement. PMD treats the (T) null initializer as a real resource instance that is then "lost" when the variable is reassigned inside try, even though the original value is the null reference (nothing to close) and the real resource is closed in finally.
The rule's verdict is sensitive to the syntactic shape of the initializer (null vs (T) null) rather than its value.
PMD Version: 7.24.0
Category: CloseResource
Severity: Warning (Error Prone)
Summary
PMD's
CloseResourcerule reports localAutoCloseablevariables that may leave scope without being closed. Its verdict changes depending on whether a closeable local is initialized with the bare null literalnullor with a cast null(T) null:Connection c = null;→ no finding.Connection c = (Connection) null;→ false positive on both theconnectionandstatementdeclarations, reported as'connection' is reassigned, but the original instance is not closed, even though the "original instance" is the null reference and the variable is later closed infinally.A cast on the
nullliteral is a no-op per JLS §5.5: both forms initialize the local with the null reference of static typeT. The two are runtime-equivalent and should receive the same verdict.Reproducer
before — bare
null(no finding)after —
(T) null(false positive)Expected behavior
CloseResourceshould produce the same finding set on BEFORE and AFTER, sinceConnection c = null;andConnection c = (Connection) null;differ only by a no-op cast on a null literal. Both reassign a real resource intryand close it infinally, so neither should be reported.Actual behavior
Connection c = null;→ 0 findings (correct).Connection c = (Connection) null;→ 2 findings:'connection' is reassigned, but the original instance is not closedand the same forstatement. PMD treats the(T) nullinitializer as a real resource instance that is then "lost" when the variable is reassigned insidetry, even though the original value is the null reference (nothing to close) and the real resource is closed infinally.The rule's verdict is sensitive to the syntactic shape of the initializer (
nullvs(T) null) rather than its value.