Suppose I have two classes implemented in the following manner (Ommiting job and chunk code for the sake of clarity). Each reader will have a delimiter based on the configuration class they are declared.
1) There is clearly code repetition that I would love to generalize in another class, because if I decide to add code in class*ItemReader(), I would have to do it across several files. How can that be accomplished? Not only the "delimiter" is important here, but the class inside <> in the itemReaderBuilder
2) How can I avoid having different names for each of the methods? the are basically the same, they just need a different class inside <> and a different delimiter.
3) How can I avoid the need to save the reader inside the configuration class to calculate the resource path in runtime (using a tasklet) as is date based.
@Configuration
public ClassA{
@Value("${fileA.delimiter}")
private String delimiter;
private ItemReader reader;
@Bean
public ItemReader classAItemReader(){
reader = FlatFileItemReaderBuilder<ObjectA>
.get("reader")
.delimiter(this.delimiter)
.blabla()
.build()
return reader
}
}
@Configuration
public ClassB{
@Value("${fileB.delimiter}")
private String delimiter;
private ItemReader reader;
@Bean
public ItemReader classBItemReader(){
reader = FlatFileItemReaderBuilder<ObjectA>
.get("reader")
.delimiter(this.delimiter)
.blabla()
.build()
return reader
}
}
One option I see for your use case is to define an abstract generic configuration class in which you define a generic reader. Here is an example:
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
public abstract class MyReaderConfiguration<T> {
@Value("${file.delimiter}")
private String delimiter;
@Value("${file.columns}") // column1,column2
private String fields;
@Bean
public ItemReader<T> itemReader(){
return new FlatFileItemReaderBuilder<T>()
.name("reader")
.delimited()
.delimiter(delimiter)
.names(fields.split(","))
.build();
}
}
Other parts of your job definition can go in a subclass with the desired target type (ObjectA
or ObjectB
).