diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaSystemException.java b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaSystemException.java index 250b5ebfb3..0b879063cf 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/JpaSystemException.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/JpaSystemException.java @@ -36,4 +36,8 @@ public class JpaSystemException extends UncategorizedDataAccessException { super(ex.getMessage(), ex); } + public JpaSystemException(RuntimeException ex) { + super(ex.getMessage(), ex); + } + } diff --git a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java index 037da1f4ce..49fa9eaaf6 100644 --- a/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java +++ b/spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java @@ -24,14 +24,43 @@ import javax.persistence.PersistenceException; import org.hibernate.FlushMode; import org.hibernate.HibernateException; +import org.hibernate.NonUniqueObjectException; +import org.hibernate.NonUniqueResultException; +import org.hibernate.ObjectDeletedException; +import org.hibernate.OptimisticLockException; +import org.hibernate.PersistentObjectException; +import org.hibernate.PessimisticLockException; +import org.hibernate.PropertyValueException; +import org.hibernate.QueryException; +import org.hibernate.QueryTimeoutException; import org.hibernate.Session; +import org.hibernate.StaleObjectStateException; +import org.hibernate.StaleStateException; +import org.hibernate.TransientObjectException; +import org.hibernate.UnresolvableObjectException; +import org.hibernate.WrongClassException; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.DataException; +import org.hibernate.exception.JDBCConnectionException; +import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.SQLGrammarException; +import org.springframework.dao.CannotAcquireLockException; import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.dao.PessimisticLockingFailureException; import org.springframework.jdbc.datasource.ConnectionHandle; import org.springframework.jdbc.support.JdbcUtils; -import org.springframework.orm.hibernate3.SessionFactoryUtils; +import org.springframework.orm.ObjectOptimisticLockingFailureException; +import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.jpa.DefaultJpaDialect; import org.springframework.orm.jpa.EntityManagerFactoryUtils; +import org.springframework.orm.jpa.JpaSystemException; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.util.ClassUtils; @@ -48,6 +77,28 @@ import org.springframework.util.ReflectionUtils; @SuppressWarnings("serial") public class HibernateJpaDialect extends DefaultJpaDialect { + private static Class optimisticLockExceptionClass; + + private static Class pessimisticLockExceptionClass; + + static { + // Checking for Hibernate 4.x's Optimistic/PessimisticEntityLockException + ClassLoader cl = HibernateJpaDialect.class.getClassLoader(); + try { + optimisticLockExceptionClass = cl.loadClass("org.hibernate.dialect.lock.OptimisticEntityLockException"); + } + catch (ClassNotFoundException ex) { + optimisticLockExceptionClass = OptimisticLockException.class; + } + try { + pessimisticLockExceptionClass = cl.loadClass("org.hibernate.dialect.lock.PessimisticEntityLockException"); + } + catch (ClassNotFoundException ex) { + pessimisticLockExceptionClass = null; + } + } + + @Override public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition) throws PersistenceException, SQLException, TransactionException { @@ -97,14 +148,101 @@ public class HibernateJpaDialect extends DefaultJpaDialect { @Override public DataAccessException translateExceptionIfPossible(RuntimeException ex) { if (ex instanceof HibernateException) { - return SessionFactoryUtils.convertHibernateAccessException((HibernateException) ex); + return convertHibernateAccessException((HibernateException) ex); } if (ex instanceof PersistenceException && ex.getCause() instanceof HibernateException) { - return SessionFactoryUtils.convertHibernateAccessException((HibernateException) ex.getCause()); + return convertHibernateAccessException((HibernateException) ex.getCause()); } return EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex); } + /** + * Convert the given HibernateException to an appropriate exception + * from the {@code org.springframework.dao} hierarchy. + * @param ex HibernateException that occurred + * @return the corresponding DataAccessException instance + */ + protected DataAccessException convertHibernateAccessException(HibernateException ex) { + if (ex instanceof JDBCConnectionException) { + return new DataAccessResourceFailureException(ex.getMessage(), ex); + } + if (ex instanceof SQLGrammarException) { + SQLGrammarException jdbcEx = (SQLGrammarException) ex; + return new InvalidDataAccessResourceUsageException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); + } + if (ex instanceof QueryTimeoutException) { + QueryTimeoutException jdbcEx = (QueryTimeoutException) ex; + return new org.springframework.dao.QueryTimeoutException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); + } + if (ex instanceof LockAcquisitionException) { + LockAcquisitionException jdbcEx = (LockAcquisitionException) ex; + return new CannotAcquireLockException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); + } + if (ex instanceof PessimisticLockException) { + PessimisticLockException jdbcEx = (PessimisticLockException) ex; + return new PessimisticLockingFailureException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); + } + if (ex instanceof ConstraintViolationException) { + ConstraintViolationException jdbcEx = (ConstraintViolationException) ex; + return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + + "]; constraint [" + jdbcEx.getConstraintName() + "]", ex); + } + if (ex instanceof DataException) { + DataException jdbcEx = (DataException) ex; + return new DataIntegrityViolationException(ex.getMessage() + "; SQL [" + jdbcEx.getSQL() + "]", ex); + } + // end of JDBCException subclass handling + + if (ex instanceof QueryException) { + return new InvalidDataAccessResourceUsageException(ex.getMessage(), ex); + } + if (ex instanceof NonUniqueResultException) { + return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); + } + if (ex instanceof NonUniqueObjectException) { + return new DuplicateKeyException(ex.getMessage(), ex); + } + if (ex instanceof PropertyValueException) { + return new DataIntegrityViolationException(ex.getMessage(), ex); + } + if (ex instanceof PersistentObjectException) { + return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); + } + if (ex instanceof TransientObjectException) { + return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); + } + if (ex instanceof ObjectDeletedException) { + return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); + } + if (ex instanceof UnresolvableObjectException) { + UnresolvableObjectException hibEx = (UnresolvableObjectException) ex; + return new ObjectRetrievalFailureException(hibEx.getEntityName(), hibEx.getIdentifier(), ex.getMessage(), ex); + } + if (ex instanceof WrongClassException) { + WrongClassException hibEx = (WrongClassException) ex; + return new ObjectRetrievalFailureException(hibEx.getEntityName(), hibEx.getIdentifier(), ex.getMessage(), ex); + } + if (ex instanceof StaleObjectStateException) { + StaleObjectStateException hibEx = (StaleObjectStateException) ex; + return new ObjectOptimisticLockingFailureException(hibEx.getEntityName(), hibEx.getIdentifier(), ex); + } + if (ex instanceof StaleStateException) { + return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex); + } + if (optimisticLockExceptionClass.isInstance(ex)) { + return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex); + } + if (pessimisticLockExceptionClass != null && pessimisticLockExceptionClass.isInstance(ex)) { + if (ex.getCause() instanceof LockAcquisitionException) { + return new CannotAcquireLockException(ex.getMessage(), ex.getCause()); + } + return new PessimisticLockingFailureException(ex.getMessage(), ex); + } + + // fallback + return new JpaSystemException(ex); + } + protected Session getSession(EntityManager em) { return em.unwrap(Session.class); }