Skip to content

Commit

Permalink
Update guide
Browse files Browse the repository at this point in the history
- Use Java records for domain types
- Update Spring dependency injection style
- Update Spring Boot version to 3.1.4
- Update README.adoc
- Clean up code
  • Loading branch information
fmbenhassine committed Oct 17, 2023
1 parent bb01474 commit 7e313e5
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 86 deletions.
34 changes: 15 additions & 19 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ include::complete/src/main/java/com/example/batchprocessing/Person.java[]
----
====

You can instantiate the `Person` class either with first and last name through a
constructor or by setting the properties.

You can instantiate the `Person` record with first name and last name through the constructor.

== Create an Intermediate Processor

Expand Down Expand Up @@ -131,9 +129,8 @@ parses each line item with enough information to turn it into a `Person`.
* `processor()` creates an instance of the `PersonItemProcessor` that you defined earlier,
meant to convert the data to upper case.
* `writer(DataSource)` creates an `ItemWriter`. This one is aimed at a JDBC destination and
automatically gets a copy of the dataSource created by `@EnableBatchProcessing`. It
includes the SQL statement needed to insert a single `Person`, driven by Java bean
properties.
automatically gets a copy of the dataSource created by Spring Boot. It
includes the SQL statement needed to insert a single `Person`, driven by Java record components.

The last chunk (from `src/main/java/com/example/batchprocessing/BatchConfiguration.java`)
shows the actual job configuration:
Expand All @@ -148,12 +145,11 @@ include::complete/src/main/java/com/example/batchprocessing/BatchConfiguration.j
The first method defines the job, and the second one defines a single step. Jobs are built
from steps, where each step can involve a reader, a processor, and a writer.

In this job definition, you need an incrementer, because jobs use a database to maintain
execution state. You then list each step, (though this job has only one step). The job
You then list each step, (though this job has only one step). The job
ends, and the Java API produces a perfectly configured job.

In the step definition, you define how much data to write at a time. In this case, it
writes up to ten records at a time. Next, you configure the reader, processor, and writer
writes up to three records at a time. Next, you configure the reader, processor, and writer
by using the beans injected earlier.

NOTE: `chunk()` is prefixed `<Person,Person>` because it is a generic method. This
Expand Down Expand Up @@ -210,16 +206,16 @@ output:
====
[source,text]
----
Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)
Converting (firstName: Joe, lastName: Doe) into (firstName: JOE, lastName: DOE)
Converting (firstName: Justin, lastName: Doe) into (firstName: JUSTIN, lastName: DOE)
Converting (firstName: Jane, lastName: Doe) into (firstName: JANE, lastName: DOE)
Converting (firstName: John, lastName: Doe) into (firstName: JOHN, lastName: DOE)
Found <firstName: JILL, lastName: DOE> in the database.
Found <firstName: JOE, lastName: DOE> in the database.
Found <firstName: JUSTIN, lastName: DOE> in the database.
Found <firstName: JANE, lastName: DOE> in the database.
Found <firstName: JOHN, lastName: DOE> in the database.
Converting (Person[firstName=Jill, lastName=Doe]) into (Person[firstName=JILL, lastName=DOE])
Converting (Person[firstName=Joe, lastName=Doe]) into (Person[firstName=JOE, lastName=DOE])
Converting (Person[firstName=Justin, lastName=Doe]) into (Person[firstName=JUSTIN, lastName=DOE])
Converting (Person[firstName=Jane, lastName=Doe]) into (Person[firstName=JANE, lastName=DOE])
Converting (Person[firstName=John, lastName=Doe]) into (Person[firstName=JOHN, lastName=DOE])
Found <{Person[firstName=JILL, lastName=DOE]}> in the database.
Found <{Person[firstName=JOE, lastName=DOE]}> in the database.
Found <{Person[firstName=JUSTIN, lastName=DOE]}> in the database.
Found <{Person[firstName=JANE, lastName=DOE]}> in the database.
Found <{Person[firstName=JOHN, lastName=DOE]}> in the database.
----
====

