HHH-12666 : Add an option for restoring 5.1 native exception handling

This commit is contained in:
Gail Badner 2018-07-18 21:11:25 -07:00
parent 9286f9147b
commit 8ef0ca9a13
6 changed files with 132 additions and 65 deletions

View File

@ -47,6 +47,7 @@ import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
import org.hibernate.id.uuid.LocalObjectUuidHelper;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jpa.spi.JpaCompliance;
@ -97,6 +98,7 @@ import static org.hibernate.cfg.AvailableSettings.JTA_TRACK_BY_THREAD;
import static org.hibernate.cfg.AvailableSettings.LOG_SESSION_METRICS;
import static org.hibernate.cfg.AvailableSettings.MAX_FETCH_DEPTH;
import static org.hibernate.cfg.AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER;
import static org.hibernate.cfg.AvailableSettings.NATIVE_EXCEPTION_HANDLING_51_COMPLIANCE;
import static org.hibernate.cfg.AvailableSettings.ORDER_INSERTS;
import static org.hibernate.cfg.AvailableSettings.ORDER_UPDATES;
import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION;
@ -123,6 +125,7 @@ import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
import static org.hibernate.cfg.AvailableSettings.VALIDATE_QUERY_PARAMETERS;
import static org.hibernate.cfg.AvailableSettings.WRAP_RESULT_SETS;
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE;
/**
@ -137,7 +140,7 @@ import static org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE;
*/
@SuppressWarnings("WeakerAccess")
public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private static final Logger log = Logger.getLogger( SessionFactoryOptionsBuilder.class );
private static final CoreMessageLogger log = messageLogger( SessionFactoryOptionsBuilder.class );
private final String uuid = LocalObjectUuidHelper.generateLocalObjectUuid();
private final StandardServiceRegistry serviceRegistry;
@ -239,6 +242,8 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private boolean failOnPaginationOverCollectionFetchEnabled;
private boolean inClauseParameterPaddingEnabled;
private boolean nativeExceptionHandling51Compliance;
@SuppressWarnings({"WeakerAccess", "deprecation"})
public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, BootstrapContext context) {
this.serviceRegistry = serviceRegistry;
@ -490,7 +495,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
);
this.immutableEntityUpdateQueryHandlingMode = ImmutableEntityUpdateQueryHandlingMode.interpret(
configurationSettings.get( IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE )
configurationSettings.get( IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE )
);
this.inClauseParameterPaddingEnabled = ConfigurationHelper.getBoolean(
@ -498,6 +503,16 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
configurationSettings,
false
);
this.nativeExceptionHandling51Compliance = ConfigurationHelper.getBoolean(
NATIVE_EXCEPTION_HANDLING_51_COMPLIANCE,
configurationSettings,
false
);
if ( context.isJpaBootstrap() && nativeExceptionHandling51Compliance ) {
log.nativeExceptionHandling51ComplianceJpaBootstrapping();
this.nativeExceptionHandling51Compliance = false;
}
}
@SuppressWarnings("deprecation")
@ -1011,6 +1026,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
return jpaCompliance;
}
@Override
public boolean nativeExceptionHandling51Compliance() {
return nativeExceptionHandling51Compliance;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// In-flight mutation access

View File

@ -427,4 +427,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
public boolean inClauseParameterPaddingEnabled() {
return delegate.inClauseParameterPaddingEnabled();
}
@Override
public boolean nativeExceptionHandling51Compliance() {
return delegate.nativeExceptionHandling51Compliance();
}
}

View File

@ -286,4 +286,8 @@ public interface SessionFactoryOptions {
default boolean inClauseParameterPaddingEnabled() {
return false;
}
default boolean nativeExceptionHandling51Compliance() {
return false;
}
}

View File

@ -901,6 +901,17 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
*/
String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets";
/**
* Indicates if exception handling for a SessionFactory built via Hibernate's native bootstrapping
* should behave the same as in Hibernate ORM 5.1.
* <p/>
* This setting will be ignored if the SessionFactory was built via JPA bootstrapping.
* <p/>
* Values are {@code true} or {@code false}.
* Default value is {@code false}
*/
String NATIVE_EXCEPTION_HANDLING_51_COMPLIANCE = "hibernate.native_exception_handling_51_compliance";
/**
* Enable ordering of update statements by primary key value
*/

View File

@ -1811,4 +1811,7 @@ public interface CoreMessageLogger extends BasicLogger {
+ "in the same package as class %1$s. In this case, the class should be opened and exported to Hibernate ORM.", id = 488)
String bytecodeEnhancementFailedUnableToGetPrivateLookupFor(String className);
@LogMessage(level = WARN)
@Message(value = "Setting " + AvailableSettings.NATIVE_EXCEPTION_HANDLING_51_COMPLIANCE + "=true is not valid with JPA bootstrapping; setting will be ignored.", id = 489 )
void nativeExceptionHandling51ComplianceJpaBootstrapping();
}

