diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml
index 62c1f348f..2c3e648ea 100644
--- a/spring-batch-infrastructure/pom.xml
+++ b/spring-batch-infrastructure/pom.xml
@@ -4,8 +4,8 @@
spring-batch-infrastructure
jar
Infrastructure
-
http://static.springframework.org/spring-batch/${project.artifactId}
@@ -108,7 +108,7 @@
derby
test
-
+
+
+ org.hibernate
+ hibernate-core
+ 4.1.9.Final
+ true
+
+
+ org.hibernate
+ hibernate-entitymanager
+ 4.1.9.Final
+
+
org.hibernate
hibernate-annotations
true
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemWriter.java
index 228567b1c..d117fff7e 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemWriter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemWriter.java
@@ -19,11 +19,12 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.hibernate.Session;
import org.hibernate.SessionFactory;
+import org.hibernate.context.spi.CurrentSessionContext;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.hibernate3.HibernateOperations;
-import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.Assert;
/**
@@ -34,11 +35,21 @@ import org.springframework.util.Assert;
* default (see {@link #setClearSession(boolean) clearSession} property).
*
*
+<<<<<<< HEAD
* The writer is thread safe after its properties are set (normal singleton
* behavior), so it can be used to write in multiple concurrent transactions.
*
* @author Dave Syer
* @author Thomas Risberg
+=======
+ * The writer is thread safe once properties are set (normal singleton behavior)
+ * if a {@link CurrentSessionContext} that uses only one session per thread is
+ * used.
+ *
+ * @author Dave Syer
+ * @author Thomas Risberg
+ * @author Michael Minella
+>>>>>>> BATCH-1904: Updated to support Hibernate 4
*
*/
public class HibernateItemWriter implements ItemWriter, InitializingBean {
@@ -47,6 +58,7 @@ public class HibernateItemWriter implements ItemWriter, InitializingBean {
.getLog(HibernateItemWriter.class);
private HibernateOperations hibernateTemplate;
+ private SessionFactory sessionFactory;
private boolean clearSession = true;
@@ -66,19 +78,19 @@ public class HibernateItemWriter implements ItemWriter, InitializingBean {
*
* @param hibernateTemplate
* the hibernateTemplate to set
+ * @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
*/
public void setHibernateTemplate(HibernateOperations hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
/**
- * Set the Hibernate SessionFactory to be used internally. Will
- * automatically create a HibernateTemplate for the given SessionFactory.
+ * Set the Hibernate SessionFactory to be used internally.
*
- * @see #setHibernateTemplate
+ * @param sessionFactory session factory to be used by the writer
*/
public final void setSessionFactory(SessionFactory sessionFactory) {
- this.hibernateTemplate = new HibernateTemplate(sessionFactory);
+ this.sessionFactory = sessionFactory;
}
/**
@@ -86,8 +98,8 @@ public class HibernateItemWriter implements ItemWriter, InitializingBean {
*/
@Override
public void afterPropertiesSet() {
- Assert.notNull(hibernateTemplate,
- "HibernateItemWriter requires a HibernateOperations");
+ Assert.state(!(hibernateTemplate == null && sessionFactory == null),
+ "Either HibernateOperations or SessionFactory must be provided");
}
/**
@@ -98,21 +110,70 @@ public class HibernateItemWriter implements ItemWriter, InitializingBean {
*/
@Override
public final void write(List extends T> items) {
- doWrite(hibernateTemplate, items);
- hibernateTemplate.flush();
- if (clearSession) {
- hibernateTemplate.clear();
+ if(sessionFactory == null) {
+ doWrite(hibernateTemplate, items);
+ hibernateTemplate.flush();
+ if (clearSession) {
+ hibernateTemplate.clear();
+ }
+ }
+ else {
+ doWrite(sessionFactory, items);
+ sessionFactory.getCurrentSession().flush();
+ if(clearSession) {
+ sessionFactory.getCurrentSession().clear();
+ }
}
}
/**
- * Do perform the actual write operation. This can be overridden in a
- * subclass if necessary.
+ * Do perform the actual write operation using Hibernate's API.
+ * This can be overridden in a subclass if necessary.
*
* @param hibernateTemplate
* the HibernateTemplate to use for the operation
* @param items
* the list of items to use for the write
+ * @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
+ */
+ protected void doWrite(SessionFactory sessionFactory, List extends T> items) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Writing to Hibernate with " + items.size()
+ + " items.");
+ }
+
+ Session currentSession = sessionFactory.getCurrentSession();
+
+ if (!items.isEmpty()) {
+ long saveOrUpdateCount = 0;
+ for (T item : items) {
+ if (!currentSession.contains(item)) {
+ currentSession.saveOrUpdate(item);
+ saveOrUpdateCount++;
+ }
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug(saveOrUpdateCount + " entities saved/updated.");
+ logger.debug((items.size() - saveOrUpdateCount)
+ + " entities found in session.");
+ }
+ }
+ }
+
+ /**
+<<<<<<< HEAD
+ * Do perform the actual write operation. This can be overridden in a
+ * subclass if necessary.
+=======
+ * Do perform the actual write operation using {@link HibernateOperations}.
+ * This can be overridden in a subclass if necessary.
+>>>>>>> BATCH-1904: Updated to support Hibernate 4
+ *
+ * @param hibernateTemplate
+ * the HibernateTemplate to use for the operation
+ * @param items
+ * the list of items to use for the write
+ * @deprecated As of 2.2 in favor of using Hibernate's session management APIs directly
*/
protected void doWrite(HibernateOperations hibernateTemplate,
List extends T> items) {
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/AbstractHibernateCursorItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/AbstractHibernateCursorItemReaderIntegrationTests.java
index 96fed400b..e3f6147af 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/AbstractHibernateCursorItemReaderIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/AbstractHibernateCursorItemReaderIntegrationTests.java
@@ -6,18 +6,18 @@ import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.sample.Foo;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
-import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
+import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
/**
* Tests for {@link HibernateCursorItemReader} using {@link StatelessSession}.
- *
+ *
* @author Robert Kasanicky
* @author Dave Syer
*/
public abstract class AbstractHibernateCursorItemReaderIntegrationTests extends
- AbstractGenericDataSourceItemReaderIntegrationTests {
+AbstractGenericDataSourceItemReaderIntegrationTests {
- @Override
+ @Override
protected ItemReader createItemReader() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
@@ -26,7 +26,7 @@ public abstract class AbstractHibernateCursorItemReaderIntegrationTests extends
customizeSessionFactory(factoryBean);
factoryBean.afterPropertiesSet();
- SessionFactory sessionFactory = (SessionFactory) factoryBean.getObject();
+ SessionFactory sessionFactory = factoryBean.getObject();
HibernateCursorItemReader hibernateReader = new HibernateCursorItemReader();
setQuery(hibernateReader);
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java
index 027b0fc1e..5a97d5510 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderCommonTests.java
@@ -1,21 +1,21 @@
package org.springframework.batch.item.database;
import org.hibernate.SessionFactory;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.sample.Foo;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
-import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
@RunWith(JUnit4.class)
public class HibernateCursorItemReaderCommonTests extends AbstractDatabaseItemStreamItemReaderTests {
- @Override
+ @Override
protected ItemReader getItemReader() throws Exception {
-
+
SessionFactory sessionFactory = createSessionFactory();
String hsqlQuery = "from Foo";
@@ -30,18 +30,18 @@ public class HibernateCursorItemReaderCommonTests extends AbstractDatabaseItemSt
return reader;
}
-
+
private SessionFactory createSessionFactory() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(getDataSource());
factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
-
- return (SessionFactory) factoryBean.getObject();
+
+ return factoryBean.getObject();
}
- @Override
+ @Override
protected void pointToEmptyInput(ItemReader tested) throws Exception {
HibernateCursorItemReader reader = (HibernateCursorItemReader) tested;
reader.close();
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulIntegrationTests.java
index 84c6e404a..3f53cfb39 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulIntegrationTests.java
@@ -7,28 +7,28 @@ import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import org.hibernate.Query;
+import org.hibernate.Session;
import org.hibernate.SessionFactory;
-import org.hibernate.classic.Session;
import org.junit.Test;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.sample.Foo;
/**
* Tests for {@link HibernateCursorItemReader} using standard hibernate {@link Session}.
- *
+ *
* @author Robert Kasanicky
*/
public class HibernateCursorItemReaderStatefulIntegrationTests extends AbstractHibernateCursorItemReaderIntegrationTests {
- @Override
+ @Override
protected boolean isUseStatelessSession() {
return false;
}
-
+
//Ensure close is called on the stateful session correctly.
@Test
public void testStatefulClose(){
-
+
SessionFactory sessionFactory = createMock(SessionFactory.class);
Session session = createMock(Session.class);
Query scrollableResults = createNiceMock(Query.class);
@@ -36,21 +36,21 @@ public class HibernateCursorItemReaderStatefulIntegrationTests extends AbstractH
itemReader.setSessionFactory(sessionFactory);
itemReader.setQueryString("testQuery");
itemReader.setUseStatelessSession(false);
-
+
expect(sessionFactory.openSession()).andReturn(session);
expect(session.createQuery("testQuery")).andReturn(scrollableResults);
expect(scrollableResults.setFetchSize(0)).andReturn(scrollableResults);
expect(session.close()).andReturn(null);
-
+
replay(sessionFactory);
replay(session);
replay(scrollableResults);
-
+
itemReader.open(new ExecutionContext());
itemReader.close();
-
+
verify(sessionFactory);
verify(session);
}
-
+
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorProjectionItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorProjectionItemReaderIntegrationTests.java
index 190e17a1f..6f975f7eb 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorProjectionItemReaderIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorProjectionItemReaderIntegrationTests.java
@@ -14,13 +14,13 @@ import org.springframework.batch.item.ExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
-import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
+import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Tests for {@link HibernateCursorItemReader} using {@link StatelessSession}.
- *
+ *
* @author Robert Kasanicky
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -39,7 +39,7 @@ public class HibernateCursorProjectionItemReaderIntegrationTests {
"Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
- SessionFactory sessionFactory = (SessionFactory) factoryBean
+ SessionFactory sessionFactory = factoryBean
.getObject();
reader.setQueryString(hsqlQuery);
@@ -49,7 +49,7 @@ public class HibernateCursorProjectionItemReaderIntegrationTests {
reader.open(new ExecutionContext());
}
-
+
@Test
public void testMultipleItemsInProjection() throws Exception {
HibernateCursorItemReader