Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to best get a byte array from a ClientResponse from Spring WebClient?

Tags:

I'm trying out the new WebClient from Spring 5 (5.0.0.RC2) in a codebase that uses reactive programming and I've had success mapping the JSON response from an endpoint to a DTO in my app, which works very nice:

WebClient client = WebClient.create(baseURI); Mono<DTO> dto = client.get()         .uri(uri)         .accept(MediaType.APPLICATION_JSON)         .exchange()         .flatMap(response -> response.bodyToMono(DTO.class)); 

However, now I'm trying to the response body from an endpoint which uses Protocol Buffers (binary data served as application/octet-stream), so I'd like to get the raw bytes from the response, which I'll then map to an object myself.

I got it to work like this using Bytes from Google Guava:

Mono<byte[]> bytes = client.get()         .uri(uri)         .accept(MediaType.APPLICATION_OCTET_STREAM)         .exchange()         .flatMapMany(response -> response.body(BodyExtractors.toDataBuffers()))         .map(dataBuffer -> {             ByteBuffer byteBuffer = dataBuffer.asByteBuffer();             byte[] byteArray = new byte[byteBuffer.remaining()];             byteBuffer.get(byteArray, 0, bytes.length);             return byteArray;         })         .reduce(Bytes::concat) 

This works, but is there an easier, more elegant way to get these bytes?

like image 503
Nils Breunese Avatar asked Jun 29 '17 09:06

Nils Breunese


People also ask

What is Bytearray?

A byte array is simply a collection of bytes. The bytearray() method returns a bytearray object, which is an array of the specified bytes. The bytearray class is a mutable array of numbers ranging from 0 to 256.

Is WebClient asynchronous?

2.2. On the other side, WebClient uses an asynchronous, non-blocking solution provided by the Spring Reactive framework.


1 Answers

ClientResponse.bodyToMono() in the end uses some org.springframework.core.codec.Decoder which claims to support the specified class.

So we should check the class hierarchy of the Decoder, in particular where and how the decodeToMono() method is implemented.

There is a StringDecoder which supports decoding to String, a bunch of Jackson-related decoders (used in your DTO example under the hood), and there is also a ResourceDecoder which is of particular interest.

ResourceDecoder supports org.springframework.core.io.InputStreamResource and org.springframework.core.io.ByteArrayResource. ByteArrayResource is essentially a wrapper around byte[], so the following code will provide an access to the response body as a byte array:

Mono<byte[]> mono = client.get()             ...             .exchange()             .flatMap(response -> response.bodyToMono(ByteArrayResource.class))             .map(ByteArrayResource::getByteArray); 
like image 133
Oleg Estekhin Avatar answered Sep 18 '22 06:09

Oleg Estekhin