diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/RecordSeparatorPolicy.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/RecordSeparatorPolicy.java index fefefa7e9..22c6b9b85 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/RecordSeparatorPolicy.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/RecordSeparatorPolicy.java @@ -40,7 +40,8 @@ public interface RecordSeparatorPolicy { boolean isEndOfRecord(String line); /** - * Give the policy a chance to postprocess a record, e.g. remove a suffix. + * Give the policy a chance to post-process a complete record, e.g. remove a + * suffix. * * @param record the complete record. * @return a modified version of the record if desired. @@ -48,12 +49,14 @@ public interface RecordSeparatorPolicy { String postProcess(String record); /** - * Preprocess a line before it is appended to a record. Can be used to - * remove a prefix or line-continuation marker. + * Pre-process a record before another line is appended, in the case of a + * multi-line record. Can be used to remove a prefix or line-continuation + * marker. If a record is a single line this callback is not used (but + * {@link #postProcess(String)} will be). * - * @param line the current line. + * @param record the current record. * @return the line as it should be appended to a record. */ - String preProcess(String line); + String preProcess(String record); } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/ResourceLineReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/ResourceLineReader.java index 60e8523e3..afc31ed32 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/ResourceLineReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/separator/ResourceLineReader.java @@ -59,8 +59,7 @@ import org.springframework.util.Assert; public class ResourceLineReader extends AbstractItemReader implements LineReader, ResourceLifecycle, ItemReader, DisposableBean { - private static final Collection DEFAULT_COMMENTS = Collections - .singleton("#"); + private static final Collection DEFAULT_COMMENTS = Collections.singleton("#"); private static final String DEFAULT_ENCODING = "ISO-8859-1"; @@ -93,11 +92,9 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader * {@link DefaultRecordSeparatorPolicy}. Ideally should not be changed once * a reader is in use, but it would not be fatal if it was. * - * @param recordSeparatorPolicy - * the new {@link RecordSeparatorPolicy} + * @param recordSeparatorPolicy the new {@link RecordSeparatorPolicy} */ - public void setRecordSeparatorPolicy( - RecordSeparatorPolicy recordSeparatorPolicy) { + public void setRecordSeparatorPolicy(RecordSeparatorPolicy recordSeparatorPolicy) { /* * The rest of the code accesses the policy in synchronized blocks, * copying the reference before using it. So in principle it can be @@ -110,8 +107,7 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader * Setter for comment prefixes. Can be used to ignore header lines as well * by using e.g. the first couple of column names as a prefix. * - * @param comments - * an array of comment line prefixes. + * @param comments an array of comment line prefixes. */ public void setComments(String[] comments) { this.comments = new HashSet(Arrays.asList(comments)); @@ -123,9 +119,8 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader * * @return a String. * - * @throws BatchEnvironmentException - * if there is an IOException while accessing the input - * resource. + * @throws BatchEnvironmentException if there is an IOException while + * accessing the input resource. * * @see org.springframework.batch.item.reader.support.ItemReader#read() */ @@ -136,11 +131,9 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader String line = readLine(); String record = line; if (line != null) { - StringBuffer buffer = new StringBuffer(record); while (line != null && !recordSeparatorPolicy.isEndOfRecord(record)) { - buffer.append(recordSeparatorPolicy - .preProcess(line = readLine())); - record = buffer.toString(); + record = recordSeparatorPolicy.preProcess(record) + (line = readLine()); + // record = new StringBuilder(recordSeparatorPolicy.preProcess(record)).append(line = readLine()).toString(); } } return recordSeparatorPolicy.postProcess(record); @@ -179,9 +172,8 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader * Close the reader associated with this input source. * * @see org.springframework.batch.io.ItemReader#close() - * @throws BatchEnvironmentException - * if there is an {@link IOException} during the close - * operation. + * @throws BatchEnvironmentException if there is an {@link IOException} + * during the close operation. */ public synchronized void close() { if (state == null) { @@ -189,7 +181,8 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader } try { state.close(); - } finally { + } + finally { state = null; } } @@ -219,8 +212,7 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader * * @see #reset() * - * @throws BatchEnvironmentException - * if the mark could not be set. + * @throws BatchEnvironmentException if the mark could not be set. */ public synchronized void mark() { getState().mark(); @@ -231,9 +223,8 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader * * @see #mark() * - * @throws BatchEnvironmentException - * if the reset is unsuccessful, e.g. if the read-ahead limit - * was breached. + * @throws BatchEnvironmentException if the reset is unsuccessful, e.g. if + * the read-ahead limit was breached. */ public synchronized void reset() { getState().reset(); @@ -275,10 +266,10 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader } currentLineCount++; } - } catch (IOException e) { - throw new BatchEnvironmentException( - "Unable to read from resource '" + resource - + "' at line " + currentLineCount, e); + } + catch (IOException e) { + throw new BatchEnvironmentException("Unable to read from resource '" + resource + "' at line " + + currentLineCount, e); } return line; } @@ -288,12 +279,11 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader */ public void open() { try { - reader = new BufferedReader(new InputStreamReader(resource - .getInputStream(), encoding)); + reader = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding)); mark(); - } catch (IOException e) { - throw new BatchEnvironmentException("Could not open resource", - e); + } + catch (IOException e) { + throw new BatchEnvironmentException("Could not open resource", e); } } @@ -307,9 +297,11 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader } try { reader.close(); - } catch (IOException e) { + } + catch (IOException e) { throw new BatchEnvironmentException("Could not close reader", e); - } finally { + } + finally { currentLineCount = 0; markedLineCount = -1; } @@ -330,7 +322,8 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader try { reader.mark(READ_AHEAD_LIMIT); markedLineCount = currentLineCount; - } catch (IOException e) { + } + catch (IOException e) { throw new BatchEnvironmentException("Could not mark reader", e); } } @@ -347,7 +340,8 @@ public class ResourceLineReader extends AbstractItemReader implements LineReader try { this.reader.reset(); currentLineCount = markedLineCount; - } catch (IOException e) { + } + catch (IOException e) { throw new BatchEnvironmentException("Could not reset reader", e); } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/file/ResourceLineReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/file/ResourceLineReaderTests.java index b12972ebd..a4b58a411 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/file/ResourceLineReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/io/file/ResourceLineReaderTests.java @@ -94,8 +94,23 @@ public class ResourceLineReaderTests extends TestCase { reader.read(); assertEquals(2, reader.getCurrentLineCount()); } - - public void testLineEndings() throws Exception { + + public void testLineContent() throws Exception { + Resource resource = new ByteArrayResource("1,2,3\n4\n5,6,7".getBytes()); + ResourceLineReader reader = new ResourceLineReader(resource); + assertEquals("1,2,3", reader.read()); + assertEquals("4", reader.read()); + assertEquals("5,6,7", reader.read()); + } + + public void testLineContentWhenLineContainsQuotedNewline() throws Exception { + Resource resource = new ByteArrayResource("1,2,\"3\n4\"\n5,6,7".getBytes()); + ResourceLineReader reader = new ResourceLineReader(resource); + assertEquals("1,2,\"3\n4\"", reader.read()); + assertEquals("5,6,7", reader.read()); + } + + public void testLineEndings() throws Exception { Resource resource = new ByteArrayResource("1\n2\r\n3".getBytes()); ResourceLineReader reader = new ResourceLineReader(resource); reader.read();