This is a common pitfall that I regularly see colleagues and myself run into when refactoring legacy code using java.sql.Statement to java.sql.PreparedStatement.
When dealing with Statement, you pass the SQL that you want to run directly to the corresponding execute(String), executeQuery(String), executeUpdate(String), executeLargeUpdate(String), addBatch(String) method (or their respective overloads).
But when using a PreparedStatement, you already pass that SQL to the Connection.prepareStatement(String) call and then only use the parameterless execute(), executeQuery(), etc. methods. But since PreparedStatement extends Statement, you still inherit the method overloads with the String parameter - and calling those on a PreparedStatement will cause an exception at runtime. This is an easy thing to overlook during refactoring.
Before refactoring:
try (Statement stmt = connection.createStatement()) {
ResultSet rs = stmt.executeQuery(sql);
[...]
}
Bad code:
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
ResultSet rs = stmt.executeQuery(sql); // NONCOMPLIANT - this overload will cause an exception
[...]
}
Good code:
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
ResultSet rs = stmt.executeQuery(); // COMPLIANT
[...]
}
External references:
Most of those methods in Statement will have a note in their Javadoc that explicitly states:
**Note:**This method cannot be called on a {@code PreparedStatement} or {@code CallableStatement}.
(E.g. Statement (Java Platform SE 8 ) )
So I think it would be a valid for a Sonar rule to point out such usage as a bug when we can discern that we are dealing with one of those specific subclasses. The rule should cover all method calls inherited from Statement that are not supported on a PreparedStatement or CallableStatement.
Type: Bug
Tags: Pitfall