Jun 29th, 2010, 09:50 AM
How do I translate custom errors when using JPA and Hibernate
We're using Oracle as our backend and have a number of triggers written that enforce some additional checks on the data. These triggers utilize Oracle's RAISE_APPLICATION_ERROR procedure to set the SQLcode and message.
On the front-end, my Dao is annotated with @Repository, and Spring translates the org.hibernate.JDBCException to org.springframework.orm.hibernate3.HibernateExcept ion via SessionFactoryUtils.convertHibernateAccessExceptio n which is called from HibernateJpaDialect.
I'd like the triggers, based on their codes, to be translated to a meaningful exception and message based on my custom exception translator which extends PersistenceExceptionTranslator. Unfortunately, this does not appear to be called.
Is there some way of getting these codes to be mapped to my application specific exceptions and give them meaningful messages rather than seeing the Hibernate exception with the SQL on the front-end screens?
Jun 29th, 2010, 10:20 AM
It appears that you have to define the "PersistenceExceptionTranslationPostProcessor" bean to make this happen. Read the Spring doc for more information.
Jun 29th, 2010, 11:59 AM
I've already defined two beans in my applicationContext.xml file:
<!-- Exception translation bean post processor -->
<bean class="org.springframework.dao.annotation.Persiste nceExceptionTranslationPostProcessor" />
<entry key="20100" value="emine.operator.model.exception.ApplicationL oadInsertException" />
<entry key="20101" value="emine.operator.model.exception.LicenseNotUn iqueException" />
<entry key="20102" value="emine.operator.model.exception.LicenseNotFo undException" />
<entry key="20103" value="emine.operator.model.exception.LicenseAlrea dyRenewedException" />
<entry key="20104" value="emine.operator.model.exception.LicenseInact iveException" />
<entry key="20110" value="emine.operator.model.exception.ApplicationS tatusException" />
<entry key="20201" value="emine.operator.model.exception.ApplicationL ockedException" />
What I'm seeing is that the exception is not translated as the error is not occurring to commit time (inside of JpaTransactionManager's doCommit method). Inside the catch block there, it calls:
DataAccessException dex = getJpaDialect().translateExceptionIfPossible((Runt imeException) ex.getCause());
HibernateJpaDialect makes a call to SessionFactoryUtils to get the exception. The exception is translated to a Spring exception, but there's no CUSTOM exception checking going on at this point in time, at least none that I'm seeing.
I saw this similar thread and it mentions the common exception mapping, but nothing about the custom mapping under JPA:
The JIRA article here (https://jira.springsource.org/browse/SPR-2617) mentions the sql-error-codes.xml but those don't apply to JPA.
It almost seems like the TransactionInterceptor for JPA should be using the PersistenceExceptionTranslationInterceptor which enables the custom exception handling, but I'm just guessing and have no clue what to do with it.
I do appreciate the quick response though.
Jun 30th, 2010, 12:06 AM
It probably is to early, I should do a bit more reading and checking.
IMHO The problem lies in the fact that the PersistenceExceptionTranslationInterceptor is applied BEFORE the tx advice, which means that the transactionamanger is handling the exception. I suggest removing the PersistenceExceptionTranslationPostProcessor and using aop:config to apply the advice and explicitly setting an order making sure it applies AFTER the tx advice (which will make it run inside the tx, so any exception will pass through the interceptor first). Also make sure that it is in the SAME context as the tx advice else it won't work.
However I'm not sure if that would fix it (the exception might get swallowed again, from what I've seen quickly scanning the code) but it should at least call your exceptiontranslator.
After changing and testing a bit more I suggest you still register a JIRA (being it due to the configuration/ordering of interceptors) or the fact that the converted exception gets swallowd again.
Last edited by Marten Deinum; Jun 30th, 2010 at 12:27 AM.
Jun 30th, 2010, 11:31 AM
I'm not sure I'm understanding what you are saying regarding aop:config so I'll have to refer to the manual. I'm using Spring 2.5.6 at this point, and our lead Spring developer just left.
My thought after perusing the code was to redefine the jpaDialect property of my entityManagerFactory to use an over-ridden version. My version would override the translateExceptionIfPossible method and contain a property for my custom PersistenceExceptionTranslator. If the mapped Exception coming from the super.translateExceptionIfPossible call was mapped to Spring's HibernateJdbcException, I'd send it to my custom translator and see if the SQLCODE would map it to a more meaningful exception which is linked to an appropriate error message.
I'm not sure if that's the right approach, but it did appear to do what I wanted.
Jul 1st, 2010, 01:49 AM
Although that solves your problem, you are solving a problem you shouldn't have had in the first place (imho that is ofcourse ). Although I don't know your full configuration I suspect the issue laid out in my previous post.
Tags for this Thread