From 0a92a7752b3c0ebc2cc23ffb5f4424d3ef18ad1f Mon Sep 17 00:00:00 2001 From: robokaso Date: Wed, 7 Jan 2009 13:38:52 +0000 Subject: [PATCH] RESOLVED - BATCH-989: Add support for named queries on HibernateCursorItemReader added setQueryName(..) as alternative to setQueryString(..) --- .../database/HibernateCursorItemReader.java | 77 +++++++++++-------- ...rnateCursorItemReaderIntegrationTests.java | 19 +++-- ...rItemReaderNamedQueryIntegrationTests.java | 13 ++++ ...derStatefulNamedQueryIntegrationTests.java | 14 ++++ .../batch/item/database/Foo.hbm.xml | 17 ++-- 5 files changed, 94 insertions(+), 46 deletions(-) create mode 100644 spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderNamedQueryIntegrationTests.java create mode 100644 spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulNamedQueryIntegrationTests.java diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateCursorItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateCursorItemReader.java index c247f5ed4..9c1cb03ac 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateCursorItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateCursorItemReader.java @@ -33,9 +33,11 @@ import org.springframework.util.ClassUtils; /** * {@link ItemReader} for reading database records built on top of Hibernate. * - * It executes the HQL {@link #setQueryString(String)} when initialized and - * iterates over the result set as {@link #read()} method is called, returning - * an object corresponding to current row. + * It executes the HQL query when initialized iterates over the result set as + * {@link #read()} method is called, returning an object corresponding to + * current row. The query can be set directly using + * {@link #setQueryString(String)} or a named query can be used by + * {@link #setQueryName(String)}. * * The reader can be configured to use either {@link StatelessSession} * sufficient for simple mappings without the need to cascade to associated @@ -45,16 +47,12 @@ import org.springframework.util.ClassUtils; * When stateful session is used it will be cleared after successful commit * without being flushed (no inserts or updates are expected). * - * Reset(rollback) functionality is implemented by item buffering allowing the - * cursor used to be forward-only. - * * The implementation is *not* thread-safe. * * @author Robert Kasanicky * @author Dave Syer */ -public class HibernateCursorItemReader extends - AbstractItemCountingItemStreamItemReader implements ItemStream, +public class HibernateCursorItemReader extends AbstractItemCountingItemStreamItemReader implements ItemStream, InitializingBean { private SessionFactory sessionFactory; @@ -65,7 +63,9 @@ public class HibernateCursorItemReader extends private ScrollableResults cursor; - private String queryString; + private String queryString = ""; + + private String namedQuery = ""; private boolean useStatelessSession = true; @@ -83,30 +83,47 @@ public class HibernateCursorItemReader extends private Query createQuery() { if (useStatelessSession) { statelessSession = sessionFactory.openStatelessSession(); - return statelessSession.createQuery(queryString); - } else { + if (!namedQuery.isEmpty()) { + return statelessSession.getNamedQuery(namedQuery); + } + else { + return statelessSession.createQuery(queryString); + } + } + else { statefulSession = sessionFactory.openSession(); - return statefulSession.createQuery(queryString); + if (!namedQuery.isEmpty()) { + return statefulSession.getNamedQuery(namedQuery); + } + else { + return statefulSession.createQuery(queryString); + } } } /** - * @param sessionFactory - * hibernate session factory + * @param sessionFactory hibernate session factory */ public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public void afterPropertiesSet() throws Exception { - Assert.notNull(sessionFactory); - Assert.hasLength(queryString); + Assert.notNull(sessionFactory, "session factory must be set"); Assert.isTrue(fetchSize >= 0, "fetchSize must not be negative"); + Assert.isTrue(queryString.isEmpty() ^ namedQuery.isEmpty(), + "exactly one of queryString or queryName must be set"); } /** - * @param queryString - * HQL query string + * @param queryName name of a hibernate named query + */ + public void setQueryName(String queryName) { + this.namedQuery = queryName; + } + + /** + * @param queryString HQL query string */ public void setQueryString(String queryString) { this.queryString = queryString; @@ -115,9 +132,9 @@ public class HibernateCursorItemReader extends /** * Can be set only in uninitialized state. * - * @param useStatelessSession - * true to use {@link StatelessSession} - * false to use standard hibernate {@link Session} + * @param useStatelessSession true to use + * {@link StatelessSession} false to use standard hibernate + * {@link Session} */ public void setUseStatelessSession(boolean useStatelessSession) { Assert.state(!initialized); @@ -128,8 +145,7 @@ public class HibernateCursorItemReader extends * Clears the session if not stateful and delegates to super class. */ @Override - public void update(ExecutionContext executionContext) - throws ItemStreamException { + public void update(ExecutionContext executionContext) throws ItemStreamException { super.update(executionContext); if (!useStatelessSession) { statefulSession.clear(); @@ -142,8 +158,7 @@ public class HibernateCursorItemReader extends * ResultSet object. If the fetch size specified is zero, the * JDBC driver ignores the value. * - * @param fetchSize - * the number of rows to fetch, 0 by default + * @param fetchSize the number of rows to fetch, 0 by default * @see Query#setFetchSize(int) */ public void setFetchSize(int fetchSize) { @@ -160,7 +175,8 @@ public class HibernateCursorItemReader extends @SuppressWarnings("unchecked") T item = (T) data; return item; - } else { + } + else { // Assume if there is only one item that it is the data the user // wants. // If there is only one item this is going to be a nasty shock @@ -179,11 +195,9 @@ public class HibernateCursorItemReader extends * {@link #setQueryString(String)}. */ protected void doOpen() throws Exception { - Assert.state(!initialized, - "Cannot open an already opened ItemReader, call close first"); + Assert.state(!initialized, "Cannot open an already opened ItemReader, call close first"); - cursor = createQuery().setFetchSize(fetchSize).scroll( - ScrollMode.FORWARD_ONLY); + cursor = createQuery().setFetchSize(fetchSize).scroll(ScrollMode.FORWARD_ONLY); initialized = true; @@ -202,7 +216,8 @@ public class HibernateCursorItemReader extends if (statelessSession != null) { statelessSession.close(); } - } else { + } + else { if (statefulSession != null) { statefulSession.close(); } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderIntegrationTests.java index 8539cc526..28a65cf95 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderIntegrationTests.java @@ -32,16 +32,19 @@ public class HibernateCursorItemReaderIntegrationTests extends AbstractDataSourc SessionFactory sessionFactory = (SessionFactory) factoryBean.getObject(); - String hsqlQuery = "from Foo"; - HibernateCursorItemReader inputSource = new HibernateCursorItemReader(); - inputSource.setQueryString(hsqlQuery); - inputSource.setSessionFactory(sessionFactory); - inputSource.setUseStatelessSession(isUseStatelessSession()); - inputSource.afterPropertiesSet(); - inputSource.setSaveState(true); + HibernateCursorItemReader hibernateReader = new HibernateCursorItemReader(); + setQuery(hibernateReader); + hibernateReader.setSessionFactory(sessionFactory); + hibernateReader.setUseStatelessSession(isUseStatelessSession()); + hibernateReader.afterPropertiesSet(); + hibernateReader.setSaveState(true); - return inputSource; + return hibernateReader; + } + + protected void setQuery(HibernateCursorItemReader reader) { + reader.setQueryString("from Foo"); } protected boolean isUseStatelessSession() { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderNamedQueryIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderNamedQueryIntegrationTests.java new file mode 100644 index 000000000..a07a0a14f --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderNamedQueryIntegrationTests.java @@ -0,0 +1,13 @@ +package org.springframework.batch.item.database; + +/** + * Tests {@link HibernateCursorItemReader} configured with named query. + */ +public class HibernateCursorItemReaderNamedQueryIntegrationTests extends HibernateCursorItemReaderIntegrationTests { + + @Override + protected void setQuery(HibernateCursorItemReader reader) { + reader.setQueryName("allFoos"); + } + +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulNamedQueryIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulNamedQueryIntegrationTests.java new file mode 100644 index 000000000..cafc8c347 --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/HibernateCursorItemReaderStatefulNamedQueryIntegrationTests.java @@ -0,0 +1,14 @@ +package org.springframework.batch.item.database; + +/** + * Tests {@link HibernateCursorItemReader} configured with stateful session and + * named query. + */ +public class HibernateCursorItemReaderStatefulNamedQueryIntegrationTests extends + HibernateCursorItemReaderNamedQueryIntegrationTests { + + @Override + protected boolean isUseStatelessSession() { + return false; + } +} diff --git a/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/Foo.hbm.xml b/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/Foo.hbm.xml index bc2f3f4cc..4c4b7bbbb 100644 --- a/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/Foo.hbm.xml +++ b/spring-batch-infrastructure/src/test/resources/org/springframework/batch/item/database/Foo.hbm.xml @@ -5,11 +5,14 @@ - - - - - - + + + + + + - \ No newline at end of file + + from Foo + +