Skip to content

[java] CloseResource: False positive for closeable initialized with (T) null #6743

@Chordrain

Description

@Chordrain

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    a:false-positivePMD flags a piece of code that is not problematic

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions