I have below value in my application.properties
file
input.file-path=c:\\temp\\data
In that path I have two files:
- Students_Input_20221212.dat
- Workers_Input_20221212.dat
is there a way using @Value
annotation to get each of the files by using the start with string? Something like below:
@Value("${input.file-path}/Students_Input_*.dat")
private String inputFileStudents;
@Value("${input.file-path}/Workers_Input_*.dat")
private String inputFileWorkers;
So I have:
inputFileStudents = "c:\\temp\\data\\Students_Input_20221212.dat"
inputFileWorkers = "c:\\temp\\data\\Workers_Input_20221212.dat"
CodePudding user response:
Finally found:
[PathMatching]ResourcePatternResolver
!
Consider:
- spring-boot:3 starter (web)
- properties:
# existing path (win): input.file=C:\\temp\\data # file filter (ant path matcher): input.students.filter=Students_Input_*.dat input.workers.filter=Workers_Input_*.dat
Testing time:
// ...
import java.util.Arrays;
// import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.support.ResourcePatternResolver; // !!
// ...
@Bean
InitializingBean patternResolverShowCase( /* <- just a demo ... */
/*@Autowired*/ ResourcePatternResolver resolver, /* <- autowire/@value "anywhere"(in spring beans)... */
@Value("${input.file}") String folder, /* <- alternative for @Value: (type-safe) @ConfigurationProperties ;) */
@Value("${input.students.filter}") String studentsFilter, /* < filter1 */
@Value("${input.workers.filter}") String workersFilter /* < filter2 */
) {
return () -> { // <- initializingBean - lambda..
System.err.println( // <- just a demo...
Arrays.toString( // ..do whatever you like with:
resolver.getResources("file:" folder "/" studentsFilter)
)
);
System.err.println(
Arrays.toString( // ... :
resolver.getResources("file:" folder "/" workersFilter)
)
);
};
}
With SpEL
Declaring (assigning name and implementation class, otherwise we get a "nameless default"):
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; // !
// ...
@Bean
ResourcePatternResolver rssResolver() {
return new PathMatchingResourcePatternResolver();
}
..we can also just (SpEL):
import org.springframework.core.io.Resource; // !
// ...
@Value("#{@rssResolver.getResources('file:' '${input.file}' '/' '${input.students.filter}')}") Resource[] studentFiles;
@Value("#{@rssResolver.getResources('file:' '${input.file}' '/' '${input.workers.filter}')}") Resource[] workerFiles;
// do whatever you like with'em (in spring) ...
Explanations
- above link...
- properties, path separator handling and adjustment: to your needs/suits.
@Value("#{...}")
SpEL expression (in a@Value
...).@rssResolver
refers to "rssResolver" bean.- plus:
Original answer:
Wildcards will be hard (fromthis (wiring a directory into bean context) is easy-peasy:@Value
), butProperties:
# existing path (win): myFolder=C:\\temp\\data # file filter (regex!): myFileFilter=^test.*\.txt$
Test
@Bean InitializingBean fileResourceShowCase(/* <- just a demo */ @Value("${myFolder}") FileSystemResource rss1, /* <- org.springframework.core.io */ @Value("#{T(java.nio.file.Path).of('${myFolder}')}") Path path, /* <- java.nio */ @Value("#{new java.io.File('${myFolder}')}") File file, /* <- java.io */ @Value("${myFileFilter}") String filter /* <- custom/extra */ ) { return () -> { // 3 ways to access java.io.File: System.err.println(rss1.getFile()); System.err.println(path.toFile()); System.err.println(file); // apply the filter: File[] files = file.listFiles((f) -> f.getName().matches(filter)); for (File f : files) { System.err.println(f); } }; }
Explanations:
@Value("${myFolder}") FileSystemResource rss1
: access the folder as a (spring)FileSystemResource
just by it's name (represented by${myFolder}
placeholder). [prefer!]@Value("#{T(java.nio.file.Path).of('${myFolder}')}") Path path
: SpEL expression for (static)Path.of(myFolder)
(where${myFolder}
is resolved as above).@Value("#{new java.io.File('${myFolder}')}") File file
: SpEL expression for:new File(myFolder)
...Links:
Don'ts
Unfortunately we cannot do this with SpEL:
@Value(""" #{ T(java.nio.file.Path).of('${myFolder}') .toFile() .listFiles( (f)->f.getName().matches('${myFileFilter}') ) } """) File[] files; // -> EL1042E: Problem parsing right operand ;(;(
see: Why doesn't this stream & lambda expression work with SpEL declaration?
Neither this:
@Value("${myFolder}/**") FileSystemResource[] rssArr // -> java.nio.file.InvalidPathException: Illegal char <*> at index ...
... the last (@Value("${myFolder}/**")
) approach brought me to: https://www.google.com/search?q=spring antpathmatcher filesystem ;)