diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/builder/JsrSimpleStepBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/builder/JsrSimpleStepBuilder.java index 7d1d75513..85baf467a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/builder/JsrSimpleStepBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/builder/JsrSimpleStepBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import java.util.ArrayList; import org.springframework.batch.core.ChunkListener; import org.springframework.batch.core.Step; -import org.springframework.batch.core.StepListener; import org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext; import org.springframework.batch.core.jsr.step.BatchletStep; import org.springframework.batch.core.jsr.step.item.JsrChunkProcessor; @@ -45,6 +44,7 @@ import org.springframework.util.Assert; * pattern defined by the spec. * * @author Michael Minella + * @author Mahmoud Ben Hassine * * @param The input type for the step * @param The output type for the step diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/IteratorItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/IteratorItemReader.java index c6da82aae..4d710136d 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/IteratorItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/IteratorItemReader.java @@ -1,74 +1,73 @@ -/* - * Copyright 2006-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.item.support; - -import java.util.Iterator; - -import org.springframework.batch.item.ItemReader; -import org.springframework.batch.item.ParseException; -import org.springframework.batch.item.UnexpectedInputException; -import org.springframework.util.Assert; - -/** - * An {@link ItemReader} that pulls data from a {@link Iterator} or - * {@link Iterable} using the constructors. - * - * @author Juliusz Brzostek - * @author Dave Syer - */ -public class IteratorItemReader implements ItemReader { - - /** - * Internal iterator - */ - private final Iterator iterator; - - /** - * Construct a new reader from this iterable (could be a collection), by - * extracting an instance of {@link Iterator} from it. - * - * @param iterable in instance of {@link Iterable} - * - * @see Iterable#iterator() - */ - public IteratorItemReader(Iterable iterable) { - Assert.notNull(iterable, "Iterable argument cannot be null!"); - this.iterator = iterable.iterator(); - } - - /** - * Construct a new reader from this iterator directly. - * @param iterator an instance of {@link Iterator} - */ - public IteratorItemReader(Iterator iterator) { - Assert.notNull(iterator, "Iterator argument cannot be null!"); - this.iterator = iterator; - } - - /** - * Implementation of {@link ItemReader#read()} that just iterates over the - * iterator provided. - */ - @Override - public T read() { - if (iterator.hasNext()) - return iterator.next(); - else - return null; // end of data - } - -} +/* + * Copyright 2006-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.batch.item.support; + +import java.util.Iterator; + +import org.springframework.batch.item.ItemReader; +import org.springframework.util.Assert; + +/** + * An {@link ItemReader} that pulls data from a {@link Iterator} or + * {@link Iterable} using the constructors. + * + * @author Juliusz Brzostek + * @author Dave Syer + * @author Mahmoud Ben Hassine + */ +public class IteratorItemReader implements ItemReader { + + /** + * Internal iterator + */ + private final Iterator iterator; + + /** + * Construct a new reader from this iterable (could be a collection), by + * extracting an instance of {@link Iterator} from it. + * + * @param iterable in instance of {@link Iterable} + * + * @see Iterable#iterator() + */ + public IteratorItemReader(Iterable iterable) { + Assert.notNull(iterable, "Iterable argument cannot be null!"); + this.iterator = iterable.iterator(); + } + + /** + * Construct a new reader from this iterator directly. + * @param iterator an instance of {@link Iterator} + */ + public IteratorItemReader(Iterator iterator) { + Assert.notNull(iterator, "Iterator argument cannot be null!"); + this.iterator = iterator; + } + + /** + * Implementation of {@link ItemReader#read()} that just iterates over the + * iterator provided. + */ + @Override + public T read() { + if (iterator.hasNext()) + return iterator.next(); + else + return null; // end of data + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/ClassifierCompositeItemWriterBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/ClassifierCompositeItemWriterBuilder.java index fc2060b54..ee4365e4f 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/ClassifierCompositeItemWriterBuilder.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/support/builder/ClassifierCompositeItemWriterBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,13 @@ package org.springframework.batch.item.support.builder; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.support.ClassifierCompositeItemWriter; import org.springframework.classify.Classifier; -import org.springframework.classify.ClassifierSupport; import org.springframework.util.Assert; /** * Creates a fully qualified ClassifierCompositeItemWriter. * * @author Glenn Renfro + * @author Mahmoud Ben Hassine * * @since 4.0 */ diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderTests.java index a08707fe9..542b5f4cf 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/file/FlatFileItemReaderTests.java @@ -1,586 +1,584 @@ -/* - * Copyright 2008-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.batch.item.file; - -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.io.InputStream; - -import javax.swing.Spring; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.batch.item.ExecutionContext; -import org.springframework.batch.item.ItemCountAware; -import org.springframework.batch.item.ItemStreamException; -import org.springframework.batch.item.file.mapping.PassThroughLineMapper; -import org.springframework.batch.item.file.separator.RecordSeparatorPolicy; -import org.springframework.core.io.AbstractResource; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; - -/** - * Tests for {@link FlatFileItemReader}. - */ -public class FlatFileItemReaderTests { - - // common value used for writing to a file - private String TEST_STRING = "FlatFileInputTemplate-TestData"; - - private FlatFileItemReader reader = new FlatFileItemReader<>(); - - private FlatFileItemReader itemReader = new FlatFileItemReader<>(); - - private ExecutionContext executionContext = new ExecutionContext(); - - private Resource inputResource2 = getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6"); - - private Resource inputResource1 = getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6"); - - @Before - public void setUp() { - - reader.setResource(inputResource1); - reader.setLineMapper(new PassThroughLineMapper()); - - itemReader.setResource(inputResource2); - itemReader.setLineMapper(new ItemLineMapper()); - } - - @Test - public void testRestartWithCustomRecordSeparatorPolicy() throws Exception { - - reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { - // 1 record = 2 lines - boolean pair = true; - - @Override - public boolean isEndOfRecord(String line) { - pair = !pair; - return pair; - } - - @Override - public String postProcess(String record) { - return record; - } - - @Override - public String preProcess(String record) { - return record; - } - }); - - reader.open(executionContext); - - assertEquals("testLine1testLine2", reader.read()); - assertEquals("testLine3testLine4", reader.read()); - - reader.update(executionContext); - - reader.close(); - - reader.open(executionContext); - - assertEquals("testLine5testLine6", reader.read()); - } - - @Test - public void testCustomRecordSeparatorPolicyEndOfFile() throws Exception { - - reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { - // 1 record = 2 lines - boolean pair = true; - - @Override - public boolean isEndOfRecord(String line) { - pair = !pair; - return pair; - } - - @Override - public String postProcess(String record) { - return record; - } - - @Override - public String preProcess(String record) { - return record; - } - }); - - reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\n")); - reader.open(executionContext); - - assertEquals("testLine1testLine2", reader.read()); - - try { - reader.read(); - fail("Expected Exception"); - } - catch (FlatFileParseException e) { - // File ends in the middle of a record - assertEquals(3, e.getLineNumber()); - assertEquals("testLine3", e.getInput()); - } - - } - - @Test - public void testCustomRecordSeparatorBlankLine() throws Exception { - - reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { - - @Override - public boolean isEndOfRecord(String line) { - return StringUtils.hasText(line); - } - - @Override - public String postProcess(String record) { - return StringUtils.hasText(record) ? record : null; - } - - @Override - public String preProcess(String record) { - return record; - } - }); - - reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\n\n")); - reader.open(executionContext); - - assertEquals("testLine1", reader.read()); - assertEquals("testLine2", reader.read()); - assertEquals("testLine3", reader.read()); - assertEquals(null, reader.read()); - - } - - @Test - public void testCustomRecordSeparatorMultilineBlankLineAfterEnd() throws Exception { - - reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { - - // 1 record = 2 lines - boolean pair = true; - - @Override - public boolean isEndOfRecord(String line) { - if (StringUtils.hasText(line)) { - pair = !pair; - } - return pair; - } - - @Override - public String postProcess(String record) { - return StringUtils.hasText(record) ? record : null; - } - - @Override - public String preProcess(String record) { - return record; - } - }); - - reader.setResource(getInputResource("testLine1\ntestLine2\n\n")); - reader.open(executionContext); - - assertEquals("testLine1testLine2", reader.read()); - assertEquals(null, reader.read()); - - } - - @Test - public void testRestartWithSkippedLines() throws Exception { - - reader.setLinesToSkip(2); - reader.open(executionContext); - - // read some records - reader.read(); - reader.read(); - // get restart data - reader.update(executionContext); - // read next two records - reader.read(); - reader.read(); - - assertEquals(2, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); - // close input - reader.close(); - - reader.setResource(getInputResource("header\nignoreme\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); - - // init for restart - reader.open(executionContext); - - // read remaining records - assertEquals("testLine3", reader.read()); - assertEquals("testLine4", reader.read()); - - reader.update(executionContext); - assertEquals(4, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); - } - - @Test - public void testCurrentItemCount() throws Exception { - - reader.setCurrentItemCount(2); - reader.open(executionContext); - - // read some records - reader.read(); - reader.read(); - // get restart data - reader.update(executionContext); - - assertEquals(4, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); - // close input - reader.close(); - - } - - @Test - public void testMaxItemCount() throws Exception { - - reader.setMaxItemCount(2); - reader.open(executionContext); - - // read some records - reader.read(); - reader.read(); - // get restart data - reader.update(executionContext); - assertNull(reader.read()); - - assertEquals(2, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); - // close input - reader.close(); - - } - - @Test - public void testMaxItemCountFromContext() throws Exception { - - reader.setMaxItemCount(2); - executionContext.putInt(reader.getClass().getSimpleName() + ".read.count.max", Integer.MAX_VALUE); - reader.open(executionContext); - // read some records - reader.read(); - reader.read(); - assertNotNull(reader.read()); - // close input - reader.close(); - - } - - @Test - public void testCurrentItemCountFromContext() throws Exception { - - reader.setCurrentItemCount(2); - executionContext.putInt(reader.getClass().getSimpleName() + ".read.count", 3); - reader.open(executionContext); - // read some records - assertEquals("testLine4", reader.read()); - // close input - reader.close(); - - } - - @Test - public void testMaxAndCurrentItemCount() throws Exception { - - reader.setMaxItemCount(2); - reader.setCurrentItemCount(2); - reader.open(executionContext); - // read some records - assertNull(reader.read()); - // close input - reader.close(); - - } - - @Test - public void testNonExistentResource() throws Exception { - - Resource resource = new NonExistentResource(); - - reader.setResource(resource); - - // afterPropertiesSet should only throw an exception if the Resource is - // null - reader.afterPropertiesSet(); - - reader.setStrict(false); - reader.open(executionContext); - assertNull(reader.read()); - reader.close(); - } - - @Test - public void testOpenBadIOInput() throws Exception { - - reader.setResource(new AbstractResource() { - @Override - public String getDescription() { - return null; - } - - @Override - public InputStream getInputStream() throws IOException { - throw new IOException(); - } - - @Override - public boolean exists() { - return true; - } - }); - - try { - reader.open(executionContext); - fail(); - } - catch (ItemStreamException ex) { - // expected - } - - // read() should then return a null - assertNull(reader.read()); - reader.close(); - - } - - @Test - public void testDirectoryResource() throws Exception { - - FileSystemResource resource = new FileSystemResource("build/data"); - resource.getFile().mkdirs(); - assertTrue(resource.getFile().isDirectory()); - reader.setResource(resource); - reader.afterPropertiesSet(); - - reader.setStrict(false); - reader.open(executionContext); - assertNull(reader.read()); - - } - - @Test - public void testRuntimeFileCreation() throws Exception { - - Resource resource = new NonExistentResource(); - - reader.setResource(resource); - - // afterPropertiesSet should only throw an exception if the Resource is - // null - reader.afterPropertiesSet(); - - // replace the resource to simulate runtime resource creation - reader.setResource(getInputResource(TEST_STRING)); - reader.open(executionContext); - assertEquals(TEST_STRING, reader.read()); - } - - /** - * In strict mode, resource must exist at the time reader is opened. - */ - @Test(expected = ItemStreamException.class) - public void testStrictness() throws Exception { - - Resource resource = new NonExistentResource(); - - reader.setResource(resource); - reader.setStrict(true); - - reader.afterPropertiesSet(); - - reader.open(executionContext); - } - - /** - * Exceptions from {@link LineMapper} are wrapped as {@link FlatFileParseException} containing contextual info about - * the problematic line and its line number. - */ - @Test - public void testMappingExceptionWrapping() throws Exception { - LineMapper exceptionLineMapper = new LineMapper() { - @Override - public String mapLine(String line, int lineNumber) throws Exception { - if (lineNumber == 2) { - throw new Exception("Couldn't map line 2"); - } - return line; - } - }; - reader.setLineMapper(exceptionLineMapper); - reader.afterPropertiesSet(); - - reader.open(executionContext); - assertNotNull(reader.read()); - - try { - reader.read(); - fail(); - } - catch (FlatFileParseException expected) { - assertEquals(2, expected.getLineNumber()); - assertEquals("testLine2", expected.getInput()); - assertEquals("Couldn't map line 2", expected.getCause().getMessage()); - assertThat(expected.getMessage(), startsWith("Parsing error at line: 2 in resource=[")); - assertThat(expected.getMessage(), endsWith("], input=[testLine2]")); - } - } - - @Test - public void testItemCountAware() throws Exception { - itemReader.open(executionContext); - Item item1 = itemReader.read(); - assertEquals("testLine1", item1.getValue()); - assertEquals(1, item1.getItemCount()); - Item item2 = itemReader.read(); - assertEquals("testLine2", item2.getValue()); - assertEquals(2, item2.getItemCount()); - itemReader.update(executionContext); - itemReader.close(); - - itemReader.open(executionContext); - Item item3 = itemReader.read(); - assertEquals("testLine3", item3.getValue()); - assertEquals(3, item3.getItemCount()); - } - - @Test - public void testItemCountAwareMultiLine() throws Exception { - itemReader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { - - // 1 record = 2 lines - boolean pair = true; - - @Override - public boolean isEndOfRecord(String line) { - if (StringUtils.hasText(line)) { - pair = !pair; - } - return pair; - } - - @Override - public String postProcess(String record) { - return StringUtils.hasText(record) ? record : null; - } - - @Override - public String preProcess(String record) { - return record; - } - }); - - itemReader.open(executionContext); - Item item1 = itemReader.read(); - assertEquals("testLine1testLine2", item1.getValue()); - assertEquals(1, item1.getItemCount()); - Item item2 = itemReader.read(); - assertEquals("testLine3testLine4", item2.getValue()); - assertEquals(2, item2.getItemCount()); - itemReader.update(executionContext); - itemReader.close(); - - itemReader.open(executionContext); - Item item3 = itemReader.read(); - assertEquals("testLine5testLine6", item3.getValue()); - assertEquals(3, item3.getItemCount()); - } - - private Resource getInputResource(String input) { - return new ByteArrayResource(input.getBytes()); - } - - private static class NonExistentResource extends AbstractResource { - - public NonExistentResource() { - } - - @Override - public boolean exists() { - return false; - } - - @Override - public String getDescription() { - return "NonExistentResource"; - } - - @Override - public InputStream getInputStream() throws IOException { - return null; - } - } - - private static class Item implements ItemCountAware { - - private String value; - - private int itemCount; - - public Item(String value) { - this.value = value; - } - - @SuppressWarnings("unused") - public void setValue(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - @Override - public void setItemCount(int count) { - this.itemCount = count; - } - - public int getItemCount() { - return itemCount; - } - - } - - private static final class ItemLineMapper implements LineMapper { - - @Override - public Item mapLine(String line, int lineNumber) throws Exception { - return new Item(line); - } - - } -} +/* + * Copyright 2008-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.file; + +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.ItemCountAware; +import org.springframework.batch.item.ItemStreamException; +import org.springframework.batch.item.file.mapping.PassThroughLineMapper; +import org.springframework.batch.item.file.separator.RecordSeparatorPolicy; +import org.springframework.core.io.AbstractResource; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +/** + * Tests for {@link FlatFileItemReader}. + */ +public class FlatFileItemReaderTests { + + // common value used for writing to a file + private String TEST_STRING = "FlatFileInputTemplate-TestData"; + + private FlatFileItemReader reader = new FlatFileItemReader<>(); + + private FlatFileItemReader itemReader = new FlatFileItemReader<>(); + + private ExecutionContext executionContext = new ExecutionContext(); + + private Resource inputResource2 = getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6"); + + private Resource inputResource1 = getInputResource("testLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6"); + + @Before + public void setUp() { + + reader.setResource(inputResource1); + reader.setLineMapper(new PassThroughLineMapper()); + + itemReader.setResource(inputResource2); + itemReader.setLineMapper(new ItemLineMapper()); + } + + @Test + public void testRestartWithCustomRecordSeparatorPolicy() throws Exception { + + reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { + // 1 record = 2 lines + boolean pair = true; + + @Override + public boolean isEndOfRecord(String line) { + pair = !pair; + return pair; + } + + @Override + public String postProcess(String record) { + return record; + } + + @Override + public String preProcess(String record) { + return record; + } + }); + + reader.open(executionContext); + + assertEquals("testLine1testLine2", reader.read()); + assertEquals("testLine3testLine4", reader.read()); + + reader.update(executionContext); + + reader.close(); + + reader.open(executionContext); + + assertEquals("testLine5testLine6", reader.read()); + } + + @Test + public void testCustomRecordSeparatorPolicyEndOfFile() throws Exception { + + reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { + // 1 record = 2 lines + boolean pair = true; + + @Override + public boolean isEndOfRecord(String line) { + pair = !pair; + return pair; + } + + @Override + public String postProcess(String record) { + return record; + } + + @Override + public String preProcess(String record) { + return record; + } + }); + + reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\n")); + reader.open(executionContext); + + assertEquals("testLine1testLine2", reader.read()); + + try { + reader.read(); + fail("Expected Exception"); + } + catch (FlatFileParseException e) { + // File ends in the middle of a record + assertEquals(3, e.getLineNumber()); + assertEquals("testLine3", e.getInput()); + } + + } + + @Test + public void testCustomRecordSeparatorBlankLine() throws Exception { + + reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { + + @Override + public boolean isEndOfRecord(String line) { + return StringUtils.hasText(line); + } + + @Override + public String postProcess(String record) { + return StringUtils.hasText(record) ? record : null; + } + + @Override + public String preProcess(String record) { + return record; + } + }); + + reader.setResource(getInputResource("testLine1\ntestLine2\ntestLine3\n\n")); + reader.open(executionContext); + + assertEquals("testLine1", reader.read()); + assertEquals("testLine2", reader.read()); + assertEquals("testLine3", reader.read()); + assertEquals(null, reader.read()); + + } + + @Test + public void testCustomRecordSeparatorMultilineBlankLineAfterEnd() throws Exception { + + reader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { + + // 1 record = 2 lines + boolean pair = true; + + @Override + public boolean isEndOfRecord(String line) { + if (StringUtils.hasText(line)) { + pair = !pair; + } + return pair; + } + + @Override + public String postProcess(String record) { + return StringUtils.hasText(record) ? record : null; + } + + @Override + public String preProcess(String record) { + return record; + } + }); + + reader.setResource(getInputResource("testLine1\ntestLine2\n\n")); + reader.open(executionContext); + + assertEquals("testLine1testLine2", reader.read()); + assertEquals(null, reader.read()); + + } + + @Test + public void testRestartWithSkippedLines() throws Exception { + + reader.setLinesToSkip(2); + reader.open(executionContext); + + // read some records + reader.read(); + reader.read(); + // get restart data + reader.update(executionContext); + // read next two records + reader.read(); + reader.read(); + + assertEquals(2, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); + // close input + reader.close(); + + reader.setResource(getInputResource("header\nignoreme\ntestLine1\ntestLine2\ntestLine3\ntestLine4\ntestLine5\ntestLine6")); + + // init for restart + reader.open(executionContext); + + // read remaining records + assertEquals("testLine3", reader.read()); + assertEquals("testLine4", reader.read()); + + reader.update(executionContext); + assertEquals(4, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); + } + + @Test + public void testCurrentItemCount() throws Exception { + + reader.setCurrentItemCount(2); + reader.open(executionContext); + + // read some records + reader.read(); + reader.read(); + // get restart data + reader.update(executionContext); + + assertEquals(4, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); + // close input + reader.close(); + + } + + @Test + public void testMaxItemCount() throws Exception { + + reader.setMaxItemCount(2); + reader.open(executionContext); + + // read some records + reader.read(); + reader.read(); + // get restart data + reader.update(executionContext); + assertNull(reader.read()); + + assertEquals(2, executionContext.getInt(ClassUtils.getShortName(FlatFileItemReader.class) + ".read.count")); + // close input + reader.close(); + + } + + @Test + public void testMaxItemCountFromContext() throws Exception { + + reader.setMaxItemCount(2); + executionContext.putInt(reader.getClass().getSimpleName() + ".read.count.max", Integer.MAX_VALUE); + reader.open(executionContext); + // read some records + reader.read(); + reader.read(); + assertNotNull(reader.read()); + // close input + reader.close(); + + } + + @Test + public void testCurrentItemCountFromContext() throws Exception { + + reader.setCurrentItemCount(2); + executionContext.putInt(reader.getClass().getSimpleName() + ".read.count", 3); + reader.open(executionContext); + // read some records + assertEquals("testLine4", reader.read()); + // close input + reader.close(); + + } + + @Test + public void testMaxAndCurrentItemCount() throws Exception { + + reader.setMaxItemCount(2); + reader.setCurrentItemCount(2); + reader.open(executionContext); + // read some records + assertNull(reader.read()); + // close input + reader.close(); + + } + + @Test + public void testNonExistentResource() throws Exception { + + Resource resource = new NonExistentResource(); + + reader.setResource(resource); + + // afterPropertiesSet should only throw an exception if the Resource is + // null + reader.afterPropertiesSet(); + + reader.setStrict(false); + reader.open(executionContext); + assertNull(reader.read()); + reader.close(); + } + + @Test + public void testOpenBadIOInput() throws Exception { + + reader.setResource(new AbstractResource() { + @Override + public String getDescription() { + return null; + } + + @Override + public InputStream getInputStream() throws IOException { + throw new IOException(); + } + + @Override + public boolean exists() { + return true; + } + }); + + try { + reader.open(executionContext); + fail(); + } + catch (ItemStreamException ex) { + // expected + } + + // read() should then return a null + assertNull(reader.read()); + reader.close(); + + } + + @Test + public void testDirectoryResource() throws Exception { + + FileSystemResource resource = new FileSystemResource("build/data"); + resource.getFile().mkdirs(); + assertTrue(resource.getFile().isDirectory()); + reader.setResource(resource); + reader.afterPropertiesSet(); + + reader.setStrict(false); + reader.open(executionContext); + assertNull(reader.read()); + + } + + @Test + public void testRuntimeFileCreation() throws Exception { + + Resource resource = new NonExistentResource(); + + reader.setResource(resource); + + // afterPropertiesSet should only throw an exception if the Resource is + // null + reader.afterPropertiesSet(); + + // replace the resource to simulate runtime resource creation + reader.setResource(getInputResource(TEST_STRING)); + reader.open(executionContext); + assertEquals(TEST_STRING, reader.read()); + } + + /** + * In strict mode, resource must exist at the time reader is opened. + */ + @Test(expected = ItemStreamException.class) + public void testStrictness() throws Exception { + + Resource resource = new NonExistentResource(); + + reader.setResource(resource); + reader.setStrict(true); + + reader.afterPropertiesSet(); + + reader.open(executionContext); + } + + /** + * Exceptions from {@link LineMapper} are wrapped as {@link FlatFileParseException} containing contextual info about + * the problematic line and its line number. + */ + @Test + public void testMappingExceptionWrapping() throws Exception { + LineMapper exceptionLineMapper = new LineMapper() { + @Override + public String mapLine(String line, int lineNumber) throws Exception { + if (lineNumber == 2) { + throw new Exception("Couldn't map line 2"); + } + return line; + } + }; + reader.setLineMapper(exceptionLineMapper); + reader.afterPropertiesSet(); + + reader.open(executionContext); + assertNotNull(reader.read()); + + try { + reader.read(); + fail(); + } + catch (FlatFileParseException expected) { + assertEquals(2, expected.getLineNumber()); + assertEquals("testLine2", expected.getInput()); + assertEquals("Couldn't map line 2", expected.getCause().getMessage()); + assertThat(expected.getMessage(), startsWith("Parsing error at line: 2 in resource=[")); + assertThat(expected.getMessage(), endsWith("], input=[testLine2]")); + } + } + + @Test + public void testItemCountAware() throws Exception { + itemReader.open(executionContext); + Item item1 = itemReader.read(); + assertEquals("testLine1", item1.getValue()); + assertEquals(1, item1.getItemCount()); + Item item2 = itemReader.read(); + assertEquals("testLine2", item2.getValue()); + assertEquals(2, item2.getItemCount()); + itemReader.update(executionContext); + itemReader.close(); + + itemReader.open(executionContext); + Item item3 = itemReader.read(); + assertEquals("testLine3", item3.getValue()); + assertEquals(3, item3.getItemCount()); + } + + @Test + public void testItemCountAwareMultiLine() throws Exception { + itemReader.setRecordSeparatorPolicy(new RecordSeparatorPolicy() { + + // 1 record = 2 lines + boolean pair = true; + + @Override + public boolean isEndOfRecord(String line) { + if (StringUtils.hasText(line)) { + pair = !pair; + } + return pair; + } + + @Override + public String postProcess(String record) { + return StringUtils.hasText(record) ? record : null; + } + + @Override + public String preProcess(String record) { + return record; + } + }); + + itemReader.open(executionContext); + Item item1 = itemReader.read(); + assertEquals("testLine1testLine2", item1.getValue()); + assertEquals(1, item1.getItemCount()); + Item item2 = itemReader.read(); + assertEquals("testLine3testLine4", item2.getValue()); + assertEquals(2, item2.getItemCount()); + itemReader.update(executionContext); + itemReader.close(); + + itemReader.open(executionContext); + Item item3 = itemReader.read(); + assertEquals("testLine5testLine6", item3.getValue()); + assertEquals(3, item3.getItemCount()); + } + + private Resource getInputResource(String input) { + return new ByteArrayResource(input.getBytes()); + } + + private static class NonExistentResource extends AbstractResource { + + public NonExistentResource() { + } + + @Override + public boolean exists() { + return false; + } + + @Override + public String getDescription() { + return "NonExistentResource"; + } + + @Override + public InputStream getInputStream() throws IOException { + return null; + } + } + + private static class Item implements ItemCountAware { + + private String value; + + private int itemCount; + + public Item(String value) { + this.value = value; + } + + @SuppressWarnings("unused") + public void setValue(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public void setItemCount(int count) { + this.itemCount = count; + } + + public int getItemCount() { + return itemCount; + } + + } + + private static final class ItemLineMapper implements LineMapper { + + @Override + public Item mapLine(String line, int lineNumber) throws Exception { + return new Item(line); + } + + } +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemReaderBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemReaderBuilderTests.java index ace6ee612..84741b970 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemReaderBuilderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemReaderBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import org.junit.Test; import org.springframework.batch.item.jms.JmsItemReader; import org.springframework.jms.core.JmsOperations; -import org.springframework.jms.core.JmsTemplate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -35,6 +34,7 @@ import static org.mockito.Mockito.when; /** * @author Glenn Renfro + * @author Mahmoud Ben Hassine */ public class JmsItemReaderBuilderTests { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemWriterBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemWriterBuilderTests.java index 7009dfb02..bd8884481 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemWriterBuilderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/jms/builder/JmsItemWriterBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,6 @@ import org.mockito.ArgumentCaptor; import org.springframework.batch.item.jms.JmsItemWriter; import org.springframework.jms.core.JmsOperations; -import org.springframework.jms.core.JmsTemplate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -33,6 +32,7 @@ import static org.mockito.Mockito.verify; /** * @author Glenn Renfro + * @author Mahmoud Ben Hassine */ public class JmsItemWriterBuilderTests {