Search code examples
javaspringexceptionrepository

Spring. How exception translation works?


I have following code:

@Repository
public class UserDAOImpl implements UserDAO {
    public void addUser(User user) {
        throw new HibernateException("unchecked exception");
    }
}

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDAO userDAO;

    @Override
    public void addUser(User user) {
        try {
            userDAO.addUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

web.xml:

<context:component-scan base-package="org.example.dao,
                                      org.example.services"/>
<mvc:annotation-driven />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

Is it enough to translate exception? Should I to implement custom translator?

It would be nice to get example code.


Solution

  • Basically, Spring Framework and other Spring related Projects (such as Spring Data NoSQL), define a thorough hierarchy of persistence exception inheriting from org.springframework .dao.DataAccessException. This hierarchy takes care of all the exception that are thrown by JDBC, Hibernate, other ORM implemntations, and JPA, etc.

    In your webapplication, You need to do two things to achieve exception translation.

    First, configure org.springframework.dao.support .PersistenceExceptionTranslator implementation(s) in your configuration files. You can do this by defining a bean of LocalContainerEntityManagerFactoryBean in your root config class like this:

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
      Map<String, Object> properties = new Hashtable<>();
      properties.put(
          "javax.persistence.schema-generation.database.action",
          "none");
    
      HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    
      //you will chose a dialect that you are using for your project.
      adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");  
    
      LocalContainerEntityManagerFactoryBean factory = 
          new LocalContainerEntityManagerFactoryBean();
      factory.setJpaVendorAdapter(adapter);
      factory.setDataSource(this.springJpaDataSource());
    
      //the packages that contains you @Repositories annotations
      factory.setPackagesToScan("packagenames"); 
    
      factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
      factory.setValidationMode(ValidationMode.NONE);
      factory.setJpaPropertyMap(properties);
      return factory;
    }
    

    This class LocalContainerEntityManagerFactoryBean implements PersistenceExceptionTranslator. So you have taken care of first step.

    The second step is to mark your repositories/entities with @Repository annotation. This tells Spring that the annotated bean is eligible for exception translation using the configured PersistenceExceptionTranslators. If the repository methods throw any persistence exceptions, the PersistenceExceptionTranslators translate those exceptions as appropriate.

    Excerpts from Professional Java for Web Applications by Nicholas S. Williams.