0

I've got the following code:

try (Connection connection = getConnection();

    PreparedStatement preparedStatement = connection.prepareStatement(someSql)) {//stuff}

How do I check that connection is not null here?

Also, I got a method which returns a PreparedStatement like this:

private PreparedStatement getPreparedStatement(Connection connection)

  throws SQLException {

PreparedStatement preparedStatement = connection.prepareStatement(SQL);

preparedStatement.setString(1, "someString");

return preparedStatement;

}

this gets called within a method that uses the following try with resources:

try (Connection connection = getConnection();
    PreparedStatement preparedStatement =
        getPreparedStatement(connection)) {//stuff}

Now I would assume the prepared statement will be autoclosed, because it gets initiated in the try with resources. But SonarCloud says that i should use try with resources in the getPreparedStatement-method or close that PreparedStatement in a finally block. Is this a wrong finding by SonarCloud or is there a better way to do it?

  • So is this two separate questions? As in the first block of code is a different question from the rest? – Nexevis Feb 28 '20 at 14:39
  • Definitely a wrong finding by SonarCloud. And it’s far from the first. Code analysis tools are hard to write. – VGR Feb 28 '20 at 15:57

2 Answers2

1

getConnection should throw an exception instead of returning null. Returning null is not nice. SonarCloud seems to be wanting you to put a try-with-resource opening ingetPreparedStatement(must include thesetString`) and closing in the calling method, which of course you can't do as such.

The best approach is the Execute Around idiom. Instead of getPreparedStatement returning a PreparedStatement pass in a lambda (typically) to be executed. The resource can then be closed in a try-with-resource statement cleanly.

/*** NICE ***/
// Function instead of Consumer would allow the method to return a value.
private void prepared(
    Connection connection, Consumer<PreparedStatement> op
) throws SQLException {
    // Might want to add getConnection in here too, perhaps.
    try (
        PreparedStatement statement =
             connection.prepareStatement(SQL)
    ) { 
        statement.setString(1, "someString");
        op.accept(statement);
    }
}

Used as:

    try (Connection connection = getConnection()) {
        prepared(connection, statement -> {
            // blah, blah, blah
        });
    }

The hacky alternative is to include a try statement within getPreparedStatement that only closed in error conditions.

/*** HACKY ***/
private PreparedStatement prepared(
    Connection connection
) throws SQLException {
    boolean success = false;
    PreparedStatement statement =
        connection.prepareStatement(SQL);
    try { 
        statement.setString(1, "someString");
        success = true;
        return preparedStatement;
    } finally {
        if (!success) {
            statement.close();
        }
    }
}

If you desperately want getConnection to return null (don't) and use a single two-entry try-with-resource, then the conditional operator works.

try (
    Connection connection = getConnection();
    PreparedStatement statement =
        connection==null ? null : connection.prepareStatement(SQL)
) {
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
0

Easiest approch and IMO the most readable one would be to use 2 try-with-resources blocks. Even sonar has an built-in exception from disallowing nested try-catch-blocks for exactly this use case...

try (Connection conn = getConnection()) {
    if (conn != null) {
        try (PreparedStatement stmt = ...) {
            // do stuff
        }
    }
}

If do stuff is lengthy, it could and should be refactored into a separate method (possibly including the inner try-with-resources).

Nicktar
  • 5,548
  • 1
  • 28
  • 43
  • this is what I came up with too, but is it really good practice? – uhmdunnolol Feb 28 '20 at 15:03
  • I've seen and used it in several projects and companies. I've seen and had it in many code reviews without complaints and if even sonar has a special rule allowing it (it generally discourages nested try-catch-blocks), I think it's at least a good enough aproach for me until I see a better one. One improvement would be to prevent getConnection from returning null. – Nicktar Feb 28 '20 at 15:07
  • `getConnection` should *never* return null. – VGR Feb 28 '20 at 15:56