Possible Findbug false positive for "obl_unsatisfied_obligation" - java

I have a code section like bellow:
try (UnitOfWork unitOfWork = datasource.getConnection()) {
ResultSet resultset = untiOfWork.getStatement().getResultSet();
unitOfWork.queueToClose(resultSet);
...
}
The UnitOfWork is an AutoClosable. So inside of the UnitOfWork close() method is like this.
#Overide
public void close() {
for (AutoClosable closable : queueToClose) {
closable.close();
}
connection.close();
}
Now the FindBug is complaining about the ResultSet is not being closed. Is this a false positive? Is this a bad pattern?

In addition to the excellent answer that 'Alexey Romanov' posted there is a potential leak in your implementation of UnitOfWork.close where if any of those close calls throws an exception your connection is not closed.
#Override
public void close() throws Exception {
Exception first = null;
try (AutoCloseable requiredForJdk8 = this.connection) {
for (AutoCloseable closable : this.queueToClose) {
try {
closable.close();
} catch (Exception e) {
if (first == null) {
first = e;
} else {
if (first != e) {
first.addSuppressed(e);
}
}
}
}
if (first != null){
throw first;
}
}
}

It is a false positive in the sense that ResultSet will be closed, but there is no way for FindBugs to know this.
It is also a bad pattern: what happens if you forget to call queueToClose after getting a ResultSet? Does UnitOfWork.getStatement() add the statement to queueToClose before returning it?
Better would be
try (UnitOfWork unitOfWork = datasource.getConnection();
Statement statement = unitOfWork.getStatement();
ResultSet resultset = statement.getResultSet()) {
...
}

Related

Invoke method in another class's try catch block

