or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

exception-translation.mdhibernate-configuration.mdhibernate-transaction-management.mdindex.mdjpa-configuration.mdjpa-transaction-management.mdjpa-vendor-adapters.mdpersistence-unit-management.mdshared-resources.mdutility-classes.mdweb-integration.md
tile.json

exception-translation.mddocs/

Exception Translation

Exception translation from JPA and Hibernate exceptions to Spring's DataAccessException hierarchy for consistent error handling across persistence technologies.

Quick Reference

Spring automatically translates JPA/Hibernate exceptions to DataAccessException:

@Service
@Transactional
public class UserService {

    @PersistenceContext
    private EntityManager entityManager;

    public User findById(Long id) {
        try {
            User user = entityManager.find(User.class, id);
            if (user == null) {
                throw new EntityNotFoundException("User not found: " + id);
            }
            return user;
        } catch (EntityNotFoundException ex) {
            // Automatically translated to JpaObjectRetrievalFailureException
            throw ex;
        }
    }

    public void updateUser(User user) {
        try {
            entityManager.merge(user);
        } catch (OptimisticLockException ex) {
            // Automatically translated to JpaOptimisticLockingFailureException
            throw ex;
        }
    }
}

JPA Exception Classes

// Entity not found
class JpaObjectRetrievalFailureException extends ObjectRetrievalFailureException {
    JpaObjectRetrievalFailureException(EntityNotFoundException ex);
}

// Optimistic locking failure
class JpaOptimisticLockingFailureException extends ObjectOptimisticLockingFailureException {
    JpaOptimisticLockingFailureException(OptimisticLockException ex);
}

// Uncategorized errors
class JpaSystemException extends UncategorizedDataAccessException {
    JpaSystemException(RuntimeException ex);
}

Core ORM Exception Classes

// Optimistic locking violation
class ObjectOptimisticLockingFailureException extends OptimisticLockingFailureException {

    ObjectOptimisticLockingFailureException(Class<?> persistentClass, Object identifier);
    ObjectOptimisticLockingFailureException(String persistentClassName, Object identifier);
    ObjectOptimisticLockingFailureException(
        Class<?> persistentClass, Object identifier, String msg, Throwable cause);

    Class<?> getPersistentClass();
    String getPersistentClassName();
    Object getIdentifier();
}

// Object not found
class ObjectRetrievalFailureException extends DataRetrievalFailureException {

    ObjectRetrievalFailureException(Class<?> persistentClass, Object identifier);
    ObjectRetrievalFailureException(String persistentClassName, Object identifier);
    ObjectRetrievalFailureException(
        Class<?> persistentClass, Object identifier, String msg, Throwable cause);

    Class<?> getPersistentClass();
    String getPersistentClassName();
    Object getIdentifier();
}

Exception Handling Examples

Global Exception Handler

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(JpaObjectRetrievalFailureException.class)
    public ResponseEntity<ErrorResponse> handleObjectNotFound(
            JpaObjectRetrievalFailureException ex) {
        ErrorResponse error = new ErrorResponse();
        error.setMessage("Entity not found: " +
            ex.getPersistentClassName() + " with id " + ex.getIdentifier());
        error.setStatus(HttpStatus.NOT_FOUND.value());

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @ExceptionHandler(JpaOptimisticLockingFailureException.class)
    public ResponseEntity<ErrorResponse> handleOptimisticLocking(
            JpaOptimisticLockingFailureException ex) {
        ErrorResponse error = new ErrorResponse();
        error.setMessage("The entity was modified by another transaction. " +
            "Please reload and try again.");
        error.setStatus(HttpStatus.CONFLICT.value());

        return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
    }

    @ExceptionHandler(JpaSystemException.class)
    public ResponseEntity<ErrorResponse> handleJpaSystemException(
            JpaSystemException ex) {
        ErrorResponse error = new ErrorResponse();
        error.setMessage("A system error occurred: " + ex.getMessage());
        error.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }

    @ExceptionHandler(DataAccessException.class)
    public ResponseEntity<ErrorResponse> handleDataAccessException(
            DataAccessException ex) {
        ErrorResponse error = new ErrorResponse();
        error.setMessage("Data access error: " + ex.getMessage());
        error.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
    }
}

Service Layer Exception Handling

@Service
@Transactional
public class OrderService {

    @PersistenceContext
    private EntityManager entityManager;

    public Order createOrder(OrderRequest request) {
        try {
            // Verify product exists
            Product product = entityManager.find(Product.class, request.getProductId());
            if (product == null) {
                throw new ObjectRetrievalFailureException(
                    Product.class, request.getProductId());
            }

            // Create order
            Order order = new Order();
            order.setProduct(product);
            order.setQuantity(request.getQuantity());

            entityManager.persist(order);
            return order;

        } catch (EntityNotFoundException ex) {
            // Translated to JpaObjectRetrievalFailureException
            throw ex;
        } catch (PersistenceException ex) {
            // Translated to JpaSystemException
            throw ex;
        }
    }

    public void updateOrder(Long orderId, int newQuantity) {
        try {
            Order order = entityManager.find(Order.class, orderId);
            if (order == null) {
                throw new ObjectRetrievalFailureException(Order.class, orderId);
            }

            order.setQuantity(newQuantity);
            entityManager.merge(order);

        } catch (OptimisticLockException ex) {
            // Translated to JpaOptimisticLockingFailureException
            throw new ObjectOptimisticLockingFailureException(
                Order.class, orderId,
                "Order was modified by another user", ex
            );
        }
    }
}

Hibernate Exception Translator

For Hibernate-specific exception translation:

import org.springframework.orm.hibernate5.HibernateExceptionTranslator;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;

@Configuration
public class HibernateConfig {

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator(
            DataSource dataSource) {
        HibernateExceptionTranslator translator = new HibernateExceptionTranslator();

        // Use custom JDBC exception translator
        SQLExceptionTranslator jdbcTranslator =
            new SQLErrorCodeSQLExceptionTranslator(dataSource);
        translator.setJdbcExceptionTranslator(jdbcTranslator);

        return translator;
    }
}

API Reference

class HibernateExceptionTranslator implements PersistenceExceptionTranslator {

    // Set JDBC exception translator
    void setJdbcExceptionTranslator(SQLExceptionTranslator translator);

    // Translate exception
    DataAccessException translateExceptionIfPossible(RuntimeException ex);
}

@FunctionalInterface
interface PersistenceExceptionTranslator {

    // Returns null if exception should not be translated
    DataAccessException translateExceptionIfPossible(RuntimeException ex);
}

Common DataAccessException Subclasses

ExceptionDescription
DataIntegrityViolationExceptionConstraint violations (unique, foreign key, etc.)
DataAccessResourceFailureExceptionResource failures (connection lost, etc.)
InvalidDataAccessApiUsageExceptionInvalid use of persistence API
OptimisticLockingFailureExceptionOptimistic locking violations
PessimisticLockingFailureExceptionPessimistic locking failures
DataRetrievalFailureExceptionFailed to retrieve data
UncategorizedDataAccessExceptionUncategorized or unknown errors

These exceptions allow consistent error handling regardless of the underlying persistence technology (JPA, Hibernate, JDBC, etc.).

Related Topics

  • JPA Transaction Management - Transaction configuration
  • Utility Classes - Exception translation utilities