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 e537b7389..18e6f2fea 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 @@ -203,7 +203,14 @@ public class HibernateCursorItemReader extends AbstractItemCountingItemStream initialized = true; } - + + @Override + protected void jumpToItem(int itemIndex) throws Exception { + for(int i = 0; i < itemIndex; i++){ + cursor.next(); + } + } + /** * Close the cursor and hibernate session. */ diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java index 8a91688a7..ed8813a86 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/FlatFileItemReader.java @@ -221,13 +221,13 @@ public class FlatFileItemReader extends AbstractItemCountingItemStreamItemRea } String line = null; - try { line = this.reader.readLine(); if (line == null) { return null; } lineCount++; + while (isComment(line)) { line = reader.readLine(); if (line == null) { @@ -235,12 +235,30 @@ public class FlatFileItemReader extends AbstractItemCountingItemStreamItemRea } lineCount++; } + + line = applyRecordSeparatorPolicy(line); } catch (IOException e) { throw new FlatFileParseException("Unable to read from resource: [" + resource + "]", e, line, lineCount); } return line; } + + private String applyRecordSeparatorPolicy(String line) throws IOException{ + + String record = line; + while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) { + line = this.reader.readLine(); + if (line==null) { + throw new FlatFileParseException("Unexpected end of file before record complete", record, lineCount); + } + record = recordSeparatorPolicy.preProcess(record) + line; + lineCount++; + } + + return recordSeparatorPolicy.postProcess(record); + + } private boolean isComment(String line) { for (String prefix : comments) { @@ -282,6 +300,13 @@ public class FlatFileItemReader extends AbstractItemCountingItemStreamItemRea } } } + + @Override + protected void jumpToItem(int itemIndex) throws Exception { + for (int i = 0; i < itemIndex; i++) { + readLine(); + } + } public void afterPropertiesSet() throws Exception { Assert.notNull(lineMapper, "LineMapper is required"); diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java index b66866640..35a4c674e 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java @@ -22,7 +22,9 @@ import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -211,5 +213,49 @@ public class StaxEventItemReader extends AbstractItemCountingItemStreamItemRe return item; } - + + /* + * jumpToItem is overridden because reading in and attempting to bind an entire fragment + * is unacceptable in a restart scenario, and may cause exceptions to be thrown that + * were already skipped in previous runs. + */ + @Override + protected void jumpToItem(int itemIndex) throws Exception { + for (int i = 0; i < itemIndex; i++) { + readToStartFragement(); + readToEndFragment(); + } + } + + /* + * Read until the first StartElement tag that matches the provided + * fragmentRootElementName. Because there may be any number of tags in between where the reader + * is now and the fragment start, this is done in a loop until the element type and name + * match. + */ + private void readToStartFragement() throws XMLStreamException{ + while(true){ + XMLEvent nextEvent = eventReader.nextEvent(); + if( nextEvent.isStartElement() && + ((StartElement)nextEvent).getName().getLocalPart().equals(fragmentRootElementName)){ + return; + } + } + } + + /* + * Read until the first EndElement tag that matches the provided + * fragmentRootElementName. Because there may be any number of tags in between where the reader + * is now and the fragment end tag, this is done in a loop until the element type and name + * match + */ + private void readToEndFragment() throws XMLStreamException{ + while(true){ + XMLEvent nextEvent = eventReader.nextEvent(); + if( nextEvent.isEndElement() && + ((EndElement)nextEvent).getName().getLocalPart().equals(fragmentRootElementName)){ + return; + } + } + } }