View File

@ -43,14 +43,18 @@ public class ExceptionConverterImpl implements ExceptionConverter {
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( ExceptionConverterImpl.class );
private final SharedSessionContractImplementor sharedSessionContract;
private final boolean isJpaBootstrap;
private final boolean nativeExceptionHandling51Compliance;
public ExceptionConverterImpl(SharedSessionContractImplementor sharedSessionContract) {
this.sharedSessionContract = sharedSessionContract;
isJpaBootstrap = sharedSessionContract.getFactory().getSessionFactoryOptions().isJpaBootstrap();
nativeExceptionHandling51Compliance = sharedSessionContract.getFactory().getSessionFactoryOptions().nativeExceptionHandling51Compliance();
}
@Override
public RuntimeException convertCommitException(RuntimeException e) {
if ( sharedSessionContract.getFactory().getSessionFactoryOptions().isJpaBootstrap() ) {
if ( isJpaBootstrap ) {
Throwable wrappedException;
if ( e instanceof HibernateException ) {
wrappedException = convert( (HibernateException) e );
@ -83,72 +87,92 @@ public class ExceptionConverterImpl implements ExceptionConverter {
@Override
public RuntimeException convert(HibernateException e, LockOptions lockOptions) {
Throwable cause = e;
if ( cause instanceof StaleStateException ) {
final PersistenceException converted = wrapStaleStateException( (StaleStateException) cause );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof LockAcquisitionException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof LockingStrategyException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.PessimisticLockException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.QueryTimeoutException ) {
final QueryTimeoutException converted = new QueryTimeoutException( cause.getMessage(), cause );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof ObjectNotFoundException ) {
final EntityNotFoundException converted = new EntityNotFoundException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.NonUniqueObjectException ) {
final EntityExistsException converted = new EntityExistsException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.NonUniqueResultException ) {
final NonUniqueResultException converted = new NonUniqueResultException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof UnresolvableObjectException ) {
final EntityNotFoundException converted = new EntityNotFoundException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof QueryException ) {
return new IllegalArgumentException( cause );
}
else if ( cause instanceof MultipleBagFetchException ) {
return new IllegalArgumentException( cause );
}
else if ( cause instanceof TransientObjectException ) {
try {
sharedSessionContract.markForRollbackOnly();
if ( !nativeExceptionHandling51Compliance ) {
Throwable cause = e;
if ( cause instanceof StaleStateException ) {
final PersistenceException converted = wrapStaleStateException( (StaleStateException) cause );
handlePersistenceException( converted );
return converted;
}
catch (Exception ne) {
//we do not want the subsequent exception to swallow the original one
log.unableToMarkForRollbackOnTransientObjectException( ne );
else if ( cause instanceof LockAcquisitionException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof LockingStrategyException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.PessimisticLockException ) {
final PersistenceException converted = wrapLockException( (HibernateException) cause, lockOptions );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.QueryTimeoutException ) {
final QueryTimeoutException converted = new QueryTimeoutException( cause.getMessage(), cause );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof ObjectNotFoundException ) {
final EntityNotFoundException converted = new EntityNotFoundException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.NonUniqueObjectException ) {
final EntityExistsException converted = new EntityExistsException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof org.hibernate.NonUniqueResultException ) {
final NonUniqueResultException converted = new NonUniqueResultException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof UnresolvableObjectException ) {
final EntityNotFoundException converted = new EntityNotFoundException( cause.getMessage() );
handlePersistenceException( converted );
return converted;
}
else if ( cause instanceof QueryException ) {
return new IllegalArgumentException( cause );
}
else if ( cause instanceof MultipleBagFetchException ) {
return new IllegalArgumentException( cause );
}
else if ( cause instanceof TransientObjectException ) {
try {
sharedSessionContract.markForRollbackOnly();
}
catch (Exception ne) {
//we do not want the subsequent exception to swallow the original one
log.unableToMarkForRollbackOnTransientObjectException( ne );
}
return new IllegalStateException( e ); //Spec 3.2.3 Synchronization rules
}
else {
final PersistenceException converted = new PersistenceException( cause );
handlePersistenceException( converted );
return converted;
}
return new IllegalStateException( e ); //Spec 3.2.3 Synchronization rules
}
else {
final PersistenceException converted = new PersistenceException( cause );
handlePersistenceException( converted );
return converted;
if ( e instanceof QueryException ) {
return e;
}
else if ( e instanceof MultipleBagFetchException ) {
return e;
}
else {
try {
sharedSessionContract.markForRollbackOnly();
}
catch (Exception ne) {
//we do not want the subsequent exception to swallow the original one
log.unableToMarkForRollbackOnTransientObjectException( ne );
}
return e;
}
}
}