I am setting up a Spring Batch job which would process a multi-record file. One of the record is having the following structure.
Ind,RecCode,AccNum,RecTypeDesc,EffectiveDate,CreditAmount,DebitAmount,BatchNumber,NumberOfTrasactions
5, 20, 100, prl, 12084, as0, 0, 3, 1
Depending upon the value in the RecordCode field, it will be either a payment record or a reversal record.
I am setting up the PatternMatchingCompositeLineMapper to read the record types in the file. I have created the following 2 FieldSetMapper implementations classes
@Component("paymentBatchFieldSetMapper")
public class PaymentBatchFieldSetMapper implements FieldSetMapper<PaymentBatch> {
@Override
public PaymentBatch mapFieldSet(FieldSet fieldSet) throws BindException {
// TODO Auto-generated method stub
return null;
}
}
and second one as,
@Component("reversalBatchFieldSetMapper")
public class ReversalBatchFieldSetMapper implements FieldSetMapper<PaymentBatch> {
@Override
public PaymentBatch mapFieldSet(FieldSet fieldSet) throws BindException {
// TODO Auto-generated method stub
return null;
}
}
I have created a factory class as following to return either of the above 2 as below
@Component("achBatchFieldSetMapperFactory")
public class ACHBatchFieldSetMapperFactory {
@Autowired
private ApplicationContext applicationContext;
public FieldSetMapper<? extends AbstractACHBatch> getFieldSetMapper(RecordTypeDescription recordTypeDescription) {
FieldSetMapper<? extends AbstractACHBatch> fieldSetMapper = null;
switch(recordTypeDescription) {
case PAYMENT:
fieldSetMapper = applicationContext.getBean(PaymentBatchFieldSetMapper.class);
break;
case REVERSAL:
fieldSetMapper = applicationContext.getBean(ReversalBatchFieldSetMapper.class);
break;
}
return fieldSetMapper;
}
}
Below is the bean configuration for the map object to be injected into PatternMatchingCompositeLineMapper.
@Bean
public Map<String, LineTokenizer> fieldSetMapperMap(FileHeaderFieldSetMapper fileHeaderFieldSetMapper, PaymentBatchFieldSetMapper paymentBatchFieldSetMapper,
ReversalBatchFieldSetMapper reversalBatchFieldSetMapper) {
Map<String, FieldSetMapper> map = new HashMap<String, FieldSetMapper>();
map.put("1*", fileHeaderFieldSetMapper);
map.put("5*", ?????);
}
Is there a possibility that I can use the factory to return the needed FieldSet mapper depending upon the record in the file?
The item reader is designed to return one type of items at a time. Let's imagine we manage to map records to either PaymentBatch
or ReversalBatch
according to the RecordCode
field, this means that after the mapping occurs, the ItemReader
would return two types. This is not possible by design.
What you can do is create a POJO that has a one-to-one mapping with the fields in your input file, then use a ClassifierCompositeItemProcessor
to process each item according to its type (The classifier would be based on the RecordTypeDescription
enum in your case).
NB: It is of course technically possible to forget about the generic type of the ItemReader<T>
interface and make the item reader return Object
s, but this would require ugly usage of instanceof
in your processor to determine the record type. I highly recommend not using this approach.