diff --git a/spring-batch/pom.xml b/spring-batch/pom.xml
index f372ebd724..f72024d32b 100644
--- a/spring-batch/pom.xml
+++ b/spring-batch/pom.xml
@@ -18,9 +18,10 @@
UTF-8
- 4.3.4.RELEASE
- 3.0.7.RELEASE
+ 5.0.3.RELEASE
+ 4.0.0.RELEASE
3.15.1
+ 4.1
@@ -51,6 +52,16 @@
spring-batch-core
${spring.batch.version}
+
+ org.springframework.batch
+ spring-batch-test
+ ${spring.batch.version}
+
+
+ com.opencsv
+ opencsv
+ ${opencsv.version}
+
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineProcessor.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineProcessor.java
new file mode 100644
index 0000000000..5b6cd9add3
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineProcessor.java
@@ -0,0 +1,36 @@
+package org.baeldung.taskletsvschunks.chunks;
+
+import org.baeldung.taskletsvschunks.model.Line;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.item.ItemProcessor;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+
+public class LineProcessor implements ItemProcessor, StepExecutionListener {
+
+ private final Logger logger = LoggerFactory.getLogger(LineProcessor.class);
+
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ logger.debug("Line Processor initialized.");
+ }
+
+ @Override
+ public Line process(Line line) throws Exception {
+ long age = ChronoUnit.YEARS.between(line.getDob(), LocalDate.now());
+ logger.debug("Calculated age " + age + " for line " + line.toString());
+ line.setAge(age);
+ return line;
+ }
+
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ logger.debug("Line Processor ended.");
+ return ExitStatus.COMPLETED;
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineReader.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineReader.java
new file mode 100644
index 0000000000..5f6b6de218
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineReader.java
@@ -0,0 +1,36 @@
+package org.baeldung.taskletsvschunks.chunks;
+
+import org.baeldung.taskletsvschunks.model.Line;
+import org.baeldung.taskletsvschunks.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.item.ItemReader;
+
+public class LineReader implements ItemReader, StepExecutionListener {
+
+ private final Logger logger = LoggerFactory.getLogger(LineReader.class);
+ private FileUtils fu;
+
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ fu = new FileUtils("taskletsvschunks/input/tasklets-vs-chunks.csv");
+ logger.debug("Line Reader initialized.");
+ }
+
+ @Override
+ public Line read() throws Exception {
+ Line line = fu.readLine();
+ if (line != null) logger.debug("Read line: " + line.toString());
+ return line;
+ }
+
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ fu.closeReader();
+ logger.debug("Line Reader ended.");
+ return ExitStatus.COMPLETED;
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LinesWriter.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LinesWriter.java
new file mode 100644
index 0000000000..66f9103a56
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LinesWriter.java
@@ -0,0 +1,39 @@
+package org.baeldung.taskletsvschunks.chunks;
+
+import org.baeldung.taskletsvschunks.model.Line;
+import org.baeldung.taskletsvschunks.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.item.ItemWriter;
+
+import java.util.List;
+
+public class LinesWriter implements ItemWriter, StepExecutionListener {
+
+ private final Logger logger = LoggerFactory.getLogger(LinesWriter.class);
+ private FileUtils fu;
+
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ fu = new FileUtils("output.csv");
+ logger.debug("Line Writer initialized.");
+ }
+
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ fu.closeWriter();
+ logger.debug("Line Writer ended.");
+ return ExitStatus.COMPLETED;
+ }
+
+ @Override
+ public void write(List extends Line> lines) throws Exception {
+ for (Line line : lines) {
+ fu.writeLine(line);
+ logger.debug("Wrote line " + line.toString());
+ }
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/model/Line.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/model/Line.java
new file mode 100644
index 0000000000..fee6fd31a6
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/model/Line.java
@@ -0,0 +1,55 @@
+package org.baeldung.taskletsvschunks.model;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public class Line implements Serializable {
+
+ private String name;
+ private LocalDate dob;
+ private Long age;
+
+ public Line(String name, LocalDate dob) {
+ this.name = name;
+ this.dob = dob;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public LocalDate getDob() {
+ return dob;
+ }
+
+ public void setDob(LocalDate dob) {
+ this.dob = dob;
+ }
+
+ public Long getAge() {
+ return age;
+ }
+
+ public void setAge(Long age) {
+ this.age = age;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ sb.append(this.name);
+ sb.append(",");
+ sb.append(this.dob.format(DateTimeFormatter.ofPattern("MM/dd/yyyy")));
+ if (this.age != null) {
+ sb.append(",");
+ sb.append(this.age);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesProcessor.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesProcessor.java
new file mode 100644
index 0000000000..ba7a3088d5
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesProcessor.java
@@ -0,0 +1,49 @@
+package org.baeldung.taskletsvschunks.tasklets;
+
+import org.baeldung.taskletsvschunks.model.Line;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.batch.repeat.RepeatStatus;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+
+public class LinesProcessor implements Tasklet, StepExecutionListener {
+
+ private final Logger logger = LoggerFactory.getLogger(LinesProcessor.class);
+
+ private List lines;
+
+ @Override
+ public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
+ for (Line line : lines) {
+ long age = ChronoUnit.YEARS.between(line.getDob(), LocalDate.now());
+ logger.debug("Calculated age " + age + " for line " + line.toString());
+ line.setAge(age);
+ }
+ return RepeatStatus.FINISHED;
+ }
+
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ ExecutionContext executionContext = stepExecution
+ .getJobExecution()
+ .getExecutionContext();
+ this.lines = (List) executionContext.get("lines");
+ logger.debug("Lines Processor initialized.");
+ }
+
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ logger.debug("Lines Processor ended.");
+ return ExitStatus.COMPLETED;
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesReader.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesReader.java
new file mode 100644
index 0000000000..9905ee8f8a
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesReader.java
@@ -0,0 +1,53 @@
+package org.baeldung.taskletsvschunks.tasklets;
+
+import org.baeldung.taskletsvschunks.model.Line;
+import org.baeldung.taskletsvschunks.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.repeat.RepeatStatus;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LinesReader implements Tasklet, StepExecutionListener {
+
+ private final Logger logger = LoggerFactory.getLogger(LinesReader.class);
+
+ private List lines;
+ private FileUtils fu;
+
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ lines = new ArrayList();
+ fu = new FileUtils("taskletsvschunks/input/tasklets-vs-chunks.csv");
+ logger.debug("Lines Reader initialized.");
+ }
+
+ @Override
+ public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
+ Line line = fu.readLine();
+ while (line != null) {
+ lines.add(line);
+ logger.debug("Read line: " + line.toString());
+ line = fu.readLine();
+ }
+ return RepeatStatus.FINISHED;
+ }
+
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ fu.closeReader();
+ stepExecution
+ .getJobExecution()
+ .getExecutionContext()
+ .put("lines", this.lines);
+ logger.debug("Lines Reader ended.");
+ return ExitStatus.COMPLETED;
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesWriter.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesWriter.java
new file mode 100644
index 0000000000..937288a890
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesWriter.java
@@ -0,0 +1,50 @@
+package org.baeldung.taskletsvschunks.tasklets;
+
+import org.baeldung.taskletsvschunks.model.Line;
+import org.baeldung.taskletsvschunks.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepContribution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.core.scope.context.ChunkContext;
+import org.springframework.batch.core.step.tasklet.Tasklet;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.batch.repeat.RepeatStatus;
+
+import java.util.List;
+
+public class LinesWriter implements Tasklet, StepExecutionListener {
+
+ private final Logger logger = LoggerFactory.getLogger(LinesWriter.class);
+
+ private List lines;
+ private FileUtils fu;
+
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ ExecutionContext executionContext = stepExecution
+ .getJobExecution()
+ .getExecutionContext();
+ this.lines = (List) executionContext.get("lines");
+ fu = new FileUtils("output.csv");
+ logger.debug("Lines Writer initialized.");
+ }
+
+ @Override
+ public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
+ for (Line line : lines) {
+ fu.writeLine(line);
+ logger.debug("Wrote line " + line.toString());
+ }
+ return RepeatStatus.FINISHED;
+ }
+
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ fu.closeWriter();
+ logger.debug("Lines Writer ended.");
+ return ExitStatus.COMPLETED;
+ }
+}
diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/utils/FileUtils.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/utils/FileUtils.java
new file mode 100644
index 0000000000..df36d5c756
--- /dev/null
+++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/utils/FileUtils.java
@@ -0,0 +1,95 @@
+package org.baeldung.taskletsvschunks.utils;
+
+import com.opencsv.CSVReader;
+import com.opencsv.CSVWriter;
+import org.baeldung.taskletsvschunks.model.Line;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+public class FileUtils {
+
+ private final Logger logger = LoggerFactory.getLogger(FileUtils.class);
+
+ private String fileName;
+ private CSVReader CSVReader;
+ private CSVWriter CSVWriter;
+ private FileReader fileReader;
+ private FileWriter fileWriter;
+ private File file;
+
+ public FileUtils(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public Line readLine() {
+ try {
+ if (CSVReader == null) initReader();
+ String[] line = CSVReader.readNext();
+ if (line == null) return null;
+ return new Line(line[0], LocalDate.parse(line[1], DateTimeFormatter.ofPattern("MM/dd/yyyy")));
+ } catch (Exception e) {
+ logger.error("Error while reading line in file: " + this.fileName);
+ return null;
+ }
+ }
+
+ public void writeLine(Line line) {
+ try {
+ if (CSVWriter == null) initWriter();
+ String[] lineStr = new String[2];
+ lineStr[0] = line.getName();
+ lineStr[1] = line
+ .getAge()
+ .toString();
+ CSVWriter.writeNext(lineStr);
+ } catch (Exception e) {
+ logger.error("Error while writing line in file: " + this.fileName);
+ }
+ }
+
+ private void initReader() throws Exception {
+ ClassLoader classLoader = this
+ .getClass()
+ .getClassLoader();
+ if (file == null) file = new File(classLoader
+ .getResource(fileName)
+ .getFile());
+ if (fileReader == null) fileReader = new FileReader(file);
+ if (CSVReader == null) CSVReader = new CSVReader(fileReader);
+ }
+
+ private void initWriter() throws Exception {
+ if (file == null) {
+ file = new File(fileName);
+ file.createNewFile();
+ }
+ if (fileWriter == null) fileWriter = new FileWriter(file, true);
+ if (CSVWriter == null) CSVWriter = new CSVWriter(fileWriter);
+ }
+
+ public void closeWriter() {
+ try {
+ CSVWriter.close();
+ fileWriter.close();
+ } catch (IOException e) {
+ logger.error("Error while closing writer.");
+ }
+ }
+
+ public void closeReader() {
+ try {
+ CSVReader.close();
+ fileReader.close();
+ } catch (IOException e) {
+ logger.error("Error while closing reader.");
+ }
+ }
+
+}
diff --git a/spring-batch/src/main/resources/logback.xml b/spring-batch/src/main/resources/logback.xml
new file mode 100644
index 0000000000..dc9218caf3
--- /dev/null
+++ b/spring-batch/src/main/resources/logback.xml
@@ -0,0 +1,33 @@
+
+
+
+ C:\Users\admin\Desktop\Baeldung\repo\magkrause\tutorials\spring-batch\src\main\resources\taskletsvschunks\logs.log
+
+
+ %d{yyyy-MM-dd HH:mm:ss} [%thread] %level %logger{35} - %msg%n
+
+
+
+
+
+ ${DEV_HOME}/archived/debug.%d{yyyy-MM-dd}.%i.log
+
+
+ 10MB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-batch/src/main/resources/taskletsvschunks/chunks.xml b/spring-batch/src/main/resources/taskletsvschunks/chunks.xml
new file mode 100644
index 0000000000..f4b77ac10c
--- /dev/null
+++ b/spring-batch/src/main/resources/taskletsvschunks/chunks.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-batch/src/main/resources/taskletsvschunks/input/tasklets-vs-chunks.csv b/spring-batch/src/main/resources/taskletsvschunks/input/tasklets-vs-chunks.csv
new file mode 100644
index 0000000000..214bd3cb70
--- /dev/null
+++ b/spring-batch/src/main/resources/taskletsvschunks/input/tasklets-vs-chunks.csv
@@ -0,0 +1,6 @@
+Mae Hodges,10/22/1972
+Gary Potter,02/22/1953
+Betty Wise,02/17/1968
+Wayne Rose,04/06/1977
+Adam Caldwell,09/27/1995
+Lucille Phillips,05/14/1992
\ No newline at end of file
diff --git a/spring-batch/src/main/resources/taskletsvschunks/tasklets.xml b/spring-batch/src/main/resources/taskletsvschunks/tasklets.xml
new file mode 100644
index 0000000000..34ce2944bc
--- /dev/null
+++ b/spring-batch/src/main/resources/taskletsvschunks/tasklets.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java
new file mode 100644
index 0000000000..d32edaf2ce
--- /dev/null
+++ b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java
@@ -0,0 +1,24 @@
+package org.baeldung.taskletsvschunks.chunks;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.test.JobLauncherTestUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = "classpath:/taskletsvschunks/chunks.xml")
+public class ChunksTest {
+
+ @Autowired private JobLauncherTestUtils jobLauncherTestUtils;
+
+ @Test
+ public void test() throws Exception {
+ JobExecution jobExecution = jobLauncherTestUtils.launchJob();
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+}
\ No newline at end of file
diff --git a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java
new file mode 100644
index 0000000000..4702b67a5c
--- /dev/null
+++ b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java
@@ -0,0 +1,24 @@
+package org.baeldung.taskletsvschunks.tasklets;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.test.JobLauncherTestUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = "classpath:/taskletsvschunks/tasklets.xml")
+public class TaskletsTest {
+
+ @Autowired private JobLauncherTestUtils jobLauncherTestUtils;
+
+ @Test
+ public void test() throws Exception {
+ JobExecution jobExecution = jobLauncherTestUtils.launchJob();
+ Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+ }
+}
\ No newline at end of file