1

Like for reading single file in spring batch from s3, we use

@Bean
public FlatFileItemReader<Map<String, Object>> itemReader() {
    FlatFileItemReader<Map<String, Object>> reader = new FlatFileItemReader<>();
    reader.setLineMapper(new JsonLineMapper());
    reader.setRecordSeparatorPolicy(new JsonRecordSeparatorPolicy());
    reader.setResource(resourceLoader.getResource("s3://" + amazonS3Bucket + "/" + file));
    return reader;
}

But if i want to read all the files from some specific folder/key then is there something to MultiResourceItemReader, like below(which we use for local filesystem)

MultiResourceItemReader<UserData> reader = new MultiResourceItemReader<>();
reader.setResources(resources);
Compo
  • 36,585
  • 5
  • 27
  • 39
Gaurav Raghav
  • 157
  • 1
  • 6

2 Answers2

2

No, it is up to you to create the Resource array and pass it to the MultiResourceItemReader.

Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50
2

Create a MultiResourceItemReader like this,

@Autowired
private AmazonS3 s3;

@Autowired
private ResourceLoader resourceLoader;


public MultiResourceItemReader<String> fileItemReader() throws Exception {

    List<Resource> resourceList = new ArrayList<>();

    String s3ResponseFilePath = "s3://bucket/path/"; //put your s3 path here

    //TODO: warn: this functn can only return max 1000 objects
    s3objects = s3.listObjects("bucket", s3ResponseFilePath).getObjectSummaries();

    for(S3ObjectSummary it:s3objects)
        resourceList.add(resourceLoader.getResource( "s3://" + s3Config.getBucket() + "/" + it.getKey()));

    Resource[] resources = resourceList.toArray(new Resource[resourceList.size()]);

    MultiResourceItemReader<String> reader = new MultiResourceItemReader<>();
    reader.setResources(resources);
    reader.setDelegate(flatFileItemReader());

    return reader;
}

This reader will need a delegate and lineMapper, you can implement it like this,

private FlatFileItemReader<String> flatFileItemReader() throws Exception {

    FlatFileItemReader<String> reader = new FlatFileItemReader<>();
    JsonLineMapper lineMapper = new JsonLineMapper();
    reader.setLineMapper(lineMapper);
    reader.afterPropertiesSet();

    return reader;
}


public class JsonLineMapper implements LineMapper<String> {

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public String mapLine(String s, int i) throws Exception {

        return s;
    }
}
Gaurav Raghav
  • 157
  • 1
  • 6
  • Seems to be not working using the same strategy in [my question](https://stackoverflow.com/questions/70144975/input-resource-must-exist-for-aws-s3-resources) – Braham Shakti Nov 28 '21 at 16:09
  • I created the reader in same approach with -> SynchronizedItemStreamReader delegating to MultiResourceItemReader which delegates to FlatFileItemReader but got an error - resource must exist (s3 resource urls shown in logs is same as my file available in s3 bucket). any idea what could be wrong ? – Ashish Awasthi Aug 21 '22 at 23:58