Skip to content

Commit e42167b

Browse files
committed
Add java configuration for the multi-line job sample
Issue #3663
1 parent 7bb5ca7 commit e42167b

File tree

10 files changed

+404
-70
lines changed

10 files changed

+404
-70
lines changed

spring-batch-samples/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,25 @@ to read and write multiple files in the same step.
190190

191191
[MultiResource Input Output Job Sample](./src/main/java/org/springframework/batch/sample/file/multiresource/README.md)
192192

193+
### MultiLine Input Job
194+
195+
The goal of this sample is to show how to process input files where a single logical
196+
item spans multiple physical line:
197+
198+
```
199+
BEGIN
200+
INFO,UK21341EAH45,customer1
201+
AMNT,978,98.34
202+
END
203+
BEGIN
204+
INFO,UK21341EAH46,customer2
205+
AMNT,112,18.12
206+
END
207+
...
208+
```
209+
210+
[MultiLine Input Job Sample](./src/main/java/org/springframework/batch/sample/file/multiline/README.md)
211+
193212
### Football Job
194213

195214
This is a (American) Football statistics loading job. It loads two files containing players and games
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package org.springframework.batch.sample.file.multiline;
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.file.FlatFileItemReader;
12+
import org.springframework.batch.item.file.FlatFileItemWriter;
13+
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
14+
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
15+
import org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper;
16+
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
17+
import org.springframework.batch.item.file.transform.FieldSet;
18+
import org.springframework.batch.item.file.transform.PassThroughLineAggregator;
19+
import org.springframework.beans.factory.annotation.Value;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.context.annotation.Configuration;
22+
import org.springframework.core.io.Resource;
23+
import org.springframework.core.io.WritableResource;
24+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
25+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
26+
import org.springframework.jdbc.support.JdbcTransactionManager;
27+
28+
@Configuration
29+
@EnableBatchProcessing
30+
public class MultiLineJobConfiguration {
31+
32+
@Bean
33+
@StepScope
34+
public MultiLineTradeItemReader itemReader(@Value("#{jobParameters[inputFile]}") Resource resource) {
35+
FlatFileItemReader<FieldSet> delegate = new FlatFileItemReaderBuilder<FieldSet>().name("delegateItemReader")
36+
.resource(resource)
37+
.lineTokenizer(new DelimitedLineTokenizer())
38+
.fieldSetMapper(new PassThroughFieldSetMapper())
39+
.build();
40+
MultiLineTradeItemReader reader = new MultiLineTradeItemReader();
41+
reader.setDelegate(delegate);
42+
return reader;
43+
}
44+
45+
@Bean
46+
@StepScope
47+
public MultiLineTradeItemWriter itemWriter(@Value("#{jobParameters[outputFile]}") WritableResource resource) {
48+
FlatFileItemWriter<String> delegate = new FlatFileItemWriterBuilder<String>().name("delegateItemWriter")
49+
.resource(resource)
50+
.lineAggregator(new PassThroughLineAggregator<>())
51+
.build();
52+
MultiLineTradeItemWriter writer = new MultiLineTradeItemWriter();
53+
writer.setDelegate(delegate);
54+
return writer;
55+
}
56+
57+
@Bean
58+
public Job job(JobRepository jobRepository, JdbcTransactionManager transactionManager,
59+
MultiLineTradeItemReader itemReader, MultiLineTradeItemWriter itemWriter) {
60+
return new JobBuilder("ioSampleJob", jobRepository)
61+
.start(new StepBuilder("step1", jobRepository).<Trade, Trade>chunk(2, transactionManager)
62+
.reader(itemReader)
63+
.writer(itemWriter)
64+
.build())
65+
.build();
66+
}
67+
68+
// Infrastructure beans
69+
70+
@Bean
71+
public DataSource dataSource() {
72+
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
73+
.addScript("/org/springframework/batch/core/schema-drop-hsqldb.sql")
74+
.addScript("/org/springframework/batch/core/schema-hsqldb.sql")
75+
.generateUniqueName(true)
76+
.build();
77+
}
78+
79+
@Bean
80+
public JdbcTransactionManager transactionManager(DataSource dataSource) {
81+
return new JdbcTransactionManager(dataSource);
82+
}
83+
84+
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.batch.sample.iosample.internal;
17+
package org.springframework.batch.sample.file.multiline;
1818

1919
import org.springframework.batch.item.ExecutionContext;
2020
import org.springframework.batch.item.ItemReader;
2121
import org.springframework.batch.item.ItemStream;
2222
import org.springframework.batch.item.ItemStreamException;
2323
import org.springframework.batch.item.file.FlatFileItemReader;
2424
import org.springframework.batch.item.file.transform.FieldSet;
25-
import org.springframework.batch.sample.domain.trade.Trade;
2625
import org.springframework.lang.Nullable;
2726
import org.springframework.util.Assert;
2827

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2022 the original author or authors.
2+
* Copyright 2006-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,15 +14,14 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.batch.sample.iosample.internal;
17+
package org.springframework.batch.sample.file.multiline;
1818

1919
import org.springframework.batch.item.Chunk;
2020
import org.springframework.batch.item.ExecutionContext;
2121
import org.springframework.batch.item.ItemStream;
2222
import org.springframework.batch.item.ItemStreamException;
2323
import org.springframework.batch.item.ItemWriter;
2424
import org.springframework.batch.item.file.FlatFileItemWriter;
25-
import org.springframework.batch.sample.domain.trade.Trade;
2625

2726
/**
2827
* @author Dan Garrette
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
### MultiLine Input Job
2+
3+
## About
4+
5+
The goal of this sample is to show how to process input files where a single logical
6+
item spans multiple physical line:
7+
8+
```
9+
BEGIN
10+
INFO,UK21341EAH45,customer1
11+
AMNT,978,98.34
12+
END
13+
BEGIN
14+
INFO,UK21341EAH46,customer2
15+
AMNT,112,18.12
16+
END
17+
...
18+
```
19+
20+
## Run the sample
21+
22+
You can run the sample from the command line as following:
23+
24+
```
25+
$>cd spring-batch-samples
26+
# Launch the sample using the XML configuration
27+
$>../mvnw -Dtest=MultiLineFunctionalTests#testLaunchJobWithXmlConfig test
28+
# Launch the sample using the Java configuration
29+
$>../mvnw -Dtest=MultiLineFunctionalTests#testLaunchJobWithJavaConfig test
30+
```
31+
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright 2006-2013 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.multiline;
18+
19+
import java.io.Serializable;
20+
import java.math.BigDecimal;
21+
22+
/**
23+
* @author Rob Harrop
24+
* @author Dave Syer
25+
*/
26+
@SuppressWarnings("serial")
27+
public class Trade implements Serializable {
28+
29+
private String isin = "";
30+
31+
private long quantity = 0;
32+
33+
private BigDecimal price = BigDecimal.ZERO;
34+
35+
private String customer = "";
36+
37+
private Long id;
38+
39+
private long version = 0;
40+
41+
public Trade() {
42+
}
43+
44+
public Trade(String isin, long quantity, BigDecimal price, String customer) {
45+
this.isin = isin;
46+
this.quantity = quantity;
47+
this.price = price;
48+
this.customer = customer;
49+
}
50+
51+
/**
52+
* @param id id of the trade
53+
*/
54+
public Trade(long id) {
55+
this.id = id;
56+
}
57+
58+
public long getId() {
59+
return id;
60+
}
61+
62+
public void setId(long id) {
63+
this.id = id;
64+
}
65+
66+
public long getVersion() {
67+
return version;
68+
}
69+
70+
public void setVersion(long version) {
71+
this.version = version;
72+
}
73+
74+
public void setCustomer(String customer) {
75+
this.customer = customer;
76+
}
77+
78+
public void setIsin(String isin) {
79+
this.isin = isin;
80+
}
81+
82+
public void setPrice(BigDecimal price) {
83+
this.price = price;
84+
}
85+
86+
public void setQuantity(long quantity) {
87+
this.quantity = quantity;
88+
}
89+
90+
public String getIsin() {
91+
return isin;
92+
}
93+
94+
public BigDecimal getPrice() {
95+
return price;
96+
}
97+
98+
public long getQuantity() {
99+
return quantity;
100+
}
101+
102+
public String getCustomer() {
103+
return customer;
104+
}
105+
106+
@Override
107+
public String toString() {
108+
return "Trade: [isin=" + this.isin + ",quantity=" + this.quantity + ",price=" + this.price + ",customer="
109+
+ this.customer + "]";
110+
}
111+
112+
@Override
113+
public int hashCode() {
114+
final int prime = 31;
115+
int result = 1;
116+
result = prime * result + ((customer == null) ? 0 : customer.hashCode());
117+
result = prime * result + ((isin == null) ? 0 : isin.hashCode());
118+
result = prime * result + ((price == null) ? 0 : price.hashCode());
119+
result = prime * result + (int) (quantity ^ (quantity >>> 32));
120+
result = prime * result + (int) (version ^ (version >>> 32));
121+
return result;
122+
}
123+
124+
@Override
125+
public boolean equals(Object obj) {
126+
if (this == obj) {
127+
return true;
128+
}
129+
if (obj == null) {
130+
return false;
131+
}
132+
if (getClass() != obj.getClass()) {
133+
return false;
134+
}
135+
Trade other = (Trade) obj;
136+
if (customer == null) {
137+
if (other.customer != null) {
138+
return false;
139+
}
140+
}
141+
else if (!customer.equals(other.customer)) {
142+
return false;
143+
}
144+
if (isin == null) {
145+
if (other.isin != null) {
146+
return false;
147+
}
148+
}
149+
else if (!isin.equals(other.isin)) {
150+
return false;
151+
}
152+
if (price == null) {
153+
if (other.price != null) {
154+
return false;
155+
}
156+
}
157+
else if (!price.equals(other.price)) {
158+
return false;
159+
}
160+
if (quantity != other.quantity) {
161+
return false;
162+
}
163+
if (version != other.version) {
164+
return false;
165+
}
166+
return true;
167+
}
168+
169+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
</batch:step>
1515
</batch:job>
1616

17-
<bean id="itemReader" class="org.springframework.batch.sample.iosample.internal.MultiLineTradeItemReader">
17+
<bean id="itemReader" class="org.springframework.batch.sample.file.multiline.MultiLineTradeItemReader" scope="step">
1818
<property name="delegate">
1919
<bean class="org.springframework.batch.item.file.FlatFileItemReader">
20-
<property name="resource" value="data/iosample/input/multiLine.txt" />
20+
<property name="resource" value="#{jobParameters[inputFile]}" />
2121
<property name="lineMapper">
2222
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
2323
<property name="lineTokenizer">
@@ -32,10 +32,10 @@
3232
</property>
3333
</bean>
3434

35-
<bean id="itemWriter" class="org.springframework.batch.sample.iosample.internal.MultiLineTradeItemWriter">
35+
<bean id="itemWriter" class="org.springframework.batch.sample.file.multiline.MultiLineTradeItemWriter" scope="step">
3636
<property name="delegate">
3737
<bean class="org.springframework.batch.item.file.FlatFileItemWriter">
38-
<property name="resource" value="file:target/test-outputs/multiLineOutput.txt" />
38+
<property name="resource" value="#{jobParameters[outputFile]}" />
3939
<property name="lineAggregator">
4040
<bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
4141
</property>

0 commit comments

Comments
 (0)