Skip to content

Commit 43e7c8c

Browse files
committed
Add java configuration for the fixed length file import sample
Issue #3663
1 parent 2750238 commit 43e7c8c

File tree

7 files changed

+219
-85
lines changed

7 files changed

+219
-85
lines changed

spring-batch-samples/README.md

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -171,43 +171,10 @@ from a delimited file, processing it and writing it to another file.
171171

172172
### Fixed Length Import Job
173173

174-
The goal is to demonstrate a typical scenario of importing data
175-
from a fixed-length file to database
176-
177-
This job shows a typical scenario, when reading input data and
178-
processing the data is cleanly separated. The data provider is
179-
responsible for reading input and mapping each record to a domain
180-
object, which is then passed to the module processor. The module
181-
processor handles the processing of the domain objects, in this case
182-
it only writes them to database.
183-
184-
In this example we are using a simple fixed length record structure
185-
that can be found in the project at
186-
`data/iosample/input`. A considerable amount of
187-
thought can go into designing the folder structures for batch file
188-
management. The fixed length records look like this:
189-
190-
UK21341EAH4597898.34customer1
191-
UK21341EAH4611218.12customer2
192-
UK21341EAH4724512.78customer2
193-
UK21341EAH48108109.25customer3
194-
UK21341EAH49854123.39customer4
195-
196-
Looking back to the configuration file you will see where this is
197-
documented in the property of the `FixedLengthTokenizer`. You can
198-
infer the following properties:
199-
200-
201-
FieldName | Length
202-
--------- | :----:
203-
ISIN | 12
204-
Quantity | 3
205-
Price | 5
206-
Customer | 9
207-
208-
*Output target:* database - writes the data to database using a DAO
209-
object
174+
The goal is to demonstrate a typical scenario of reading data
175+
from a fixed length file, processing it and writing it to another file.
210176

177+
[Fixed Length Import Job sample](./src/main/java/org/springframework/batch/sample/file/fixed/README.md)
211178

212179
### Football Job
213180

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package org.springframework.batch.sample.file.fixed;
2+
3+
import javax.sql.DataSource;
4+
5+
import org.springframework.batch.core.Job;
6+
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
7+
import org.springframework.batch.core.configuration.annotation.StepScope;
8+
import org.springframework.batch.core.job.builder.JobBuilder;
9+
import org.springframework.batch.core.repository.JobRepository;
10+
import org.springframework.batch.core.step.builder.StepBuilder;
11+
import org.springframework.batch.item.ItemReader;
12+
import org.springframework.batch.item.ItemWriter;
13+
import org.springframework.batch.item.file.FlatFileItemReader;
14+
import org.springframework.batch.item.file.FlatFileItemWriter;
15+
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
16+
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
17+
import org.springframework.batch.item.file.transform.Range;
18+
import org.springframework.batch.sample.domain.trade.CustomerCredit;
19+
import org.springframework.batch.sample.domain.trade.internal.CustomerCreditIncreaseProcessor;
20+
import org.springframework.beans.factory.annotation.Value;
21+
import org.springframework.context.annotation.Bean;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.core.io.Resource;
24+
import org.springframework.core.io.WritableResource;
25+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
26+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
27+
import org.springframework.jdbc.support.JdbcTransactionManager;
28+
29+
@Configuration
30+
@EnableBatchProcessing
31+
public class FixedLengthJobConfiguration {
32+
33+
@Bean
34+
@StepScope
35+
public FlatFileItemReader<CustomerCredit> itemReader(@Value("#{jobParameters[inputFile]}") Resource resource) {
36+
return new FlatFileItemReaderBuilder<CustomerCredit>().name("itemReader")
37+
.resource(resource)
38+
.fixedLength()
39+
.columns(new Range(1, 9), new Range(10, 11))
40+
.names("name", "credit")
41+
.targetType(CustomerCredit.class)
42+
.build();
43+
}
44+
45+
@Bean
46+
@StepScope
47+
public FlatFileItemWriter<CustomerCredit> itemWriter(
48+
@Value("#{jobParameters[outputFile]}") WritableResource resource) {
49+
return new FlatFileItemWriterBuilder<CustomerCredit>().name("itemWriter")
50+
.resource(resource)
51+
.formatted()
52+
.format("%-9s%-2.0f")
53+
.names("name", "credit")
54+
.build();
55+
}
56+
57+
@Bean
58+
public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager,
59+
ItemReader<CustomerCredit> itemReader, ItemWriter<CustomerCredit> itemWriter) {
60+
return new JobBuilder("ioSampleJob", jobRepository)
61+
.start(new StepBuilder("step1", jobRepository).<CustomerCredit, CustomerCredit>chunk(2, transactionManager)
62+
.reader(itemReader)
63+
.processor(new CustomerCreditIncreaseProcessor())
64+
.writer(itemWriter)
65+
.build())
66+
.build();
67+
}
68+
69+
// Infrastructure beans
70+
71+
@Bean
72+
public DataSource dataSource() {
73+
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
74+
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
75+
.addScript("/org/springframework/batch/core/schema-hsqldb.sql")
76+
.generateUniqueName(true)
77+
.build();
78+
}
79+
80+
@Bean
81+
public JdbcTransactionManager transactionManager(DataSource dataSource) {
82+
return new JdbcTransactionManager(dataSource);
83+
}
84+
85+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
### Fixed Length File Import Job
2+
3+
## About
4+
5+
The goal is to demonstrate a typical scenario of reading data
6+
from a fixed length file, processing it and writing it to another file.
7+
8+
In this example we are using a simple fixed length record structure
9+
that can be found in the project at
10+
`src/main/resources/org/springframework/batch/sample/file/fixed/data`.
11+
The fixed length records look like this:
12+
13+
```
14+
customer110
15+
customer220
16+
customer330
17+
customer440
18+
customer550
19+
customer660
20+
```
21+
22+
Looking back to the configuration of the reader you will this is
23+
configured in the fixed column ranges:
24+
25+
FieldName | Range
26+
--------- | :----:
27+
name | 1,9
28+
credit | 10,11
29+
30+
## Run the sample
31+
32+
You can run the sample from the command line as following:
33+
34+
```
35+
$>cd spring-batch-samples
36+
# Launch the sample using the XML configuration
37+
$>../mvnw -Dtest=FixedLengthFunctionalTests#testLaunchJobWithXmlConfig test
38+
# Launch the sample using the Java configuration
39+
$>../mvnw -Dtest=FixedLengthFunctionalTests#testLaunchJobWithJavaConfig test
40+
```
41+

