0

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!

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I wil test it now. Do you a reference for public <T> T? I only know public T and I would like to understand it. :)
0

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.

1 Comment

Great answer! But with lambda, I can only have an one-method-interface and I need minSdkVersion 1.7 :) But also a great Idea to use lambda to shrink code. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.