diff options
author | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2014-02-07 12:46:52 +0100 |
---|---|---|
committer | Jean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com> | 2014-02-07 12:50:15 +0100 |
commit | f01cfd845d078e6b2df8b53c5d00866e16623e09 (patch) | |
tree | e00d3d4d577234b5c610a4ad7f2d9775af93d10c /sonar-core | |
parent | eb6c3ebf24003a296f2a69ce5ba60fbd24e651b6 (diff) | |
download | sonarqube-f01cfd845d078e6b2df8b53c5d00866e16623e09.tar.gz sonarqube-f01cfd845d078e6b2df8b53c5d00866e16623e09.zip |
SONAR-4925 Fix an issue with unexpected exception thrown by proxified objects
Diffstat (limited to 'sonar-core')
6 files changed, 139 insertions, 19 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/InvocationUtils.java b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/InvocationUtils.java new file mode 100644 index 00000000000..0ac7960d491 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/InvocationUtils.java @@ -0,0 +1,46 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.core.persistence.profiling; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +class InvocationUtils { + + private InvocationUtils() { + // Only private stuff + } + + static Object invokeQuietly(Object target, Method method, Object[] params) throws Throwable { + Object result = null; + try { + result = method.invoke(target, params); + } catch(InvocationTargetException invocationException) { + for (Class<?> exceptionClass: method.getExceptionTypes()) { + if (exceptionClass.isInstance(invocationException.getCause())) { + throw invocationException.getCause(); + } + throw new IllegalStateException(invocationException.getCause()); + } + } + return result; + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingConnectionHandler.java b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingConnectionHandler.java index 1a8c86eed33..aa16400b629 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingConnectionHandler.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingConnectionHandler.java @@ -36,7 +36,7 @@ class ProfilingConnectionHandler implements InvocationHandler { @Override public Object invoke(Object target, Method method, Object[] args) throws Throwable { - Object result = method.invoke(connection, args); + Object result = InvocationUtils.invokeQuietly(connection, method, args); if ("prepareStatement".equals(method.getName())) { PreparedStatement statement = (PreparedStatement) result; String sql = (String) args[0]; diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingPreparedStatementHandler.java b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingPreparedStatementHandler.java index 8550e7bfe19..f3fa082b94e 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingPreparedStatementHandler.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingPreparedStatementHandler.java @@ -19,8 +19,8 @@ */ package org.sonar.core.persistence.profiling; -import org.apache.commons.lang.StringUtils; import com.google.common.collect.Lists; +import org.apache.commons.lang.StringUtils; import org.sonar.core.profiling.StopWatch; import java.lang.reflect.InvocationHandler; @@ -52,21 +52,25 @@ class ProfilingPreparedStatementHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().startsWith("execute")) { StopWatch watch = PROFILING.start(); - Object result = method.invoke(statement, args); - StringBuilder sqlBuilder = new StringBuilder().append(sql); - if (!arguments.isEmpty()) { - sqlBuilder.append(" - parameters are: "); - for (Object arg: arguments) { - sqlBuilder.append(PARAM_PREFIX).append(arg).append(PARAM_SUFFIX).append(PARAM_SEPARATOR); + Object result = null; + try { + result = InvocationUtils.invokeQuietly(statement, method, args); + } finally { + StringBuilder sqlBuilder = new StringBuilder().append(sql); + if (!arguments.isEmpty()) { + sqlBuilder.append(" - parameters are: "); + for (Object arg: arguments) { + sqlBuilder.append(PARAM_PREFIX).append(arg).append(PARAM_SUFFIX).append(PARAM_SEPARATOR); + } } + PROFILING.stop(watch, StringUtils.removeEnd(sqlBuilder.toString(), PARAM_SEPARATOR)); } - PROFILING.stop(watch, StringUtils.removeEnd(sqlBuilder.toString(), PARAM_SEPARATOR)); return result; } else if (method.getName().startsWith("set") && args.length > 1) { arguments.set((Integer) args[0] - 1, args[1]); - return method.invoke(statement, args); + return InvocationUtils.invokeQuietly(statement, method, args); } else { - return method.invoke(statement, args); + return InvocationUtils.invokeQuietly(statement, method, args); } } diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingStatementHandler.java b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingStatementHandler.java index 89d91c0db81..152f26661fe 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingStatementHandler.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/profiling/ProfilingStatementHandler.java @@ -39,11 +39,15 @@ class ProfilingStatementHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().startsWith("execute")) { StopWatch watch = PROFILING.start(); - Object result = method.invoke(statement, args); - PROFILING.stop(watch, (String) args[0]); + Object result = null; + try { + result = InvocationUtils.invokeQuietly(statement, method, args); + } finally { + PROFILING.stop(watch, (String) args[0]); + } return result; } else { - return method.invoke(statement, args); + return InvocationUtils.invokeQuietly(statement, method, args); } } } diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/profiling/InvocationUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/profiling/InvocationUtilsTest.java new file mode 100644 index 00000000000..53844aa5947 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/persistence/profiling/InvocationUtilsTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.persistence.profiling; + +import org.fest.assertions.Fail; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.SQLException; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class InvocationUtilsTest { + + @Test + public void should_return_result() throws Throwable { + String toString = "toString"; + Object target = mock(Object.class); + when(target.toString()).thenReturn(toString); + + assertThat(InvocationUtils.invokeQuietly(target, Object.class.getMethod("toString"), new Object[0])).isEqualTo(toString); + } + + @Test + public void should_throw_declared_exception() throws Throwable { + Connection target = mock(Connection.class); + String failSql = "any sql"; + when(target.prepareStatement(failSql)).thenThrow(new SQLException("Expected")); + + try { + InvocationUtils.invokeQuietly(target, Connection.class.getMethod("prepareStatement", String.class), new Object[] { failSql }); + Fail.fail(); + } catch (Throwable t) { + assertThat(t).isInstanceOf(SQLException.class); + } + } + + @Test + public void should_wrap_undeclared_exception() throws Throwable { + Connection target = mock(Connection.class); + String failSql = "any sql"; + when(target.prepareStatement(failSql)).thenThrow(new SQLException("Expected")); + + try { + InvocationUtils.invokeQuietly(target, Object.class.getMethod("wait"), new Object[0]); + Fail.fail(); + } catch (Throwable t) { + assertThat(t).isInstanceOf(IllegalStateException.class); + } + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/persistence/profiling/PersistenceProfilingTest.java b/sonar-core/src/test/java/org/sonar/core/persistence/profiling/PersistenceProfilingTest.java index 9faec0790e3..1ad3213e860 100644 --- a/sonar-core/src/test/java/org/sonar/core/persistence/profiling/PersistenceProfilingTest.java +++ b/sonar-core/src/test/java/org/sonar/core/persistence/profiling/PersistenceProfilingTest.java @@ -31,11 +31,7 @@ import org.sonar.api.config.Settings; import org.sonar.core.profiling.Profiling; import java.io.ByteArrayInputStream; -import java.sql.Connection; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.Statement; -import java.sql.Timestamp; +import java.sql.*; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; |