2

I'm prototyping a small Spring WebFlux application in Kotlin. This application needs to GET a tar archive from a remote REST endpoint and store it locally on disk. Sounds simple.

I first created an integration test that starts the spring server and one other WebFlux server with a mock REST endpoint that serves the tar archive.

The test should go like:

1) app: GET mock-server/archive

2) mock-server: response with status 200 and tar archive in body as type attachment

3) app: block until all bytes received, then untar and use files

The problem I'm having is that when I try and collect the bytes into a ByteArray on the app, it blocks forever.

My mock-server/archive routes to the following function:

fun serveArchive(request: ServerRequest): Mono<ServerResponse> { val tarFile = FileSystemResource(ARCHIVE_PATH) assert(tarFile.exists() && tarFile.isFile && tarFile.contentLength() != 0L) return ServerResponse .ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) .contentLength(tarFile.contentLength()) .header("Content-Disposition", "attachment; filename=\"$ARCHIVE_FNAME\"") .body(fromResource(tarFile)) } 

Then my app calls that with the following:

private fun retrieveArchive { client.get().uri(ARCHIVE_URL).accept(MediaType.APPLICATION_OCTET_STREAM) .exchange() .flatMap { response -> storeArchive(response.bodyToMono()) }.subscribe() } private fun storeArchive(archive: Mono<ByteArrayResource>): Mono<Void> { val archiveContentBytes = archive.block() // <- this blocks forever val archiveContents = TarArchiveInputStream(archiveContentBytes.inputStream) // read archive } 

I've see How to best get a byte array from a ClientResponse from Spring WebClient? and that's why I'm trying to use the ByteArrayResource.

When I step through everything, I see that serveArchive seems to be working (the assert statement says the file I'm passing exists and there are some bytes in it). In retrieveArchive I get a 200 and can see all the appropriate information in the .headers (content-type, content-length all look good). When I get down to storeArchive and try to retrieve the bytes from the Mono using block, it simply blocks forever.

I'm at a complete loss of how to debug something like this.

1 Answer 1

5

You just have to return the converted body from the flatMap so it transforms from Mono<T> to T:

client.get().uri(ARCHIVE_URL).accept(MediaType.APPLICATION_OCTET_STREAM) .exchange() .flatMap { response -> response.bodyToMono(ByteArrayResource::class.java) } .map { archiveContentBytes -> archiveContentBytes.inputStream } .doOnSuccess { inputStream -> //here is you code to do anything with the inputStream val archiveContents = TarArchiveInputStream(inputStream) } .subscribe() 
Sign up to request clarification or add additional context in comments.

1 Comment

Nailed it! Thank you! I ended up using ...flatMap { response -> response.bodyToMono<ByteArrayResource>() }.map { storeArchive(it) } and just change my signature of storeArchive to take a ByteArrayResource. But now I'm actually getting my bytes and able to untar the archive, etc. Thank you very much!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.