diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java index 031af3c9d..8210d8ac5 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/DrivingQueryItemReader.java @@ -28,11 +28,11 @@ import org.springframework.util.Assert; /** *
* Convenience class for driving query input sources. Input Sources of this type - * use a 'driving query' to return back a list of keys. A key can be defined - * as anything that can uniquely identify a record so that a more detailed - * record can be retrieved for each object. This allows a much smaller footprint - * to be stored in memory for processing. The following 'Customer' example table - * will help illustrate this: + * use a 'driving query' to return back a list of keys. A key can be defined as + * anything that can uniquely identify a record so that a more detailed record + * can be retrieved for each object. This allows a much smaller footprint to be + * stored in memory for processing. The following 'Customer' example table will + * help illustrate this: * *
* CREATE TABLE CUSTOMER ( @@ -42,12 +42,14 @@ import org.springframework.util.Assert; * ); ** - *
A cursor based solution would simply open up a cursor over ID, NAME, and CREDIT, - * and move it from one to the next. This can cause issues on databases with - * pessimistic locking strategies. A 'driving query' approach would be to + *
+ * A cursor based solution would simply open up a cursor over ID, NAME, and + * CREDIT, and move it from one to the next. This can cause issues on databases + * with pessimistic locking strategies. A 'driving query' approach would be to * return only the ID of the customer, then use a separate DAO to retrieve the - * name and credit for each ID. This means that there will be a call to a - * separate DAO for each call to {@link ItemReader#read()}.
+ * name and credit for each ID. This means that there will be a call to a + * separate DAO for each call to {@link ItemReader#read()}. + * * ** Mutability: Because this base class cannot guarantee that the keys returned @@ -62,8 +64,7 @@ import org.springframework.util.Assert; * * @author Lucas Ward */ -public class DrivingQueryItemReader implements ItemReader, InitializingBean, - ItemStream { +public class DrivingQueryItemReader implements ItemReader, InitializingBean, ItemStream { private boolean initialized = false; @@ -76,7 +77,7 @@ public class DrivingQueryItemReader implements ItemReader, InitializingBean, private int lastCommitIndex = 0; private KeyCollector keyGenerator; - + private boolean saveState = false; public DrivingQueryItemReader() { @@ -113,13 +114,13 @@ public class DrivingQueryItemReader implements ItemReader, InitializingBean, /** * Get the current key. This method will return the same object returned by - * the last read() method. If the ItemReader hasn't been initialized yet, - * then null will be returned. + * the last read() method. If no items have been read yet the ItemReader + * yet, then null will be returned. * * @return the current key. */ protected Object getCurrentKey() { - if (initialized) { + if (initialized && currentIndex > 0) { return keys.get(currentIndex - 1); } @@ -152,7 +153,7 @@ public class DrivingQueryItemReader implements ItemReader, InitializingBean, Assert.state(keys == null && !initialized, "Cannot open an already opened input source" + ", call close() first."); keys = keyGenerator.retrieveKeys(executionContext); - if(keys == null || keys.size() == 0){ + if (keys == null || keys.size() == 0) { throw new NoWorkFoundException("KeyGenerator must return at least 1 key"); } keysIterator = keys.listIterator(); @@ -160,9 +161,9 @@ public class DrivingQueryItemReader implements ItemReader, InitializingBean, } public void update(ExecutionContext executionContext) { - if(saveState){ + if (saveState) { Assert.notNull(executionContext, "ExecutionContext must not be null"); - if(getCurrentKey() != null){ + if (getCurrentKey() != null) { keyGenerator.updateContext(getCurrentKey(), executionContext); } } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java index 7d018fbe8..339d7bee4 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/CommonItemStreamItemReaderTests.java @@ -37,6 +37,8 @@ public abstract class CommonItemStreamItemReaderTests extends CommonItemReaderTe */ public void testRestart() throws Exception { + testedAsStream().update(executionContext); + Foo foo1 = (Foo) tested.read(); assertEquals(1, foo1.getValue());