I have written a code which fetched the S3 objects from AWS s3 using S3 sdk and stores the same in our DB, the only problem is the task is repeated for three different services, the only thing is changed is the instance of service class.

I have copy and pasted code in each service layer just to changes the instance for an instance.

The task is repeated for service classes VehicleImageService, MsilLayoutService and NonMsilLayout service, every layer is having its own repository.

I am trying to identify a way to accomplish the same by placing that snippet in one place and on an runtime using Reflection API I wish to pass the correct instance and invoke the method, but I want to achieve the same using best industry practices and pattern. I.e. I want to refactor into generic methods for other services, so instance can be passed at runtime.

So kindly assist me on the same.

public void persistImageDetails() {
        String bucketKey = null; //common param
        String modelCode = null;//common param
        List<S3Object> objList = new ArrayList<>(); //common param
        String bucketName = s3BucketDetails.getBucketName();//common param
        String bucketPath = s3BucketDetails.getBucketPrefix();//common param
        try {
            //the layoutRepository object can be MSILRepository,NonMSILRepository and VehilceImageRepository
            List<ModelCode> modelCodes = layoutRepository.findDistinctAllBy(); // this line need to take care of
            List<String> modelCodePresent = modelCodes.stream().map(ModelCode::getModelCode)
            List<CommonPrefix> allKeysInDesiredBucket = listAllKeysInsideBucket(bucketName, bucketPath);//common param
            synchDB(modelCodePresent, allKeysInDesiredBucket);
            if (null != allKeysInDesiredBucket && !allKeysInDesiredBucket.isEmpty()) {
                for (CommonPrefix commonPrefix : allKeysInDesiredBucket) {
                    bucketKey = commonPrefix.prefix();
                    modelCode = new File(bucketKey).getName();
                    if (modelCodePresent.contains(modelCode)) {
                        log.info("skipping iteration for {} model code", modelCode);
                    objList = s3Service.getBucketObjects(bucketName, bucketKey);
                    if (null != objList && !objList.isEmpty()) {
                        for (S3Object object : AppUtil.skipFirst(objList)) {
                            saveLayout(bucketName, modelCode, object);
            log.info("MSIL Vehicle Layout entries has been successfully saved");
        } catch (Exception e) {
            log.error("Error occured", e);
    private void saveLayout(String bucketName, String modelCode, S3Object object) {
        log.info("Inside saveLayout::Start preparing entity to persist");
        String resourceUri = null;
        MsilVehicleLayout vehicleLayout = new MsilVehicleLayout();// this can be MsilVehicleLayout. NonMsilVehicleLayout, VehicleImage
        resourceUri = getS3ObjectURI(bucketName, object.key());
        layoutRepository.save(vehicleLayout); //the layoutRepository object can be MSILRepository,NonMSILRepository and VehilceImageRepository
        log.info("Exiting saveLayout::End entity saved");
  • \$\begingroup\$ Unless all your classes have a common interface you can adhere to (all of them have the same methods you need to call) in your code, the only thing which changes is the class name, the best you can do is have instanceof checks and that is just poor code in general. Might want to think about an interface or inheritance hierarchy for your LayoutRepositories \$\endgroup\$ Sep 30, 2022 at 13:16
  • \$\begingroup\$ Could you please elaborate and provide snippet for the same \$\endgroup\$
    – jack
    Sep 30, 2022 at 14:14


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy