CompletableFuture Byte Array Handling Issue in Java Spring Application

  Kiến thức lập trình

I’m working on a Java code where I need to asynchronously fetch a byte array representing a zip file from a service and then write this into a file. While I have structured my code using CompletableFuture to handle these operations, I’m encountering an issue where the byte array, although correctly fetched and logged with the expected length, seems to be incomplete when written to the file. That inturn is creating a corrupted/incomplete zip file on the disk.
What I have observed is, the issue only arises when the operations are performed asynchronously; synchronous execution works fine.

Here is the relevant part of my code:

 @Service
    public class DemoService {
    
        @Autowired
        private ProcessService fileProcessingService;
    
        public CompletableFuture<byte[]> getAttachmentFileById(String id, String tag) {
            return CompletableFuture.supplyAsync(() -> id)
                .thenCompose(idVal -> fileProcessingService.retrieveAttachmentIDById(idVal, tag))
                .thenCompose(attachmentId -> fileProcessingService.retrieveFileByAttachmentUuid(attachmentId))
                .exceptionally(ex -> {
                    logger.error("Exception occurred while fetching attachment file for id {}", id);
                    logger.error("Exception is ::", ex);
                    return null;
                });
        }

public CompletableFuture<File> processAndWriteFile(String id, String tag, String filename) {
            return getAttachmentFileByCollectionId(id, tag)
                .thenCompose(zipBytes -> {
                    if (zipBytes != null) {
                        return writeToFile(zipBytes, filename);
                    } else {
                        CompletableFuture<File> failedFuture = new CompletableFuture<>();
                        failedFuture.completeExceptionally(new RuntimeException("Failed to retrieve bytes for collection ID: " + id));
                        return failedFuture;
                    }
                });
        }
    
        public CompletableFuture<File> writeToFile(byte[] zipBytes, String filename) {
            String tempDir = System.getProperty("java.io.tmpdir");
            File tempFile = new File(tempDir, filename);
            return CompletableFuture.supplyAsync(() -> {
                try (FileOutputStream out = new FileOutputStream(tempFile)) {
                    out.write(zipBytes);
                    return tempFile;
                } catch (IOException e) {
                    logger.error("Failed to write zip file to disk", e);
                    throw new RuntimeException("Failed to write zip file to disk", e);
                }
            });
        }
    }

The method retrieveFileByAttachmentUuid from fileProcessingService is confirmed to return the correct byte length by getting Headers getContentLength(), as verified by logs immediately after data retrieval.
However, by the time the byte array is passed to writeToFile(), it is incomplete and creates an incomplete file with size lesser than the actual size.

Question:

  1. Could this issue be related to how CompletableFuture handles the byte array?
  2. What might be causing this data loss, and how can I ensure that the entire byte array is written to the file correctly?

LEAVE A COMMENT