Rozwiązanie 1: Podklasa
Wystarczy utworzyć niestandardową implementację o PreparedStatement których delegaci wszystkich wywołań oryginalnego przygotowanym oświadczeniu, dodając tylko wywołania zwrotne w setObject itp metody. Przykład:
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);
}
};
}
Jeśli chcesz zapisać parametry i je później, istnieje wiele rozwiązań, ale wolę tworząc nową klasę jak ParameterAwarePreparedStatement która ma parametry na mapie. Struktura może być podobny do tego:
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);
}
}
Rozwiązanie 2: Dynamiczne proxy
To drugie rozwiązanie jest krótsza, ale wydaje się bardziej hacky.
Można utworzyć dynamiczny serwer proxy, wywołując metodę fabryczną na java.lang.reflect.Proxy i delegować wszystkie wywołania w oryginalnej instancji. Przykład:
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;
}
Następnie przechwycić setObject itd połączeń patrząc na nazwy metody i patrząc do drugich argumentów metoda swoimi wartościami.