Index: src/net/lemnik/eodsql/impl/BaseQueryImpl.java =================================================================== --- src/net/lemnik/eodsql/impl/BaseQueryImpl.java (revision 217) +++ src/net/lemnik/eodsql/impl/BaseQueryImpl.java (working copy) @@ -39,6 +39,8 @@ protected Map methods = new HashMap(); private ConnectionSource connectionSource; + + private ExceptionTranslator exceptionTranslator; private volatile boolean closed = false; @@ -56,6 +58,7 @@ this.connectionSource = connectionSource; createImplementations(clazz, baseInterface); + this.exceptionTranslator = new ExceptionTranslator(connectionSource); } protected void close() throws SQLException { @@ -145,8 +148,8 @@ final Object[] args) throws Throwable { + final Callable impl = methods.get(method); try { - final Callable impl = methods.get(method); return impl.invoke(method, args); } catch(final RuntimeException runtimeException) { // we catch this, so that it's not caught in the catch(Exception) @@ -163,7 +166,7 @@ } // if we got here, the Exception was not declared, wrap it in a RuntimeException - throw new RuntimeException(exception); + throw exceptionTranslator.translateException(method, impl, exception); } } @@ -226,6 +229,11 @@ } } } + + AbstractMethodImplementation getMethodImpl() + { + return (AbstractMethodImplementation) implementation; + } } @@ -263,7 +271,7 @@ public void releaseConnection(final Connection connection) throws SQLException { - if(connection == connection) { + if(this.connection == connection) { lock.unlock(); } } @@ -336,6 +344,11 @@ } } } + + DataSource getDataSource() + { + return datasource; + } private static class ConnectionUtil { Index: src/net/lemnik/eodsql/impl/ExceptionTranslator.java =================================================================== --- src/net/lemnik/eodsql/impl/ExceptionTranslator.java (revision 0) +++ src/net/lemnik/eodsql/impl/ExceptionTranslator.java (revision 0) @@ -0,0 +1,118 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.lemnik.eodsql.impl; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.sql.SQLException; + +import org.springframework.dao.IncorrectResultSizeDataAccessException; + +import net.lemnik.eodsql.impl.BaseQueryImpl.Callable; +import net.lemnik.eodsql.impl.BaseQueryImpl.ConnectionSource; +import net.lemnik.eodsql.impl.BaseQueryImpl.MethodImpl; + +/** + * A class for translating checked into unchecked exceptions. + * + * @author Bernd Rinn + */ +public class ExceptionTranslator +{ + private final static boolean haveSpring = checkHaveSpring(); + + private static boolean checkHaveSpring() + { + try + { + Class.forName("org.springframework.jdbc.support.SQLExceptionTranslator"); + return true; + } catch (ClassNotFoundException ex) + { + return false; + } + } + + private final SpringSQLExceptionTranslatorWrapper translatorOrNull; + + ExceptionTranslator(ConnectionSource source) + { + if (haveSpring) + { + translatorOrNull = new SpringSQLExceptionTranslatorWrapper(source); + } else + { + translatorOrNull = null; + } + } + + /** + * Throw the given exception, wrapping it in some sort of unchecked exception. + */ + RuntimeException translateException(final String task, final String sql, final Exception ex) + { + if (translatorOrNull != null && ex instanceof SQLException) + { + return translatorOrNull.translate(task, sql, (SQLException) ex); + } else + { + return new RuntimeException(ex); + } + } + + /** + * Throw the given exception, wrapping it in some sort of unchecked exception. + */ + RuntimeException translateException(final Method method, final Callable callable, + final Exception ex) + { + if (translatorOrNull != null && ex instanceof SQLException) + { + final String methodName = method.getName(); + final String sql; + if (callable instanceof MethodImpl) + { + final AbstractMethodImplementation m = + ((MethodImpl) callable).getMethodImpl(); + sql = m.query.toString(); + } else + { + sql = "?"; + } + return translatorOrNull.translate(methodName, sql, (SQLException) ex); + } else + { + return new RuntimeException(ex); + } + } + + /** + * Returns an exception when a unique result is expected from the database, but the database + * returns multiple rows. + */ + public static RuntimeException uniqueResultExpected() + { + final String msg = "A unique result was expected but the database returned multiple rows."; + if (haveSpring) + { + return new IncorrectResultSizeDataAccessException(msg, 1); + } else + { + return new RuntimeException(msg); + } + } +} Index: src/net/lemnik/eodsql/impl/SpringSQLExceptionTranslatorWrapper.java =================================================================== --- src/net/lemnik/eodsql/impl/SpringSQLExceptionTranslatorWrapper.java (revision 0) +++ src/net/lemnik/eodsql/impl/SpringSQLExceptionTranslatorWrapper.java (revision 0) @@ -0,0 +1,79 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.lemnik.eodsql.impl; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; +import org.springframework.jdbc.support.SQLExceptionTranslator; + +import net.lemnik.eodsql.impl.BaseQueryImpl.ConnectionSource; +import net.lemnik.eodsql.impl.BaseQueryImpl.DataSourceConnectionSource; + +/** + * A wrapper for Spring's SQLExceptionTranslator. + *

+ * Only construct this class when spring is in the class path! + * + * @author Bernd Rinn + */ +class SpringSQLExceptionTranslatorWrapper +{ + private final SQLExceptionTranslator exceptionTranslator; + + SpringSQLExceptionTranslatorWrapper(ConnectionSource source) + { + if (source instanceof DataSourceConnectionSource) + { + exceptionTranslator = + new SQLErrorCodeSQLExceptionTranslator(((DataSourceConnectionSource) source) + .getDataSource()); + } else + { + SQLExceptionTranslator exceptionTranslatorTmp = null; + Connection conn = null; + try + { + conn = source.getConnection(); + final String databaseProductName = conn.getMetaData().getDatabaseProductName(); + exceptionTranslatorTmp = new SQLErrorCodeSQLExceptionTranslator(databaseProductName); + } catch (SQLException ex) + { + exceptionTranslatorTmp = new SQLErrorCodeSQLExceptionTranslator(); + } finally + { + if (conn != null) + { + try + { + source.releaseConnection(conn); + } catch (SQLException ex1) + { + // Nothing we can do here. + } + } + } + exceptionTranslator = exceptionTranslatorTmp; + } + } + + RuntimeException translate(String task, String sql, SQLException ex) + { + return exceptionTranslator.translate(task, sql, ex); + } +}