diff --git a/src/main/java/com/zaxxer/hikari/proxy/CallableStatementProxy.java b/src/main/java/com/zaxxer/hikari/proxy/CallableStatementProxy.java index 9cd50236..8f73f586 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/CallableStatementProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/CallableStatementProxy.java @@ -19,6 +19,23 @@ package com.zaxxer.hikari.proxy; import java.sql.CallableStatement; /** + * This is the proxy class for java.sql.CallableStatement. It is used in two ways: + * + * 1) If instrumentation is not used, Javassist will generate a new class + * that extends this class and delegates all method calls to the 'delegate' + * member (which points to the real Connection). + * + * 2) If instrumentation IS used, Javassist will be used to inject all of + * the &HikariInject and &HikariOverride annotated fields and methods + * of this class into the actual CallableStatement implementation provided by the + * JDBC driver. In order to avoid name conflicts some of the fields and + * methods are prefixed with _ or __. + * + * Methods prefixed with __, like __executeQuery() are especially + * important because when we inject out own executeQuery() into the + * target implementation, the original method is renamed to __executeQuery() + * so that the call operates the same whether delegation or instrumentation + * is used. * * @author Brett Wooldridge */ @@ -33,6 +50,7 @@ public abstract class CallableStatementProxy extends PreparedStatementProxy impl // Overridden java.sql.CallableStatement Methods // ********************************************************************** + // *********************************************************************** // These methods contain code we do not want injected into the actual // java.sql.Connection implementation class. These methods are only diff --git a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index 2284571a..82e19074 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -32,18 +32,23 @@ import com.zaxxer.hikari.javassist.HikariInject; import com.zaxxer.hikari.javassist.HikariOverride; /** - * This is the proxy class for java.sql.Connection. It is used in - * two ways: + * This is the proxy class for java.sql.Connection. It is used in two ways: * * 1) If instrumentation is not used, Javassist will generate a new class * that extends this class and delegates all method calls to the 'delegate' * member (which points to the real Connection). * * 2) If instrumentation IS used, Javassist will be used to inject all of - * the non-final methods of this class into the actual Connection implementation - * provided by the JDBC driver. All of the fields, except for PROXY_FACTORY - * and 'delegate' are also injected. In order to avoid name conflicts the - * fields of this class have slightly unconventional names. + * the &HikariInject and &HikariOverride annotated fields and methods + * of this class into the actual Connection implementation provided by the + * JDBC driver. In order to avoid name conflicts some of the fields and + * methods are prefixed with _ or __. + * + * Methods prefixed with __, like __createStatement() are especially + * important because when we inject out own createStatement() into the + * target implementation, the original method is renamed to __createStatement() + * so that the call operates the same whether delegation or instrumentation + * is used. * * @author Brett Wooldridge */ @@ -77,6 +82,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect SQL_ERRORS.add("57P02"); // CRASH SHUTDOWN SQL_ERRORS.add("01002"); // SQL92 disconnect error + // This is important when injecting in instrumentation mode. Do not change + // this name without also fixing the HikariClassTransformer. __static(); } @@ -84,6 +91,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect { this.delegate = connection; + // This is important when injecting in instrumentation mode. Do not change + // this name without also fixing the HikariClassTransformer. __init(); } @@ -187,11 +196,6 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect return statement; } - public final Connection getDelegate() - { - return delegate; - } - // ********************************************************************** // "Overridden" java.sql.Connection Methods // ********************************************************************** diff --git a/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java b/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java index 026f47d3..5cd79a8d 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java +++ b/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactoryFactory.java @@ -28,6 +28,7 @@ import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import javassist.CtNewMethod; +import javassist.LoaderClassPath; import javassist.Modifier; import com.zaxxer.hikari.util.ClassLoaderUtils; @@ -58,10 +59,9 @@ public final class JavassistProxyFactoryFactory private JavassistProxyFactoryFactory() { - ClassPool defaultPool = ClassPool.getDefault(); - classPool = new ClassPool(defaultPool); + classPool = new ClassPool(); classPool.importPackage("java.sql"); - classPool.childFirstLookup = true; + classPool.appendClassPath(new LoaderClassPath(this.getClass().getClassLoader())); try { @@ -86,8 +86,9 @@ public final class JavassistProxyFactoryFactory private ProxyFactory generateProxyFactory() throws Exception { - CtClass targetCt = classPool.makeClass("com.zaxxer.hikari.proxy.JavassistProxyFactory"); - CtClass superCt = classPool.getCtClass("com.zaxxer.hikari.proxy.ProxyFactory"); + String packageName = ProxyFactory.class.getPackage().getName(); + CtClass targetCt = classPool.makeClass(packageName + ".JavassistProxyFactory"); + CtClass superCt = classPool.getCtClass(ProxyFactory.class.getName()); targetCt.setSuperclass(superCt); targetCt.setModifiers(Modifier.FINAL); @@ -98,23 +99,23 @@ public final class JavassistProxyFactoryFactory StringBuilder call = new StringBuilder("{"); if ("getProxyConnection".equals(method.getName())) { - call.append("return new com.zaxxer.hikari.proxy.ConnectionJavassistProxy($$);"); + call.append("return new ").append(packageName).append(".ConnectionJavassistProxy($$);"); } if ("getProxyStatement".equals(method.getName())) { - call.append("return $2 != null ? new com.zaxxer.hikari.proxy.StatementJavassistProxy($$) : null;"); + call.append("return $2 != null ? new ").append(packageName).append(".StatementJavassistProxy($$) : null;"); } if ("getProxyPreparedStatement".equals(method.getName())) { - call.append("return $2 != null ? new com.zaxxer.hikari.proxy.PreparedStatementJavassistProxy($$) : null;"); + call.append("return $2 != null ? new ").append(packageName).append(".PreparedStatementJavassistProxy($$) : null;"); } if ("getProxyResultSet".equals(method.getName())) { - call.append("return $2 != null ? new com.zaxxer.hikari.proxy.ResultSetJavassistProxy($$) : null;"); + call.append("return $2 != null ? new ").append(packageName).append(".ResultSetJavassistProxy($$) : null;"); } if ("getProxyCallableStatement".equals(method.getName())) { - call.append("return $2 != null ? new com.zaxxer.hikari.proxy.CallableStatementJavassistProxy($$) : null;"); + call.append("return $2 != null ? new ").append(packageName).append(".CallableStatementJavassistProxy($$) : null;"); } call.append('}'); method.setBody(call.toString()); diff --git a/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java b/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java index cbc37aee..4ccfe775 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java @@ -23,6 +23,23 @@ import java.sql.SQLException; import com.zaxxer.hikari.javassist.HikariOverride; /** + * This is the proxy class for java.sql.PreparedStatement. It is used in two ways: + * + * 1) If instrumentation is not used, Javassist will generate a new class + * that extends this class and delegates all method calls to the 'delegate' + * member (which points to the real Connection). + * + * 2) If instrumentation IS used, Javassist will be used to inject all of + * the &HikariInject and &HikariOverride annotated fields and methods + * of this class into the actual PreparedStatement implementation provided by the + * JDBC driver. In order to avoid name conflicts some of the fields and + * methods are prefixed with _ or __. + * + * Methods prefixed with __, like __executeQuery() are especially + * important because when we inject out own executeQuery() into the + * target implementation, the original method is renamed to __executeQuery() + * so that the call operates the same whether delegation or instrumentation + * is used. * * @author Brett Wooldridge */ @@ -42,13 +59,7 @@ public abstract class PreparedStatementProxy extends StatementProxy implements I { try { - ResultSet rs = __executeQuery(); - if (rs != null) - { - ((IHikariResultSetProxy) rs)._setProxyStatement(this); - } - - return rs; + return _trackResultSet(__executeQuery()); } catch (SQLException e) { @@ -66,10 +77,6 @@ public abstract class PreparedStatementProxy extends StatementProxy implements I public ResultSet __executeQuery() throws SQLException { ResultSet resultSet = ((PreparedStatement) delegate).executeQuery(); - if (resultSet != null) - { - resultSet = PROXY_FACTORY.getProxyResultSet(this, resultSet); - } - return resultSet; + return wrapResultSet(resultSet); } } diff --git a/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java b/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java index 05a1643a..493129eb 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java @@ -23,6 +23,18 @@ import java.sql.Statement; import com.zaxxer.hikari.javassist.HikariInject; /** + * This is the proxy class for java.sql.ResultSet. It is used in two ways: + * + * 1) If instrumentation is not used, Javassist will generate a new class + * that extends this class and delegates all method calls to the 'delegate' + * member (which points to the real Connection). + * + * 2) If instrumentation IS used, Javassist will be used to inject all of + * the &HikariInject and &HikariOverride annotated fields and methods + * of this class into the actual ResultSet implementation provided by the + * JDBC driver. In order to avoid name conflicts some of the fields and + * methods are prefixed with _ or __. + * * @author Brett Wooldridge */ public abstract class ResultSetProxy implements IHikariResultSetProxy, ResultSet diff --git a/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java b/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java index cace42f4..fcbf67e7 100644 --- a/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java +++ b/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java @@ -25,6 +25,24 @@ import com.zaxxer.hikari.javassist.HikariInject; import com.zaxxer.hikari.javassist.HikariOverride; /** + * This is the proxy class for java.sql.Statement. It is used in two ways: + * + * 1) If instrumentation is not used, Javassist will generate a new class + * that extends this class and delegates all method calls to the 'delegate' + * member (which points to the real Connection). + * + * 2) If instrumentation IS used, Javassist will be used to inject all of + * the &HikariInject and &HikariOverride annotated fields and methods + * of this class into the actual Statement implementation provided by the + * JDBC driver. In order to avoid name conflicts some of the fields and + * methods are prefixed with _ or __. + * + * Methods prefixed with __, like __executeQuery() are especially + * important because when we inject out own executeQuery() into the + * target implementation, the original method is renamed to __executeQuery() + * so that the call operates the same whether delegation or instrumentation + * is used. + * * @author Brett Wooldridge */ public abstract class StatementProxy implements IHikariStatementProxy, Statement @@ -39,6 +57,8 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement static { + // This is important when injecting in instrumentation mode. Do not change + // this name without also fixing the HikariClassTransformer. __static(); } @@ -71,6 +91,16 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement { } + @HikariInject + protected T _trackResultSet(T resultSet) + { + if (resultSet != null) + { + ((IHikariResultSetProxy) resultSet)._setProxyStatement(this); + } + return resultSet; + } + // ********************************************************************** // Overridden java.sql.Statement Methods // ********************************************************************** @@ -85,6 +115,7 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement _isClosed = true; _connection._unregisterStatement(this); + try { __close(); @@ -100,13 +131,7 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement { try { - ResultSet rs = __executeQuery(sql); - if (rs != null) - { - ((IHikariResultSetProxy) rs)._setProxyStatement(this); - } - - return rs; + return _trackResultSet(__executeQuery(sql)); } catch (SQLException e) { @@ -119,13 +144,7 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement { try { - ResultSet rs = __getResultSet(); - if (rs != null) - { - ((IHikariResultSetProxy) rs)._setProxyStatement(this); - } - - return rs; + return _trackResultSet(__getResultSet()); } catch (SQLException e) { @@ -138,13 +157,7 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement { try { - ResultSet rs = __getGeneratedKeys(); - if (rs != null) - { - ((IHikariResultSetProxy) rs)._setProxyStatement(this); - } - - return rs; + return _trackResultSet(__getGeneratedKeys()); } catch (SQLException e) { @@ -184,31 +197,26 @@ public abstract class StatementProxy implements IHikariStatementProxy, Statement public ResultSet __executeQuery(String sql) throws SQLException { - ResultSet resultSet = delegate.executeQuery(sql); - if (resultSet != null) - { - resultSet = PROXY_FACTORY.getProxyResultSet(this, resultSet); - } - return resultSet; + return wrapResultSet(delegate.executeQuery(sql)); } public ResultSet __getGeneratedKeys() throws SQLException { - ResultSet generatedKeys = delegate.getGeneratedKeys(); - if (generatedKeys != null) - { - generatedKeys = PROXY_FACTORY.getProxyResultSet(this, generatedKeys); - } - return generatedKeys; + return wrapResultSet(delegate.getGeneratedKeys()); } public ResultSet __getResultSet() throws SQLException { - ResultSet resultSet = delegate.getResultSet(); + return wrapResultSet(delegate.getResultSet()); + } + + protected ResultSet wrapResultSet(ResultSet resultSet) + { if (resultSet != null) { resultSet = PROXY_FACTORY.getProxyResultSet(this, resultSet); } - return resultSet; + + return resultSet; } } \ No newline at end of file