Solución 1: Subclase
Basta con crear una implementación personalizada de un PreparedStatement que delega todas las llamadas al declaración preparada el original, sólo se suma devoluciones de llamada en el setObject, etc. métodos. Ejemplo:
public PreparedStatement prepareStatement(String sql) {
final PreparedStatement delegate = conn.prepareStatement(sql);
return new PreparedStatement() {
// TODO: much more methods to delegate
@Override
public void setString(int parameterIndex, String x) throws SQLException {
// TODO: remember value of X
delegate.setString(parameterIndex, x);
}
};
}
Si desea guardar los parámetros y obtener más adelante, hay muchas soluciones, pero yo prefiero la creación de una nueva clase como ParameterAwarePreparedStatement que tiene los parámetros en un mapa. La estructura podría ser similar a esto:
public class ParameterAwarePreparedStatement implements PreparedStatement {
private final PreparedStatement delegate;
private final Map<Integer,Object> parameters;
public ParameterAwarePreparedStatement(PreparedStatement delegate) {
this.delegate = delegate;
this.parameters = new HashMap<>();
}
public Map<Integer,Object> getParameters() {
return Collections.unmodifiableMap(parameters);
}
// TODO: many methods to delegate
@Override
public void setString(int parameterIndex, String x) throws SQLException {
delegate.setString(parameterIndex, x);
parameters.put(parameterIndex, x);
}
}
Solución 2: proxy dinámico
Esta segunda solución es más corto, pero parece más hacky.
Puede crear un proxy dinámico llamando a un método de fábrica en java.lang.reflect.Proxy y delegar todas las llamadas en la instancia original. Ejemplo:
public PreparedStatement prepareStatement(String sql) {
final PreparedStatement ps = conn.prepareStatement(sql);
final PreparedStatement psProxy = (PreparedStatement) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class<?>[]{PreparedStatement.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("setLong")) {
// ... your code here ...
}
// this invokes the default call
return method.invoke(ps, args);
}
});
return psProxy;
}
A continuación, interceptar la setObject, etc. llamadas examinado los nombres de métodos y mirando a los segundos argumentos de los métodos para sus valores.