vedamen
Apr 2nd, 2009, 06:44 AM
The @Repository annotation was introduced to add Spring exception translation to your DAO. I created 2 small examples, one with the @Repository and one without the @Repository, and it seems that both examples do both the spring exception translation. both examples throw a spring exception. I expected that the one without the @Repository should throw a Hibernate exception, and the one with @Repository should throw a Spring exception. Any ideas?
These examples are JPA examples, but I tried the same with Hibernate and I got the same result.
The application: I add two entities with the same id to generate an exception.
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("springconfig.xml");
PersonDao personDao = (PersonDao) context.getBean("personDAO");
// create 2 persons and save them in the database
Person fbperson = new Person(1, "Frank Brown");
personDao.savePerson(fbperson);
Person mjperson = new Person(1, "Mary Jones");
personDao.savePerson(mjperson);
}
}
The entity where I generate the id myself.
@Entity
public class Person {
@Id
private long id;
private String name;
...
}
The DAO class without the @Repository
@Transactional
public class PersonDaoImpl implements PersonDao {
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void savePerson(Person person){
entityManager.persist(person);
}
}
The spring configuration file
<tx:annotation-driven transaction-manager="jpatransactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnn otationBeanPostProcessor" />
<bean id="personDAO" class="PersonDaoImpl" />
<!-- the datasource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerD ataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:hsql://localhost/mydb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityMa nagerFactoryBean">
<property name="persistenceXmlLocation"
value="persistence.xml" />
<property name="persistenceUnitName" value="jpaunit" />
<property name="dataSource" ref="dataSource" />
<!-- specify Hibernate as the the JPA provider -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVen dorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto ">create</prop>
</props>
</property>
</bean>
<!-- The transaction manager for JPA -->
<bean id="jpatransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="jpaunit">
<class>Person</class>
<exclude-unlisted-classes/>
</persistence-unit>
</persistence>
The output:
Exception in thread "main" org.springframework.orm.hibernate3.HibernateJdbcEx ception: JDBC exception on Hibernate data access: SQLException for SQL [insert into Person (name, id) values (?, ?)]; SQL state [null]; error code [0]; Could not execute JDBC batch update; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: java.sql.BatchUpdateException: failed batch
...
So we get a sql BatchUpdateException exception, that is wrapped by a hibernate GenericJDBCException which is wrapped by a spring HibernateJdbcException (which is a spring DataAccessException)
So we have already Spring exception translation.
When I add the @Repository annotation to the DAO and the PersistenceExceptionTranslationPostProcessor bean to the spring configuration file, I get the same output:
@Transactional
@Repository
public class PersonDaoImpl implements PersonDao {
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void savePerson(Person person){
entityManager.persist(person);
}
}
add the following bean to the spring XML configuration file:
<bean class="org.springframework.dao.annotation.PersistenceExce ptionTranslationPostProcessor"/>
I get the same output:
Exception in thread "main" org.springframework.orm.hibernate3.HibernateJdbcEx ception: JDBC exception on Hibernate data access: SQLException for SQL [insert into Person (name, id) values (?, ?)]; SQL state [null]; error code [0]; Could not execute JDBC batch update; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: java.sql.BatchUpdateException: failed batch
...
So it seems that the @Repository does not change anything.
These examples are JPA examples, but I tried the same with Hibernate and I got the same result.
The application: I add two entities with the same id to generate an exception.
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("springconfig.xml");
PersonDao personDao = (PersonDao) context.getBean("personDAO");
// create 2 persons and save them in the database
Person fbperson = new Person(1, "Frank Brown");
personDao.savePerson(fbperson);
Person mjperson = new Person(1, "Mary Jones");
personDao.savePerson(mjperson);
}
}
The entity where I generate the id myself.
@Entity
public class Person {
@Id
private long id;
private String name;
...
}
The DAO class without the @Repository
@Transactional
public class PersonDaoImpl implements PersonDao {
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void savePerson(Person person){
entityManager.persist(person);
}
}
The spring configuration file
<tx:annotation-driven transaction-manager="jpatransactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnn otationBeanPostProcessor" />
<bean id="personDAO" class="PersonDaoImpl" />
<!-- the datasource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerD ataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:hsql://localhost/mydb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityMa nagerFactoryBean">
<property name="persistenceXmlLocation"
value="persistence.xml" />
<property name="persistenceUnitName" value="jpaunit" />
<property name="dataSource" ref="dataSource" />
<!-- specify Hibernate as the the JPA provider -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVen dorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto ">create</prop>
</props>
</property>
</bean>
<!-- The transaction manager for JPA -->
<bean id="jpatransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="jpaunit">
<class>Person</class>
<exclude-unlisted-classes/>
</persistence-unit>
</persistence>
The output:
Exception in thread "main" org.springframework.orm.hibernate3.HibernateJdbcEx ception: JDBC exception on Hibernate data access: SQLException for SQL [insert into Person (name, id) values (?, ?)]; SQL state [null]; error code [0]; Could not execute JDBC batch update; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: java.sql.BatchUpdateException: failed batch
...
So we get a sql BatchUpdateException exception, that is wrapped by a hibernate GenericJDBCException which is wrapped by a spring HibernateJdbcException (which is a spring DataAccessException)
So we have already Spring exception translation.
When I add the @Repository annotation to the DAO and the PersistenceExceptionTranslationPostProcessor bean to the spring configuration file, I get the same output:
@Transactional
@Repository
public class PersonDaoImpl implements PersonDao {
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void savePerson(Person person){
entityManager.persist(person);
}
}
add the following bean to the spring XML configuration file:
<bean class="org.springframework.dao.annotation.PersistenceExce ptionTranslationPostProcessor"/>
I get the same output:
Exception in thread "main" org.springframework.orm.hibernate3.HibernateJdbcEx ception: JDBC exception on Hibernate data access: SQLException for SQL [insert into Person (name, id) values (?, ?)]; SQL state [null]; error code [0]; Could not execute JDBC batch update; nested exception is org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
...
Caused by: java.sql.BatchUpdateException: failed batch
...
So it seems that the @Repository does not change anything.