spring-batch-samples/src/main/resources/jobs/iosample/fixedLength.xml renamed to spring-batch-samples/src/main/resources/org/springframework/batch/sample/file/fixed/job/fixedLength.xml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xsi:schemaLocation="
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:batch="http://www.springframework.org/schema/batch"
5+
xsi:schemaLocation="
6+
http://www.springframework.org/schema/batch https://www.springframework.org/schema/batch/spring-batch.xsd
57
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
68

9+
<batch:job id="ioSampleJob" xmlns="http://www.springframework.org/schema/batch">
10+
<batch:step id="step1">
11+
<batch:tasklet>
12+
<batch:chunk reader="itemReader" processor="itemProcessor" writer="itemWriter"
13+
commit-interval="2"/>
14+
</batch:tasklet>
15+
</batch:step>
16+
</batch:job>
17+
18+
<bean id="itemProcessor" class="org.springframework.batch.sample.domain.trade.internal.CustomerCreditIncreaseProcessor" />
19+
720
<bean id="itemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
821
<property name="resource" value="#{jobParameters[inputFile]}" />
922
<property name="lineMapper">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2006-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.batch.sample.file.fixed;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.batch.core.BatchStatus;
22+
import org.springframework.batch.core.Job;
23+
import org.springframework.batch.core.JobExecution;
24+
import org.springframework.batch.core.JobParameters;
25+
import org.springframework.batch.core.JobParametersBuilder;
26+
import org.springframework.batch.core.launch.JobLauncher;
27+
import org.springframework.batch.test.JobLauncherTestUtils;
28+
import org.springframework.beans.factory.annotation.Autowired;
29+
import org.springframework.context.ApplicationContext;
30+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
31+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
32+
33+
import static org.junit.jupiter.api.Assertions.assertEquals;
34+
35+
@SpringJUnitConfig(locations = { "/org/springframework/batch/sample/file/fixed/job/fixedLength.xml",
36+
"/simple-job-launcher-context.xml", "/job-runner-context.xml" })
37+
class FixedLengthFunctionalTests {
38+
39+
@Autowired
40+
private JobLauncherTestUtils jobLauncherTestUtils;
41+
42+
@Test
43+
void testLaunchJobWithXmlConfig() throws Exception {
44+
// given
45+
JobParameters jobParameters = new JobParametersBuilder()
46+
.addString("inputFile", "org/springframework/batch/sample/file/fixed/data/fixedLength.txt")
47+
.addString("outputFile", "file:./target/test-outputs/fixedLengthOutput.txt")
48+
.toJobParameters();
49+
50+
// when
51+
JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);
52+
53+
// then
54+
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
55+
}
56+
57+
@Test
58+
public void testLaunchJobWithJavaConfig() throws Exception {
59+
// given
60+
ApplicationContext context = new AnnotationConfigApplicationContext(FixedLengthJobConfiguration.class);
61+
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
62+
Job job = context.getBean(Job.class);
63+
JobParameters jobParameters = new JobParametersBuilder()
64+
.addString("inputFile", "org/springframework/batch/sample/file/fixed/data/fixedLength.txt")
65+
.addString("outputFile", "file:./target/test-outputs/fixedLengthOutput.txt")
66+
.toJobParameters();
67+
68+
// when
69+
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
70+
71+
// then
72+
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
73+
}
74+
75+
}

spring-batch-samples/src/test/java/org/springframework/batch/sample/iosample/FixedLengthFunctionalTests.java

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)