I have some methods that follow this pattern
try(Connection connection = MySqlConnection.getConnection()){
PreparedStatement statement = connection.prepareStatement(
"Insert into db values (NULL ,?,?,?,?,?, NULL , ?)",
Statement.RETURN_GENERATED_KEYS);
...
statement.executeUpdate();
...
}
catch(SQLException e) {
throw new RuntimeException(e);
}
I was told to extract try-catch with connection to class MySqlConnection and create a new method that would execute all logic and encapsulate creating connection. So, I don't quite get this approach and have no idea, how to resolve it without writing some ugly templates or strategies. Would it be better to just leave it as it is, or can it be implemented in an easy way?
Create a ConnectionHelper that will deal with exceptions. This is a little bit tricky, you have to define your own functional interface because standard Consumer does not work with checked SQLExceptions:
public class ConnectionHelper {
#FunctionalInterface
public interface ConnectionConsumer {
void accept(Connection connection) throws SQLException;
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Then use it like this:
public void doSomeUpdate() {
ConnectionHelper.doWithConnection(connection -> {
PreparedStatement statement = connection.prepareStatement(
"Insert into db values (NULL ,?,?,?,?,?, NULL , ?)",
Statement.RETURN_GENERATED_KEYS);
statement.executeUpdate();
});
}
This works well as long as you don't have to return anything from your database, which is rarely the case. So we need to extend the helper with another functional interface, ConnectionFunction, to be used when an object needs to be returned:
public class ConnectionHelper {
#FunctionalInterface
public interface ConnectionConsumer {
void accept(Connection connection) throws SQLException;
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
...
}
#FunctionalInterface
public interface ConnectionFunction<T> {
T apply(Connection connection) throws SQLException;
}
public static <T> T doWithConnection(ConnectionFunction<T> connectionFunction) {
try (Connection connection = MySqlConnection.getConnection()) {
return connectionFunction.apply(connection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
Then use it like this:
public boolean doSomeQuery() {
return ConnectionHelper.doWithConnection(connection -> {
PreparedStatement statement = connection.prepareStatement("SELECT * FROM table");
return statement.execute();
});
}
Updates
2 solutions to work with SQLIntegrityConstraintViolationException:
Own, runtime exception:
As this is a runtime exception, you just add try-catch where needed.
public static class MySQLIntegrityConstraintViolationException extends RuntimeException {
public MySQLIntegrityConstraintViolationException(Throwable cause) {
super(cause);
}
}
public static void doWithConnection(ConnectionConsumer connectionConsumer) {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLIntegrityConstraintViolationException e) {
throw new MySQLIntegrityConstraintViolationException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
insertWithConnection:
A specialized version of doWithConnection(). Again, use it only where/when applicable.
public static void insertWithConnection(ConnectionConsumer connectionConsumer) throws SQLIntegrityConstraintViolationException {
try (Connection connection = MySqlConnection.getConnection()) {
connectionConsumer.accept(connection);
} catch (SQLIntegrityConstraintViolationException e) {
throw e;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
Use java functional interface to separate exception handling from business logic, like this:
public class ExceptionHandler() {
public R execute(Function<T,R> function, T argument) {
try {
return function.apply(argument)
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Now you can pass to the class above any function that will contain your logic and handling exception will be independent.
Furthermore, this way you can create many useful methods, and classes that work like a proxy, or which are needed for every operation, and hat will be independent of your business logic.
For example, in the same way, you can write:
your own transaction management,
logging input and output
check user and permissions
and any other interceptor

Java - Design Pattern for repeating sql tasks

I have different methods, which queries different data from a database, but the main structure of every method is the same. To reduce the code, I want to shrink that but I don't know how. I have tried interfaces but the return statement cannot called from an inner class. (It should be typesafe!)
Structure:
public <special type> getXYdata(some parameters) {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(... special query ...)
) {
// Handle ResultsSet and return object of a special type.
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
Idea:
private interface QHandler<T> {
String getQuery();
T handleResultSet(ResultSet set) throws SQLException;
}
And then:
private void executeQuery(QHandler handler) throws ContentManagerException {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(handler.getQuery())
) {
handler.handleResultSet(results);
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
But if I call this private method in one of my data mathods, I cannot return an object from the handleResultSet() methods, because the return statement will affect this interface method. Is there an option, to tell the execiteQuery() method which return type the handler has?
Attention: It has to be type safe, no casting if possible!
Your method should not use a raw QHandler type, and should be generic:
private <T> T executeQuery(QHandler<T> handler) throws ContentManagerException {
try (Connection connection = mDataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet results = statement.executeQuery(handler.getQuery())
) {
return handler.handleResultSet(results);
} catch (SQLTimeoutException e) {
throw new ContentManagerException("Query took to long or connection timed out", e);
} catch (SQLException e) {
throw new ContentManagerException("Query or parsing its results failed", e);
}
}
Note that you're trying to reinvent Spring's JdbcTemplate. You might consider using it instead of reinventing it.
Maybe you are open for alternative solutions. If you are using Java 8, you can do somehting like this:
Interface MyHandler {
<T> T handle(Connection c);
}
class MyHelperClass {
public <T> T withConnection(MyHandler handler) {
try {
Connection connection = mDataSource.getConnection();
return handler.handle(connection);
} catch (...) {
...
} finally {
...
}
}
}
Usage:
Result r = myHelperObject.withConnection(con -> {
ResultSet results = connection.createStatement().executeQuery(query)
return new Result(..)
});
This way you can use lambda expressions so you do not need to implement various new classes for your handler interface.

Is a pooled db-access using method-level connection in a static class/method safe?

have been a long-time reader here and now I`ve got a problem I canĀ“t really get my head around.
For ease of access and to save object creation overhead I have a static class realizing database accesses. The used JVM implementation is Tomcat and for connection pooling org.apache.commons.dbcp is used.
I've read a lot about thread-safety, heap and stack here and elsewhere but I can`t get to a definitive conclusion if multiple method calls on my static class won't interfere with each other. Most topics I've read deal with instance methods while I use static ones which might have implications I overlooked.
If I understood everything correctly, as the variables connection, statement, resultset are on the method level, each function call should have a unique reference on the stack to a unique object in the heap and it should not be possible that multiple method calls interfere with each other.
Am I right or do I stand corrected? Any help would be appreciated.
The (shortened) code is :
public class DBQuery{
private static String pathToDataSource = "";
private static javax.naming.Context cxt = null;
private static javax.sql.DataSource ds = null;
private static void getDataSource() throws Exception {
if(pathToDataSource.equals("")){ pathToDataSource = Config.getParam("PathToDataSource"); }
cxt = new javax.naming.InitialContext();
ds = (javax.sql.DataSource) cxt.lookup(pathToDataSource);
}
private static Connection connect() throws Exception {
if(ds==null){ getDataSource(); }
return ds.getConnection();
}
public static Vector doDBquery(String querystring) throws Exception {
Vector retVec = new Vector();
Connection connection = null;
Statement statement = null;
ResultSet resultset = null;
try {
connection = getConnection();
statement = connection.createStatement();
resultset = statement.executeQuery(querystring);
...
} catch(Exception e) {
...
} finally {
myFinallyBlock(resultset, statement, connection);
}
return retVec;
}
// more methods like doDBInsert() following, hence closure in separate myFinallyBlock
private static void myFinallyBlock(ResultSet resultset, Statement statement, Connection connection) {
try {
if (resultset != null) resultset.close();
} catch (SQLException e) { resultset = null; }
try {
if (statement != null) statement.close();
} catch (SQLException e) { statement = null; }
try {
if (connection != null) connection.close();
} catch (SQLException e) { connection = null; }
}
} //close class
Yeah, you are right inside method there is no concurrency problems , until you are using shared variables inside it, in other words "Stateless objects are always thread-safe."
Servlet is quite good example of it ;)
edited.
For making your code safe I recommend you to do follow:
private static Connection connect() throws Exception {
if (ds == null) {
synchronized (Connection.class) {
if (ds == null) {
getDataSource();
}
}
}
return ds.getConnection();
}

Where to close result set

I am getting result set is already closed where i am passing resultset into other method.where should i closed result set.
public void mainTest(){
ResultSet rs= pstmt.executeQuery(query);
List list = populateRS(rs);
if(rs!=null)rs.close();
}
public List populateRS(ResultSet rs){
//work with result set
if(rs!=null)rs.close();
}
You should probably use a try-finally block to close the ResultSet even if populateRS (or something else) throws an exception:
ResultSet rs;
try {
rs = pstmt.executeQuery(query);
List list = populateRS(rs);
} finally {
if (rs != null) {
rs.close();
}
}
Close in the same method you open in if at all possible. Consistently doing this makes it easy for code-reviewers and maintainers to easily triage resources into (obviously freed, obviously problematic, and needs more attention).
A few other notes:
Use try (...) or do the closing in finally so the resource is closed even when the code using it fails with an exception.
Use the #WillClose and #WillNotClose annotations as appropriate so that IDEs and tools like findbugs can point out problems.
public void mainTest(){
List<?> list;
try (ResultSet rs = pstmt.executeQuery(query)) {
list = populateRS(rs);
}
// work with list
}
public List<?> populateRS(#WillNotClose ResultSet rs){
//work with result set
}
or if you're stuck with older Java:
public void mainTest(){
List<?> list;
ResultSet rs = pstmt.executeQuery(query);
try {
list = populateRS(rs);
} finally {
if(rs!=null)rs.close();
}
// work with list
}
Use the new try-with-resources statement which would automatically close the ResultSet whether an exception occurs or not because it implements AutoCloseable.
The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement.
public void mainTest()
{
try (ResultSet rs = pstmt.executeQuery(query)) {
List list = populateRS(rs);
} catch (SQLException ex) {
}
}
public List populateRS(ResultSet rs){
// work with result set
}
It is good to close where you are opening .
It is good programming practise to close all resouces in finally block
public void mainTest()
{
ResultSet rs = null;
try{
rs= pstmt.executeQuery(query);
List list = populateRS(rs);
}finally{
try {
rs.close();
} catch (SQLException ex) {
}
}
}
public List populateRS(ResultSet rs){
//work with result set
}
according to java docs
Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
Close things near where you open them. In this case that would be in the mainTest method after you call populateRS. If a method doesn't open something, it shouldn't close it.
You should close the ResultSet in the mainTest method to segregate populateRS method's participation in the lifecycle of the ResultSet.
You should have a finally block in which you should close the ResultSet. This practice gives you a guarantee that the ResultSet is closed even if an exception is thrown.

Nullpointer Exception (Derby, JDBC)

Hy!!
My error code:
Exception in thread "main" java.lang.NullPointerException
at lesebank.Konto.getKontofromID(Konto.java:39)
at lesebank.Main.main(Main.java:18)
SQL EXCEPTIONJava Result: 1
BUILD SUCCESSFUL (total time: 1 second)
Method:
Konto konto = new Konto ();
Statement s = dbconn.getSt();
try
{ //in the next line the error occurs
s.execute("select id,inhaberin,ktostd,habenzinsen,notiz from Konto where id = " +id);
ResultSet set = s.getResultSet();
if (set.next())
{
konto.setId(set.getInt(1));
konto.setId_inhaberin(set.getInt(2));
konto.setKtostd(set.getDouble(3));
konto.setHabenzinsen(set.getDouble(4));
konto.setNotiz(set.getString(5));
return konto;
}
}
catch (SQLException ex)
{
System.out.print(ex.getMessage());
}
return null;
DBConn:
public class DBConnection {
private String url = "jdbc:derby://localhost:1527/Bank";
private Connection conn;
private Statement st;
public DBConnection() {
try
{
conn = DriverManager.getConnection(this.url, "test", "test");
st = conn.createStatement();
}
catch (SQLException ex)
{
System.out.print("SQL EXCEPTION");
}
}
public Statement getSt() {
return st;
}
Database:
Please help
This is Very Bad(tm):
public DBConnection() {
try
{
conn = DriverManager.getConnection(this.url, "test", "test");
st = conn.createStatement();
}
catch (SQLException ex)
{
System.out.print("SQL EXCEPTION");
}
}
Do not catch and ignore exceptions like this. There are there for a very good reason. In this case, if your constructor fails due to an exception, the whole DbConnection object is rendered useless, since the st field will be null. Yet because the code that instantiated DbConnection has no idea this has happened, you go on to use it, and end up with the null-pointer exception.
If DbConnection's constructor triggers an exception, you need to throw that exception out of the constructor, forcing your code to deal with the exception:
public class DBConnection {
private static final String URL = "jdbc:derby://localhost:1527/Bank";
private final Connection conn;
private final Statement st;
public DBConnection() throws SQLException {
conn = DriverManager.getConnection(URL, "test", "test");
st = conn.createStatement();
}
public Statement getSt() {
return st;
}
}
Note also the final fields. This gives you a compile-time guarantee that something will be assigned to those fields.
Please check that dbconn.getSt() is not returning null. What is getSt(), anyway; anything like createStatement()? Now that I see your edit, it is likely that your DBConn class is not successful in its call to createStatement().
Not quite able to test right now, but I would sugest you make your DBConnection.getSt() method return a brand new Statement object, instead of reusing the same one over and over. Would be something like:
public Statement getSt() {
return conn.createStatement();
}
Remember to close your statement after using it.

Categories