Skip to content

Commit 0ab2bae

Browse files
committed
Add support for file patterns in MultiResourceItemReaderBuilder
Resolves #5056 Signed-off-by: Sanghyuk Jung <sanghyuk.jung@navercorp.com>
1 parent 5c07115 commit 0ab2bae

File tree

4 files changed

+63
-3
lines changed

4 files changed

+63
-3
lines changed

spring-batch-infrastructure/src/main/java/org/springframework/batch/infrastructure/item/file/builder/MultiResourceItemReaderBuilder.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.batch.infrastructure.item.file.builder;
1818

19+
import java.io.IOException;
1920
import java.util.Comparator;
2021

2122
import org.jspecify.annotations.Nullable;
@@ -25,6 +26,8 @@
2526
import org.springframework.batch.infrastructure.item.file.MultiResourceItemReader;
2627
import org.springframework.batch.infrastructure.item.file.ResourceAwareItemReaderItemStream;
2728
import org.springframework.core.io.Resource;
29+
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
30+
import org.springframework.core.io.support.ResourcePatternResolver;
2831
import org.springframework.util.Assert;
2932
import org.springframework.util.StringUtils;
3033

@@ -34,6 +37,7 @@
3437
* @author Glenn Renfro
3538
* @author Drummond Dawson
3639
* @author Stefano Cordio
40+
* @author Sanghyuk Jung
3741
* @since 4.0
3842
* @see MultiResourceItemReader
3943
*/
@@ -43,6 +47,8 @@ public class MultiResourceItemReaderBuilder<T> {
4347

4448
private Resource @Nullable [] resources;
4549

50+
private @Nullable String filesPattern;
51+
4652
private boolean strict = false;
4753

4854
private @Nullable Comparator<Resource> comparator;
@@ -90,6 +96,19 @@ public MultiResourceItemReaderBuilder<T> resources(Resource... resources) {
9096
return this;
9197
}
9298

99+
/**
100+
* The location pattern of files that the {@link MultiResourceItemReader} will use to
101+
* retrieve items. This is an Ant-style pattern that supports wildcards like `*`, `**`
102+
* and `?`(for example `/data/*.csv`or `data/**\/user?.txt`).
103+
* @param filesPattern the location pattern of files to use.
104+
* @return this instance for method chaining.
105+
*/
106+
public MultiResourceItemReaderBuilder<T> filesPattern(String filesPattern) {
107+
this.filesPattern = filesPattern;
108+
109+
return this;
110+
}
111+
93112
/**
94113
* Establishes the delegate to use for reading the resources provided.
95114
* @param delegate reads items from single {@link Resource}.
@@ -135,14 +154,31 @@ public MultiResourceItemReaderBuilder<T> comparator(Comparator<Resource> compara
135154
* @return a {@link MultiResourceItemReader}
136155
*/
137156
public MultiResourceItemReader<T> build() {
138-
Assert.notNull(this.resources, "resources array is required.");
157+
Assert.isTrue(this.resources != null || this.filesPattern != null,
158+
"resources array or filesPattern is required.");
159+
139160
Assert.notNull(this.delegate, "delegate is required.");
140161
if (this.saveState) {
141162
Assert.state(StringUtils.hasText(this.name), "A name is required when saveState is set to true.");
142163
}
143164

144165
MultiResourceItemReader<T> reader = new MultiResourceItemReader<>(this.delegate);
145-
reader.setResources(this.resources);
166+
167+
if (this.resources != null) {
168+
reader.setResources(this.resources);
169+
}
170+
else if (this.filesPattern != null) {
171+
ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
172+
try {
173+
Resource[] resources = patternResolver.getResources("file:" + this.filesPattern);
174+
reader.setResources(resources);
175+
}
176+
catch (IOException e) {
177+
throw new IllegalArgumentException("Unable to initialize resources by the pattern " + this.filesPattern,
178+
e);
179+
}
180+
}
181+
146182
reader.setSaveState(this.saveState);
147183
reader.setStrict(this.strict);
148184

spring-batch-infrastructure/src/test/java/org/springframework/batch/infrastructure/item/file/builder/MultiResourceItemReaderBuilderTests.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626
import org.springframework.batch.infrastructure.item.file.FlatFileItemReader;
2727
import org.springframework.batch.infrastructure.item.file.LineMapper;
2828
import org.springframework.batch.infrastructure.item.file.MultiResourceItemReader;
29+
import org.springframework.batch.infrastructure.item.file.mapping.PassThroughLineMapper;
2930
import org.springframework.batch.infrastructure.item.sample.Foo;
3031
import org.springframework.core.io.ByteArrayResource;
32+
import org.springframework.core.io.ClassPathResource;
3133
import org.springframework.core.io.Resource;
3234

35+
import static org.junit.jupiter.api.Assertions.assertNull;
3336
import static org.junit.jupiter.api.Assertions.assertEquals;
3437
import static org.junit.jupiter.api.Assertions.assertThrows;
3538
import static org.mockito.Mockito.mock;
@@ -79,7 +82,26 @@ void testNullDelegate() {
7982
void testNullResources() {
8083
Exception exception = assertThrows(IllegalArgumentException.class,
8184
() -> new MultiResourceItemReaderBuilder<String>().delegate(mock(FlatFileItemReader.class)).build());
82-
assertEquals("resources array is required.", exception.getMessage());
85+
assertEquals("resources array or filesPattern is required.", exception.getMessage());
86+
}
87+
88+
@Test
89+
void testFilesPattern() throws Exception {
90+
FlatFileItemReader<String> delegate = new FlatFileItemReaderBuilder<String>().name("textReader")
91+
.lineMapper(new PassThroughLineMapper())
92+
.build();
93+
94+
String basePath = new ClassPathResource("", this.getClass()).getFile().getPath();
95+
MultiResourceItemReader<String> reader = new MultiResourceItemReaderBuilder<String>().delegate(delegate)
96+
.filesPattern(basePath + "/test?.txt")
97+
.name("multiFileReader")
98+
.build();
99+
100+
reader.open(new ExecutionContext());
101+
assertEquals("1", reader.read());
102+
assertEquals("2", reader.read());
103+
assertNull(reader.read());
104+
reader.close();
83105
}
84106

85107
@Override
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2

0 commit comments

Comments
 (0)