Expand Down
2 changes: 1 addition & 1 deletion complete/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'org.springframework.boot' version '3.1.2'
id 'org.springframework.boot' version '3.1.4'
id 'io.spring.dependency-management' version '1.1.2'
id 'java'
}
Expand Down
2 changes: 1 addition & 1 deletion complete/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.2</version>
<version>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration
public class BatchConfiguration {
Expand All @@ -29,10 +26,8 @@ public FlatFileItemReader<Person> reader() {
.name("personItemReader")
.resource(new ClassPathResource("sample-data.csv"))
.delimited()
.names(new String[]{"firstName", "lastName"})
.fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
setTargetType(Person.class);
}})
.names("firstName", "lastName")
.targetType(Person.class)
.build();
}

Expand All @@ -44,32 +39,29 @@ public PersonItemProcessor processor() {
@Bean
public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<Person>()
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
.dataSource(dataSource)
.beanMapped()
.build();
}
// end::readerwriterprocessor[]

// tag::jobstep[]
@Bean
public Job importUserJob(JobRepository jobRepository,
JobCompletionNotificationListener listener, Step step1) {
public Job importUserJob(JobRepository jobRepository,Step step1, JobCompletionNotificationListener listener) {
return new JobBuilder("importUserJob", jobRepository)
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step1)
.end()
.start(step1)
.build();
}

@Bean
public Step step1(JobRepository jobRepository,
PlatformTransactionManager transactionManager, JdbcBatchItemWriter<Person> writer) {
public Step step1(JobRepository jobRepository, DataSourceTransactionManager transactionManager,
FlatFileItemReader<Person> reader, PersonItemProcessor processor, JdbcBatchItemWriter<Person> writer) {
return new StepBuilder("step1", jobRepository)
.<Person, Person> chunk(10, transactionManager)
.reader(reader())
.processor(processor())
.<Person, Person> chunk(3, transactionManager)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@SpringBootApplication
public class BatchProcessingApplication {

public static void main(String[] args) throws Exception {
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(BatchProcessingApplication.class, args)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.DataClassRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

Expand All @@ -16,7 +17,6 @@ public class JobCompletionNotificationListener implements JobExecutionListener {

private final JdbcTemplate jdbcTemplate;

@Autowired
public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
Expand All @@ -26,11 +26,9 @@ public void afterJob(JobExecution jobExecution) {
if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
log.info("!!! JOB FINISHED! Time to verify the results");

jdbcTemplate.query("SELECT first_name, last_name FROM people",
(rs, row) -> new Person(
rs.getString(1),
rs.getString(2))
).forEach(person -> log.info("Found <{{}}> in the database.", person));
jdbcTemplate
.query("SELECT first_name, last_name FROM people", new DataClassRowMapper<>(Person.class))
.forEach(person -> log.info("Found <{{}}> in the database.", person));
}
}
}
34 changes: 1 addition & 33 deletions complete/src/main/java/com/example/batchprocessing/Person.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,5 @@
package com.example.batchprocessing;

public class Person {

private String lastName;
private String firstName;

public Person() {
}

public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

@Override
public String toString() {
return "firstName: " + firstName + ", lastName: " + lastName;
}
public record Person(String firstName, String lastName) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ public class PersonItemProcessor implements ItemProcessor<Person, Person> {
private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class);

@Override
public Person process(final Person person) throws Exception {
final String firstName = person.getFirstName().toUpperCase();
final String lastName = person.getLastName().toUpperCase();
public Person process(final Person person) {
final String firstName = person.firstName().toUpperCase();
final String lastName = person.lastName().toUpperCase();

final Person transformedPerson = new Person(firstName, lastName);

Expand Down
2 changes: 1 addition & 1 deletion initial/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id 'org.springframework.boot' version '3.1.2'
id 'org.springframework.boot' version '3.1.4'
id 'io.spring.dependency-management' version '1.1.2'
id 'java'
}
Expand Down
2 changes: 1 addition & 1 deletion initial/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.2</version>
<version>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
Expand Down

0 comments on commit 7e313e5

Please sign in to comment.