diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/RepositoryItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/RepositoryItemReader.java index a5da3932d..650abf22e 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/RepositoryItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/data/RepositoryItemReader.java @@ -15,8 +15,14 @@ */ package org.springframework.batch.item.data; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.adapter.AbstractMethodInvokingDelegator.InvocationTargetThrowableWrapper; import org.springframework.batch.item.adapter.DynamicMethodInvocationException; @@ -31,11 +37,6 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MethodInvoker; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - /** *

* A {@link org.springframework.batch.item.ItemReader} that reads records utilizing @@ -173,8 +174,8 @@ public class RepositoryItemReader extends AbstractItemCountingItemStreamItemR @Override protected void jumpToItem(int itemLastIndex) throws Exception { synchronized (lock) { - page = itemLastIndex / pageSize; - current = itemLastIndex % pageSize; + page = (itemLastIndex - 1) / pageSize; + current = (itemLastIndex - 1) % pageSize; results = doPageRead(); page++; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/AbstractCursorItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/AbstractCursorItemReader.java index 836013a67..e0660fd25 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/AbstractCursorItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/AbstractCursorItemReader.java @@ -153,7 +153,7 @@ implements InitializingBean { /** * Public setter for the data source for injection purposes. * - * @param dataSource + * @param dataSource {@link javax.sql.DataSource} to be used */ public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; @@ -172,7 +172,10 @@ implements InitializingBean { * Prepare the given JDBC Statement (or PreparedStatement or * CallableStatement), applying statement settings such as fetch size, max * rows, and query timeout. @param stmt the JDBC Statement to prepare - * @throws SQLException + * + * @param stmt {@link java.sql.PreparedStatement} to be configured + * + * @throws SQLException if interactions with provided stmt fail * * @see #setFetchSize * @see #setMaxRows @@ -192,10 +195,10 @@ implements InitializingBean { } /** - * Return the exception translator for this instance. - * * Creates a default SQLErrorCodeSQLExceptionTranslator for the specified * DataSource if none is set. + * + * @return the exception translator for this instance. */ protected SQLExceptionTranslator getExceptionTranslator() { synchronized(this) { @@ -216,7 +219,7 @@ implements InitializingBean { * warnings (at debug level). * * @param statement the current statement to obtain the warnings from, if there are any. - * @throws SQLException + * @throws SQLException if interaction with provided statement fails. * * @see org.springframework.jdbc.SQLWarningException */ @@ -461,7 +464,7 @@ implements InitializingBean { * @param rs The current result set * @param currentRow Current position of the result set * @return the mapped object at the cursor position - * @throws SQLException + * @throws SQLException if interactions with the current result set fail */ protected abstract T readCursor(ResultSet rs, int currentRow) throws SQLException; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ExtendedConnectionDataSourceProxy.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ExtendedConnectionDataSourceProxy.java index 78db5b8b3..b6836cd64 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ExtendedConnectionDataSourceProxy.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ExtendedConnectionDataSourceProxy.java @@ -16,15 +16,6 @@ package org.springframework.batch.item.database; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.jdbc.datasource.ConnectionProxy; -import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.jdbc.datasource.SmartDataSource; -import org.springframework.transaction.support.TransactionSynchronizationManager; -import org.springframework.util.Assert; -import org.springframework.util.MethodInvoker; - -import javax.sql.DataSource; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; @@ -35,6 +26,16 @@ import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.jdbc.datasource.ConnectionProxy; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.jdbc.datasource.SmartDataSource; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.Assert; +import org.springframework.util.MethodInvoker; + /** * Implementation of {@link SmartDataSource} that is capable of keeping a single * JDBC Connection which is NOT closed after each use even if @@ -105,6 +106,8 @@ public class ExtendedConnectionDataSourceProxy implements SmartDataSource, Initi /** * Constructor that takes as a parameter with the {@link DataSource} to be * wrapped. + * + * @param dataSource DataSource to be used */ public ExtendedConnectionDataSourceProxy(DataSource dataSource) { this.dataSource = dataSource; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemReaderHelper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemReaderHelper.java index a769f1ea6..f9122b7fb 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemReaderHelper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/HibernateItemReaderHelper.java @@ -129,6 +129,8 @@ public class HibernateItemReaderHelper implements InitializingBean { /** * Open appropriate type of hibernate session and create the query. + * + * @return a Hibernate Query */ public Query createQuery() { @@ -174,6 +176,8 @@ public class HibernateItemReaderHelper implements InitializingBean { * Scroll through the results up to the item specified. * * @param cursor the results to scroll over + * @param itemIndex index to scroll to + * @param flushInterval the number of items to scroll past before flushing */ public void jumpToItem(ScrollableResults cursor, int itemIndex, int flushInterval) { for (int i = 0; i < itemIndex; i++) { 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 dcc4491ba..0b6c77a2f 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 @@ -122,8 +122,8 @@ public class HibernateItemWriter implements ItemWriter, InitializingBean { * Do perform the actual write operation using Hibernate's API. * This can be overridden in a subclass if necessary. * - * @param items - * the list of items to use for the write + * @param sessionFactory Hibernate SessionFactory to be used + * @param items the list of items to use for the write */ protected void doWrite(SessionFactory sessionFactory, List items) { if (logger.isDebugEnabled()) { diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ItemSqlParameterSourceProvider.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ItemSqlParameterSourceProvider.java index b0d30045e..68a023412 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ItemSqlParameterSourceProvider.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/ItemSqlParameterSourceProvider.java @@ -29,6 +29,7 @@ public interface ItemSqlParameterSourceProvider { * Provide parameter values in an {@link SqlParameterSource} based on values from * the provided item. * @param item the item to use for parameter values + * @return parameters extracted from the item */ SqlParameterSource createSqlParameterSource(T item); diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ldif/RecordMapper.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ldif/RecordMapper.java index 90a650c6d..fffb0a63f 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ldif/RecordMapper.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ldif/RecordMapper.java @@ -23,14 +23,14 @@ import org.springframework.ldap.core.LdapAttributes; * * @author Keith Barlow * - * @param + * @param type the record will be mapped to */ public interface RecordMapper { /** * Maps an {@link LdapAttributes LdapAttributes} object to the specified type. * - * @param attributes + * @param attributes attributes * @return object of type T */ T mapRecord(LdapAttributes attributes); diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java index eded4a8ec..d06cec7da 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/AbstractItemCountingItemStreamItemReader.java @@ -154,20 +154,24 @@ public abstract class AbstractItemCountingItemStreamItemReader extends Abstra maxItemCount = executionContext.getInt(getExecutionContextKey(READ_COUNT_MAX)); } + int itemCount = 0; if (executionContext.containsKey(getExecutionContextKey(READ_COUNT))) { - int itemCount = executionContext.getInt(getExecutionContextKey(READ_COUNT)); - - if (itemCount < maxItemCount) { - try { - jumpToItem(itemCount); - } - catch (Exception e) { - throw new ItemStreamException("Could not move to stored position on restart", e); - } - } - currentItemCount = itemCount; - + itemCount = executionContext.getInt(getExecutionContextKey(READ_COUNT)); } + else if(currentItemCount > 0) { + itemCount = currentItemCount; + } + + if (itemCount > 0 && itemCount < maxItemCount) { + try { + jumpToItem(itemCount); + } + catch (Exception e) { + throw new ItemStreamException("Could not move to stored position on restart", e); + } + } + + currentItemCount = itemCount; } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/poller/Poller.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/poller/Poller.java index ef1969066..187af6728 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/poller/Poller.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/poller/Poller.java @@ -50,7 +50,7 @@ public interface Poller { * * @param callable a {@link Callable} to use to retrieve a result * @return a future which itself can be used to get the result - * @throws java.lang.Exception + * @throws java.lang.Exception allows for checked exceptions */ Future poll(Callable callable) throws Exception; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/RepeatOperationsInterceptor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/RepeatOperationsInterceptor.java index 50b099195..d0e1de1f2 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/RepeatOperationsInterceptor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/interceptor/RepeatOperationsInterceptor.java @@ -47,7 +47,7 @@ public class RepeatOperationsInterceptor implements MethodInterceptor { /** * Setter for the {@link RepeatOperations}. * - * @param batchTempate + * @param batchTempate template to be used * @throws IllegalArgumentException if the argument is null. */ public void setRepeatOperations(RepeatOperations batchTempate) { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/RepositoryItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/RepositoryItemReaderTests.java index 9db26f5c9..d7d5c24a3 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/RepositoryItemReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/data/RepositoryItemReaderTests.java @@ -15,11 +15,25 @@ */ package org.springframework.batch.item.data; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; + +import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.adapter.DynamicMethodInvocationException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -29,18 +43,6 @@ import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.repository.PagingAndSortingRepository; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.mock; - public class RepositoryItemReaderTests { private RepositoryItemReader reader; @@ -140,7 +142,7 @@ public class RepositoryItemReaderTests { public void testDoReadFirstReadSecondPage() throws Exception { ArgumentCaptor pageRequestContainer = ArgumentCaptor.forClass(PageRequest.class); final Object result = new Object(); - when(repository.findAll(pageRequestContainer.capture())).thenReturn(new PageImpl(new ArrayList(){{ + when(repository.findAll(pageRequestContainer.capture())).thenReturn(new PageImpl(new ArrayList() {{ add(new Object()); }})).thenReturn(new PageImpl(new ArrayList(){{ add(result); @@ -161,7 +163,7 @@ public class RepositoryItemReaderTests { public void testDoReadFirstReadExhausted() throws Exception { ArgumentCaptor pageRequestContainer = ArgumentCaptor.forClass(PageRequest.class); final Object result = new Object(); - when(repository.findAll(pageRequestContainer.capture())).thenReturn(new PageImpl(new ArrayList(){{ + when(repository.findAll(pageRequestContainer.capture())).thenReturn(new PageImpl(new ArrayList() {{ add(new Object()); }})).thenReturn(new PageImpl(new ArrayList(){{ add(result); @@ -233,6 +235,65 @@ public class RepositoryItemReaderTests { assertEquals("id: ASC", pageRequest.getSort().toString()); } + @Test + public void testSettingCurrentItemCountExplicitly() throws Exception { + reader.setCurrentItemCount(3); + reader.setPageSize(2); + + PageRequest request = new PageRequest(1, 2, new Sort(Direction.ASC, "id")); + when(repository.findAll(request)).thenReturn(new PageImpl(new ArrayList(){{ + add("3"); + add("4"); + }})); + + request = new PageRequest(2, 2, new Sort(Direction.ASC, "id")); + when(repository.findAll(request)).thenReturn(new PageImpl(new ArrayList(){{ + add("5"); + add("6"); + }})); + + reader.open(new ExecutionContext()); + + Object result = reader.read(); + + assertEquals("3", result); + assertEquals("4", reader.read()); + assertEquals("5", reader.read()); + assertEquals("6", reader.read()); + } + + @Test + public void testSettingCurrentItemCountRestart() throws Exception { + reader.setCurrentItemCount(3); + reader.setPageSize(2); + + PageRequest request = new PageRequest(1, 2, new Sort(Direction.ASC, "id")); + when(repository.findAll(request)).thenReturn(new PageImpl(new ArrayList(){{ + add("3"); + add("4"); + }})); + + request = new PageRequest(2, 2, new Sort(Direction.ASC, "id")); + when(repository.findAll(request)).thenReturn(new PageImpl(new ArrayList(){{ + add("5"); + add("6"); + }})); + + ExecutionContext executionContext = new ExecutionContext(); + reader.open(executionContext); + + Object result = reader.read(); + reader.update(executionContext); + reader.close(); + + assertEquals("3", result); + + reader.open(executionContext); + assertEquals("4", reader.read()); + assertEquals("5", reader.read()); + assertEquals("6", reader.read()); + } + public static interface TestRepository extends PagingAndSortingRepository { Page findFirstNames(Pageable pageable); }