To come back to my earlier offer for long-winded explanation and code,
here is the utility class I was writing that prompted my question. I
wasn't trying to create a proxy, and it hadn't dawned on me the what I
was writing might easily become one, until I saw Sergey's class. I
only added a couple of fetch/execute variations for what I was using
so far, and expected that to change, as I evaluated how I really
wanted to do that. It is hardly finished, but perhaps some of the
ideas in it could be adapted to Sergey's class to handle the
awkwardness of connection closing.
My motivation in writing it was that I was acculating a number of
methods in some "service classes" which were doing JOOQ queries and I
realized they had a lot of redundant boilerplate, and I wanted to
encapsulate that somewhere. In particular the code to get and close
connections, catch exceptions, and rethrow those as domain-specific
exceptions. (That is what the "ExceptionFactory" is about...this may
not be the right term for it...and if you don't provide one it just
throws RuntimeExceptions wrapping the underlying exception).
Anyway, FWIW, here it is:
---------------------------------------------------
package com.wrycan.db.util;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SelectFinalStep;
import org.jooq.exception.DataAccessException;
import org.jooq.impl.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JooqExecutor {
private final ExceptionFactory<? extends RuntimeException>
exceptionFactory;
private final DataSource dataSource;
private final Logger logger =
LoggerFactory.getLogger(JooqExecutor.class);
public JooqExecutor(DataSource dataSource, ExceptionFactory<? extends
RuntimeException> exceptionFactory) {
this.dataSource = dataSource;
this.exceptionFactory = exceptionFactory;
logger.info("JooqExecutor created");
}
public JooqExecutor(DataSource dataSource) {
this.dataSource = dataSource;
this.exceptionFactory = new DefaultExceptionFactory();
logger.info("JooqExecutor created");
}
private abstract class Command <T> {
protected abstract T execute(SelectFinalStep select) throws
DataAccessException;
}
public final Record doFetchOne(Factory jooqFactory, SelectFinalStep
select) throws RuntimeException {
return executeCommand(jooqFactory, select, new Command<Record>() {
@Override
protected Record execute(SelectFinalStep select) {
return select.fetchOne();
}
});
}
public final Result<Record> doFetch(Factory jooqFactory,
SelectFinalStep select) throws RuntimeException {
return executeCommand(jooqFactory, select, new
Command<Result<Record>>() {
@Override
protected Result<Record> execute(SelectFinalStep select) {
return select.fetch();
}
});
}
public final Integer doExecute(Factory jooqFactory, SelectFinalStep
select) throws RuntimeException {
return executeCommand(jooqFactory, select, new Command<Integer>() {
@Override
protected Integer execute(SelectFinalStep select) {
return select.execute();
}
});
}
protected final <T> T executeCommand(Factory jooqFactory,
SelectFinalStep select, Command<T> doer) throws RuntimeException {
Connection conn = null;
try {
conn = dataSource.getConnection();
jooqFactory.setConnection(conn);
return doer.execute(select);
} catch (DataAccessException e) {
exceptionFactory.throwException("Error executing backend query" ,
e);
} catch (SQLException e) {
exceptionFactory.throwException("Error connecting backend query");
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
exceptionFactory.throwException("Error closing backend
connection");
}
}
}
exceptionFactory.throwException("Impossible exception handling
failure");
return null;
}
public static interface ExceptionFactory<E extends RuntimeException>
{
public void throwException() throws E;
public void throwException(String msg) throws E;
public void throwException(Exception e) throws E;
public void throwException(String msg, Exception e) throws E;
}
private static final class DefaultExceptionFactory implements
ExceptionFactory<RuntimeException> {
@Override
public final void throwException(String msg) throws
RuntimeException{
throw new RuntimeException(msg);
}
@Override
public final void throwException() throws RuntimeException {
throw new RuntimeException();
}
@Override
public final void throwException(Exception e) throws
RuntimeException {
throw new RuntimeException(e);
}
@Override
public final void throwException(String msg, Exception e) throws
RuntimeException {
throw new RuntimeException(msg, e);
}
}
}