Add composite item reader implementation

Resolves #757
This commit is contained in:
Mahmoud Ben Hassine
2024-10-03 09:36:27 +02:00
parent ea378b9a2c
commit 6cc718a78c
9 changed files with 381 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
## Composite ItemReader Sample
### About
This sample shows how to use a composite item reader to read data with
the same format from different data sources.
In this sample, data items of type `Person` are read from two flat files
and a relational database table.
### Run the sample
You can run the sample from the command line as following:
```
$>cd spring-batch-samples
$>../mvnw -Dtest=CompositeItemReaderSampleFunctionalTests#testJobLaunch test
```

View File

@@ -0,0 +1,2 @@
1,foo1
2,foo2
1 1 foo1
2 2 foo2

View File

@@ -0,0 +1,2 @@
3,bar1
4,bar2
1 3 bar1
2 4 bar2

View File

@@ -0,0 +1,2 @@
insert into person_source values (5, 'baz1');
insert into person_source values (6, 'baz2');

View File

@@ -0,0 +1,2 @@
create table person_source (id int primary key, name varchar(20));
create table person_target (id int primary key, name varchar(20));

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2024 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
*
* https://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.samples.compositereader;
import java.util.Arrays;
import javax.sql.DataSource;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.support.CompositeItemReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.DataClassRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.jdbc.support.JdbcTransactionManager;
import org.springframework.test.jdbc.JdbcTestUtils;
public class CompositeItemWriterSampleFunctionalTests {
record Person(int id, String name) {
}
@Test
void testJobLaunch() throws Exception {
// given
ApplicationContext context = new AnnotationConfigApplicationContext(JobConfiguration.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
// when
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
// then
Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
JdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(DataSource.class));
int personsCount = JdbcTestUtils.countRowsInTable(jdbcTemplate, "person_target");
Assertions.assertEquals(6, personsCount);
}
@Configuration
@EnableBatchProcessing
static class JobConfiguration {
@Bean
public FlatFileItemReader<Person> itemReader1() {
return new FlatFileItemReaderBuilder<Person>().name("personItemReader1")
.resource(new ClassPathResource("org/springframework/batch/samples/compositereader/data/persons1.csv"))
.delimited()
.names("id", "name")
.targetType(Person.class)
.build();
}
@Bean
public FlatFileItemReader<Person> itemReader2() {
return new FlatFileItemReaderBuilder<Person>().name("personItemReader2")
.resource(new ClassPathResource("org/springframework/batch/samples/compositereader/data/persons2.csv"))
.delimited()
.names("id", "name")
.targetType(Person.class)
.build();
}
@Bean
public JdbcCursorItemReader<Person> itemReader3() {
String sql = "select * from person_source";
return new JdbcCursorItemReaderBuilder<Person>().name("personItemReader3")
.dataSource(dataSource())
.sql(sql)
.rowMapper(new DataClassRowMapper<>(Person.class))
.build();
}
@Bean
public CompositeItemReader<Person> itemReader() {
return new CompositeItemReader<>(Arrays.asList(itemReader1(), itemReader2(), itemReader3()));
}
@Bean
public JdbcBatchItemWriter<Person> itemWriter() {
String sql = "insert into person_target (id, name) values (:id, :name)";
return new JdbcBatchItemWriterBuilder<Person>().dataSource(dataSource()).sql(sql).beanMapped().build();
}
@Bean
public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager) {
return new JobBuilder("job", jobRepository)
.start(new StepBuilder("step", jobRepository).<Person, Person>chunk(5, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.build())
.build();
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
.addScript("/org/springframework/batch/core/schema-hsqldb.sql")
.addScript("/org/springframework/batch/samples/compositereader/sql/schema.sql")
.addScript("/org/springframework/batch/samples/compositereader/sql/data.sql")
.build();
}
@Bean
public JdbcTransactionManager transactionManager(DataSource dataSource) {
return new JdbcTransactionManager(dataSource);
}
}
}