HHH-14763 Avoid suppress exceptions in try/finally

This commit is contained in:
boris-unckel 2021-07-29 15:19:17 +02:00 committed by Christian Beikov
parent 6314395edf
commit f24b91da2a
4 changed files with 89 additions and 18 deletions

View File

@ -111,6 +111,7 @@ import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.graph.GraphSemantic; import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.internal.RootGraphImpl; import org.hibernate.graph.internal.RootGraphImpl;
import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.CacheModeHelper;
@ -712,6 +713,7 @@ public class SessionImpl
} }
private void firePersist(final PersistEvent event) { private void firePersist(final PersistEvent event) {
Throwable originalException = null;
try { try {
checkTransactionSynchStatus(); checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation(); checkNoUnresolvedActionsBeforeOperation();
@ -719,18 +721,36 @@ public class SessionImpl
fastSessionServices.eventListenerGroup_PERSIST.fireEventOnEachListener( event, PersistEventListener::onPersist ); fastSessionServices.eventListenerGroup_PERSIST.fireEventOnEachListener( event, PersistEventListener::onPersist );
} }
catch (MappingException e) { catch (MappingException e) {
throw getExceptionConverter().convert( new IllegalArgumentException( e.getMessage() ) ); originalException = getExceptionConverter().convert( new IllegalArgumentException( e.getMessage() ) );
} }
catch (RuntimeException e) { catch (RuntimeException e) {
throw getExceptionConverter().convert( e ); originalException = getExceptionConverter().convert( e );
}
catch (Throwable t1) {
originalException = t1;
} }
finally { finally {
Throwable suppressed = null;
try { try {
checkNoUnresolvedActionsAfterOperation(); checkNoUnresolvedActionsAfterOperation();
} }
catch (RuntimeException e) { catch (RuntimeException e) {
throw getExceptionConverter().convert( e ); suppressed = getExceptionConverter().convert( e );
} }
catch (Throwable t2) {
suppressed = t2;
}
if ( suppressed != null ) {
if ( originalException == null ) {
originalException = suppressed;
}
else {
originalException.addSuppressed( suppressed );
}
}
}
if ( originalException != null ) {
ExceptionHelper.doThrow( originalException );
} }
} }

View File

@ -0,0 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.internal.util;
public final class ExceptionHelper {
private ExceptionHelper() {
}
/**
* Throws the given throwable even if it is a checked exception.
*
* @param e The throwable to throw.
*/
public static void doThrow(Throwable e) {
ExceptionHelper.<RuntimeException>doThrow0(e);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> void doThrow0(Throwable e) throws T {
throw (T) e;
}
}

View File

@ -10,6 +10,7 @@ import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import org.hibernate.internal.log.ConnectionAccessLogger; import org.hibernate.internal.log.ConnectionAccessLogger;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator;
import org.hibernate.tool.schema.internal.exec.JdbcContext; import org.hibernate.tool.schema.internal.exec.JdbcContext;
@ -81,29 +82,46 @@ public class DdlTransactionIsolatorNonJtaImpl implements DdlTransactionIsolator
@Override @Override
public void release() { public void release() {
if ( jdbcConnection != null ) { if ( jdbcConnection != null ) {
Throwable originalException = null;
try { try {
if ( unsetAutoCommit ) { if ( unsetAutoCommit ) {
try { try {
jdbcConnection.setAutoCommit( false ); jdbcConnection.setAutoCommit( false );
} }
catch (SQLException e) { catch (SQLException e) {
throw jdbcContext.getSqlExceptionHelper().convert( originalException = jdbcContext.getSqlExceptionHelper().convert(
e, e,
"Unable to set auto commit to false for JDBC Connection used for DDL execution" "Unable to set auto commit to false for JDBC Connection used for DDL execution" );
); }
catch (Throwable t1) {
originalException = t1;
} }
} }
} }
finally { finally {
Throwable suppressed = null;
try { try {
jdbcContext.getJdbcConnectionAccess().releaseConnection( jdbcConnection ); jdbcContext.getJdbcConnectionAccess().releaseConnection( jdbcConnection );
} }
catch (SQLException e) { catch (SQLException e) {
throw jdbcContext.getSqlExceptionHelper().convert( suppressed = jdbcContext.getSqlExceptionHelper().convert(
e, e,
"Unable to release JDBC Connection used for DDL execution" "Unable to release JDBC Connection used for DDL execution" );
);
} }
catch (Throwable t2) {
suppressed = t2;
}
if ( suppressed != null ) {
if ( originalException == null ) {
originalException = suppressed;
}
else {
originalException.addSuppressed( suppressed );
}
}
}
if ( originalException != null ) {
ExceptionHelper.doThrow( originalException );
} }
} }
} }

View File

@ -20,6 +20,7 @@ import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.transaction.spi.IsolationDelegate; import org.hibernate.engine.transaction.spi.IsolationDelegate;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ExceptionHelper;
import org.hibernate.jdbc.WorkExecutor; import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable; import org.hibernate.jdbc.WorkExecutorVisitable;
@ -103,36 +104,40 @@ public class JtaIsolationDelegate implements IsolationDelegate {
} }
private <T> T doInSuspendedTransaction(HibernateCallable<T> callable) { private <T> T doInSuspendedTransaction(HibernateCallable<T> callable) {
Throwable originalException = null;
try { try {
// First we suspend any current JTA transaction // First we suspend any current JTA transaction
Transaction surroundingTransaction = transactionManager.suspend(); Transaction surroundingTransaction = transactionManager.suspend();
LOG.debugf( "Surrounding JTA transaction suspended [%s]", surroundingTransaction ); LOG.debugf( "Surrounding JTA transaction suspended [%s]", surroundingTransaction );
boolean hadProblems = false;
try { try {
return callable.call(); return callable.call();
} }
catch (HibernateException e) { catch (Throwable t1) {
hadProblems = true; originalException = t1;
throw e;
} }
finally { finally {
try { try {
transactionManager.resume( surroundingTransaction ); transactionManager.resume( surroundingTransaction );
LOG.debugf( "Surrounding JTA transaction resumed [%s]", surroundingTransaction ); LOG.debugf( "Surrounding JTA transaction resumed [%s]", surroundingTransaction );
} }
catch (Throwable t) { catch (Throwable t2) {
// if the actually work had an error use that, otherwise error based on t // if the actually work had an error use that, otherwise error based on t
if ( !hadProblems ) { if ( originalException == null ) {
//noinspection ThrowFromFinallyBlock originalException = new HibernateException( "Unable to resume previously suspended transaction", t2 );
throw new HibernateException( "Unable to resume previously suspended transaction", t ); }
else {
originalException.addSuppressed( t2 ); // No extra nesting, directly t2
} }
} }
} }
} }
catch (SystemException e) { catch (SystemException e) {
throw new HibernateException( "Unable to suspend current JTA transaction", e ); originalException = new HibernateException( "Unable to suspend current JTA transaction", e );
} }
ExceptionHelper.doThrow( originalException );
return null;
} }
private <T> T doInNewTransaction(HibernateCallable<T> callable, TransactionManager transactionManager) { private <T> T doInNewTransaction(HibernateCallable<T> callable, TransactionManager transactionManager) {