I'd really rather not get into supporting arbitrary ExceptionConverter strategies.. JPA-compliant and then "native"-compliant are plenty.
I thought we had added a `hibernate.jpa.compliance.exception` setting, but I see it is not there. On Tue, May 15, 2018 at 1:52 PM Gail Badner <gbad...@redhat.com> wrote: > I've been looking at differences in Hibernate exception handling for > applications that uses "native" (non-JPA) Hibernate when moving from 5.1 to > 5.3. > > As you know, exception handling changed in 5.2 when > hibernate-entitymanager was merged into hibernate-core. This change is > documented in the 5.2 migration guide. [1] > > Here is the relevant text: > > "org.hibernate.HibernateException now extends > javax.persistence.PersistenceExceptions. Hibernate methods that "override" > methods from their JPA counterparts now will also throw various JDK defined > RuntimeExceptions (such as IllegalArgumentException, IllegalStateException, > etc) as required by the JPA contract." > > While digging into this, I see that a HibernateException thrown when using > 5.1 may, in 5.3, be unwrapped, or may be wrapped by a PersistenceException > (or a subclass), IllegalArgumentException, or IllegalStateException, > depending on the particular operation being performed when the > HibernateException is thrown. > > The reason why the exceptions may be wrapped or unwrapped is because > Hibernate converts exceptions (via > AbstractSharedSessionContract#exceptionConverter) for JPA operations which > may wrap the HibernateException or throw a different exception. Hibernate > does not convert exceptions from strictly "native" operations, so those > exceptions remain unwrapped. > > Here are a couple of examples to illustrate: > > 1) A HibernateException (org.hibernate.TransientObjectException) was > thrown in 5.1. In 5.3, the same condition can result in > org.hibernate.TransientObjectException that is either unwrapped, or wrapped > by IllegalStateException. I've pushed a test to my fork to illustrate. [2] > > Thrown during Session#save, #saveOrUpdate > In 5.1: org.hibernate.TransientObjectException (unwrapped) > In 5.3: org.hibernate.TransientObjectException (unwrapped) > > Thrown during Session#persist, #merge, #flush > In 5.1, org.hibernate.TransientObjectException (unwrapped) > In 5.3, org.hibernate.TransientObjectException wrapped by > IllegalStateException > > 2) A HibernateException thrown when using 5.1 may be wrapped by a > PersistenceException, even though HibernateException already extends > PersistenceException. > > For example, see TransactionTimeoutTest#testTransactionTimeoutFailure: > > https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/test/java/org/hibernate/test/tm/TransactionTimeoutTest.java#L60-L82 > > The exception thrown by the test indicates that the transaction timed out. > This exception is important enough that an application might retry the > operation, or at least log for future investigation. > > Thrown during Session#persist (or when changed to use Session#merge or > Session#flush): > In 5.1: org.hibernate.TransactionException (unwrapped) > In 5.3: org.hibernate.TransactionException wrapped by > javax.persistence.PersistenceException > > Thrown if the test is changed to use Session#save or #saveOrUpdate instead: > In 5.1: org.hibernate.TransactionException (unwrapped) > In 5.3: org.hibernate.TransactionException (unwrapped) > > Similarly, by adding some logging, I see that HibernateException objects > can be wrapped by PersistenceException when running the 5.3 hibernate-core > unit tests. Depending on the context, I see that some of the following > exceptions can be wrapped or unwrapped. > > org.hibernate.exception.ConstraintViolationException > org.hibernate.exception.DataException > org.hibernate.exception.GenericJDBCException > org.hibernate.exception.SQLGrammarException > org.hibernate.id.IdentifierGenerationException > org.hibernate.loader.custom.NonUniqueDiscoveredSqlAliasException > org.hibernate.PersistentObjectException > org.hibernate.PropertyAccessException > org.hibernate.PropertyValueException > org.hibernate.TransactionException > > You can see an example using > org.hibernate.exception.ConstraintViolationException at [3]. > > In order to deal with these differences, an application could change the > following (which was appropriate for 5.1): > > try { > ... > } > catch (HibernateException ex) { > procressHibernateException( ex ); > } > > to the following for 5.3: > > try { > ... > } > catch (PersistenceException | IllegalStateException | > IllegalArgumentException ex) { > if ( HibernateException.class.isInstance( ex ) ) { > handleHibernateException( (HibernateException) ex ); > } > else if ( HibernateException.class.isInstance( ex.getCause() ) ) { > handleHibernateException( (HibernateException) ex.getCause() ); > } > } > > IMO, it's a little clumsy having to deal with both wrapped and unwrapped > exceptions. It would be better if exceptions were consistently wrapped, or > consistently unwrapped. > > I haven't had much of a chance to think about how we can deal with this, > but one thing that comes to mind is to allow an application to choose a > particular ExceptionConverter implementation. Hibernate would need to be > changed to always convert exceptions (including for strictly native > operations) before returning to the application. > > For example, a property, hibernate.exception_converter could be added with > the following values: > > jpa - default for JPA applications > (org.hibernate.internal.ExceptionConverterImpl) > native (or legacy?) - default for native applications that does not wrap > HibernateException > fully-qualified class name that implements ExceptionConverter > > If users have to make changes to exception handling for 5.3, do you think > they would be willing to change their application to use JPA exceptions > (i.e., hibernate.exception_converter=jpa)? > > Comments? > > Regards, > Gail > > [1] > https://github.com/hibernate/hibernate-orm/blob/5.2/migration-guide.adoc > [2] > https://github.com/gbadner/hibernate-core/blob/exception-compatibility/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/ORMTransientObjectExceptionUnitTestCase.java > [3] > https://github.com/gbadner/hibernate-core/blob/exception-compatibility/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/ORMConstraintViolationExceptionUnitTestCase.java > > > _______________________________________________ hibernate-dev mailing list hibernate-dev@lists.jboss.org https://lists.jboss.org/mailman/listinfo/hibernate-dev