diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilder.java
index 239eb373d..91f0f8600 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilder.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilder.java
@@ -20,17 +20,19 @@ import java.util.Map;
import org.hibernate.SessionFactory;
import org.springframework.batch.item.database.HibernateCursorItemReader;
+import org.springframework.batch.item.database.orm.HibernateNativeQueryProvider;
import org.springframework.batch.item.database.orm.HibernateQueryProvider;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* This is a builder for the {@link HibernateCursorItemReader}. When configuring, one of
- * the following should be provided:
+ * the following should be provided (listed in order of precedence):
*
- * - {@link #queryString(String)}
- * - {@link #queryName(String)}
* - {@link #queryProvider(HibernateQueryProvider)}
+ * - {@link #queryName(String)}
+ * - {@link #queryString(String)}
+ * - {@link #nativeQuery(String)} and {@link #entityClass(Class)}
*
*
* @author Michael Minella
@@ -61,6 +63,10 @@ public class HibernateCursorItemReaderBuilder {
private String name;
+ private String nativeQuery;
+
+ private Class nativeClass;
+
/**
* A name used to prevent key collisions while saving the state in the
* {@link org.springframework.batch.item.ExecutionContext}
@@ -212,6 +218,23 @@ public class HibernateCursorItemReaderBuilder {
return this;
}
+ /**
+ * Used to configure a {@link HibernateNativeQueryProvider}. This is ignored if
+ * @param nativeQuery
+ * @return
+ */
+ public HibernateCursorItemReaderBuilder nativeQuery(String nativeQuery) {
+ this.nativeQuery = nativeQuery;
+
+ return this;
+ }
+
+ public HibernateCursorItemReaderBuilder entityClass(Class nativeClass) {
+ this.nativeClass = nativeClass;
+
+ return this;
+ }
+
/**
* Returns a fully constructed {@link HibernateCursorItemReader}.
*
@@ -226,18 +249,39 @@ public class HibernateCursorItemReaderBuilder {
"A name is required when saveState is set to true.");
}
- if (queryProvider == null) {
- Assert.state(StringUtils.hasText(queryString) ^ StringUtils.hasText(queryName),
- "queryString or queryName must be set");
- }
-
HibernateCursorItemReader reader = new HibernateCursorItemReader<>();
reader.setFetchSize(this.fetchSize);
reader.setParameterValues(this.parameterValues);
- reader.setQueryName(this.queryName);
- reader.setQueryProvider(this.queryProvider);
- reader.setQueryString(this.queryString);
+
+ if(this.queryProvider != null) {
+ reader.setQueryProvider(this.queryProvider);
+ }
+ else if(StringUtils.hasText(this.queryName)) {
+ reader.setQueryName(this.queryName);
+ }
+ else if(StringUtils.hasText(this.queryString)) {
+ reader.setQueryString(this.queryString);
+ }
+ else if(StringUtils.hasText(this.nativeQuery) && this.nativeClass != null) {
+ HibernateNativeQueryProvider provider = new HibernateNativeQueryProvider();
+ provider.setSqlQuery(this.nativeQuery);
+ provider.setEntityClass(this.nativeClass);
+
+ try {
+ provider.afterPropertiesSet();
+ }
+ catch (Exception e) {
+ throw new IllegalStateException("Unable to initialize the HibernateNativeQueryProvider", e);
+ }
+
+ reader.setQueryProvider(provider);
+ }
+ else {
+ throw new IllegalStateException("A HibernateQueryProvider, queryName, queryString, " +
+ "or both the nativeQuery and entityClass must be configured");
+ }
+
reader.setSessionFactory(this.sessionFactory);
reader.setUseStatelessSession(this.useStatelessSession);
reader.setCurrentItemCount(this.currentItem);
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilderTests.java
index f7d44a5f1..ffa812fb2 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilderTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/builder/HibernateCursorItemReaderBuilderTests.java
@@ -137,7 +137,6 @@ public class HibernateCursorItemReaderBuilderTests {
provider.setSqlQuery("select * from T_FOOS");
provider.afterPropertiesSet();
-
HibernateCursorItemReader reader = new HibernateCursorItemReaderBuilder()
.name("fooReader")
.sessionFactory(this.sessionFactory)
@@ -161,6 +160,32 @@ public class HibernateCursorItemReaderBuilderTests {
assertEquals(5, i);
}
+ @Test
+ public void testConfigurationNativeQuery() throws Exception {
+ HibernateCursorItemReader reader = new HibernateCursorItemReaderBuilder()
+ .name("fooReader")
+ .sessionFactory(this.sessionFactory)
+ .nativeQuery("select * from T_FOOS")
+ .entityClass(Foo.class)
+ .build();
+
+ reader.afterPropertiesSet();
+
+ ExecutionContext executionContext = new ExecutionContext();
+
+ reader.open(executionContext);
+
+ int i = 0;
+ while(reader.read() != null) {
+ i++;
+ }
+
+ reader.update(executionContext);
+ reader.close();
+
+ assertEquals(5, i);
+ }
+
@Test
public void testValidation() {
try {
@@ -195,10 +220,12 @@ public class HibernateCursorItemReaderBuilderTests {
.sessionFactory(this.sessionFactory)
.saveState(false)
.build();
- fail("queryString or queryName must be set");
+ fail("A HibernateQueryProvider, queryName, queryString, " +
+ "or both the nativeQuery and entityClass must be configured");
}
catch (IllegalStateException ise) {
- assertEquals("queryString or queryName must be set", ise.getMessage());
+ assertEquals("A HibernateQueryProvider, queryName, queryString, " +
+ "or both the nativeQuery and entityClass must be configured", ise.getMessage());
}
}