org.springframework.http.codec.multipart.Part.content() returns a Flux<DataBuffer>, meaning nothing happens until you subscribe to this Publisher.

If your code can be executed in a blocking way without causing errors, you can refactor it like this to get the String result:

public void parseFilePart(Part filePartMono) {
  List<String> parts = 
    filePartMono.content()
    .map(dataBuffer -> {
          byte[] bytes = new byte[dataBuffer.readableByteCount()];
          dataBuffer.read(bytes);
          DataBufferUtils.release(dataBuffer);
          return new String(bytes, StandardCharsets.UTF_8);
    })
    .collectList()
    .block();
  //do what you want here with the Strings you retrieved
}

If you're sure that the Flux<DataBuffer> will always emit 1 single DataBuffer, you can replace .collectList().block() with .blockFirst() and obtain a String result instead of List<String>.

If your code can't be executed in a blocking fashion, then you could refactor it like this:

public void parseFilePart(Part filePartMono) {
    filePartMono.content()
    .map(dataBuffer -> {
          byte[] bytes = new byte[dataBuffer.readableByteCount()];
          dataBuffer.read(bytes);
          DataBufferUtils.release(dataBuffer);
          return new String(bytes, StandardCharsets.UTF_8);
    })
    .subscribe(resultString -> {
      //do what you want with the result String here
    });
}

P.S. I didn't test your implementation to convert DataBuffer to String, so you might have to double-check that now that it's actually invoked

Answer from Domenico Sibilio on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › java string › convert a bytebuffer to string in java
Convert a ByteBuffer to String in Java | Baeldung
August 15, 2025 - ByteBuffer is one of many beneficial classes in the java.nio package. It’s used to read data from channels and write data into channels directly. In this short tutorial, we’ll learn how to convert a ByteBuffer to String in Java.
🌐
Tabnine
tabnine.com › home › code library
Code Library - Tabnine
July 25, 2024 - Get the answers and suggestions you need from our AI code assistant. Get started in minutes with a free 90 day trial of Tabnine Pro.
🌐
Spring
docs.spring.io › spring-framework › docs › current › javadoc-api › org › springframework › core › codec › StringDecoder.html
StringDecoder (Spring Framework 6.1.14 API)
Decode from a data buffer stream to a String stream, either splitting or aggregating incoming data chunks to realign along newlines delimiters and produce a stream of strings. This is useful for streaming but is also necessary to ensure that multi-byte characters can be decoded correctly, avoiding ...
🌐
GitHub
github.com › spring-projects › spring-framework › issues › 31873
DefaultDataBuffer fails to transform its content to a string · Issue #31873 · spring-projects/spring-framework
December 20, 2023 - import static org.junit.jupiter.api.Assertions.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.junit.jupiter.api.Test; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DefaultDataBufferFactory; class DefaultDataBufferStringTransformationTest { @Test void test() { Charset charset = StandardCharsets.UTF_8; DataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.allocateBuffer(DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY); String name = "Müller"; int repeatCount = 19; for(int i = 0; i < repeatCount; i++) { dataBuffer.write(name, charset); } String expected = name.repeat(repeatCount); String result = dataBuffer.toString(charset); assertEquals(expected, result); } } May be it has something to do with this issue.
Author: spring-projects
🌐
Frozenmountain
docs.frozenmountain.com › icelink3 › api › Java › fm › icelink › DataBuffer.html
DataBuffer
Sets whether fm.icelink.DataBuffer.data is little-endian. ... Gets a subset of this instance. ... Gets a subset of this instance. ... Converts this instance to an array of bytes. ... Converts this instance to a hexadecimal string.
🌐
Spring
docs.spring.io › spring-framework › docs › 5.0.2.RELEASE_to_5.0.3.RELEASE › Spring Framework 5.0.3.RELEASE › org › springframework › core › codec › StringDecoder.html
StringDecoder
Decode from a bytes stream to a String stream. By default, this decoder will split the received DataBuffers along newline characters (\r\n), but this can be changed by passing false as a constructor argument.
🌐
Java Tips
javatips.net › api › spring-reactive-master › src › main › java › org › springframework › core › codec › StringDecoder.java
StringDecoder.java example
*/ public StringDecoder() { this(true); } /** * Create a {@code StringDecoder} that decodes a bytes stream to a String stream * * @param splitOnNewline whether this decoder should split the received data buffers * along newline characters */ public StringDecoder(boolean splitOnNewline) { super(new MimeType("text", "*", DEFAULT_CHARSET), MimeTypeUtils.ALL); this.splitOnNewline = splitOnNewline; } @Override public boolean canDecode(ResolvableType elementType, MimeType mimeType, Object... hints) { return super.canDecode(elementType, mimeType, hints) && String.class.equals(elementType.getRawClass(
Find elsewhere
🌐
Medium
sid-infinity-yadav.medium.com › using-databuffer-with-spring-webflux-spring-events-a6eb0420ebd2
Using DataBuffer with Spring WebFlux, Spring Events | by Siddarth Yadav | Medium
December 8, 2020 - public class FileEvent extends ApplicationEvent { public FileEvent(String filePath) { super(filePath); } } public class FileEventPublisher { @Autowired ApplicationEventPublisher applicationEventPublisher; public void publishFileEvent(String filePath) { FileEvent fileEvent = new FileEvent(filePath); applicationEventPublisher.publishEvent(fileEvent); } } Listener class in this will do the heavy lifting of converting the DataBuffer to string and passing to subscribers
🌐
javathinking
javathinking.com › blog › convert-buffer-to-string-java
Convert Buffer to String in Java — javathinking.com
Data Transmission: Converting buffer data to a string before sending it over a network or storing it in a text-based file. import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; public class ByteBufferToStringExample { public static void main(String[] args) { // Create a ByteBuffer String originalString = "Hello, World!"; ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(originalString); // Convert ByteBuffer to String String result = StandardCharsets.UTF_8.decode(byteBuffer).toString(); System.out.println("Original String: " + originalString); System.out.println("Converted String: " + result); } }
🌐
Program Creek
programcreek.com › java-api-examples
org.springframework.core.io.buffer.DataBuffer Java Examples
@Test public void toEntityList() { DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); DefaultDataBuffer dataBuffer = factory.wrap(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); Flux<DataBuffer> body = Flux.just(dataBuffer); mockTextPlainResponse(body); List<HttpMessageReader<?>> messageReaders = Collections .singletonList(new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes())); given(mockExchangeStrategies.messageReaders()).willReturn(messageReaders); ResponseEntity<List<String>> result = defaultClientResponse.toEntityList(String.class).block(); assertEquals(Collections.singletonList("foo"), result.getBody()); assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals(HttpStatus.OK.value(), result.getStatusCodeValue()); assertEquals(MediaType.TEXT_PLAIN, result.getHeaders().getContentType()); } Example #2 ·
🌐
Baeldung
baeldung.com › home › spring › spring web › reading flux into a single inputstream using spring reactive webclient
Reading Flux Into a Single InputStream Using Spring Reactive WebClient | Baeldung
January 8, 2024 - In this tutorial, we’ll deep dive into Java reactive programming to solve an interesting problem of how to read Flux<DataBuffer> into a single InputStream. As a first step to solving the problem of reading Flux<DataBuffer> into a single InputStream, we’ll use the Spring reactive WebClient for making a GET request. Further, we can use one of the public API endpoints hosted by gorest.co.in for such testing scenarios: String REQUEST_ENDPOINT = "https://gorest.co.in/public/v2/users";
🌐
GitHub
github.com › spring-projects › spring-framework › blob › main › spring-core › src › test › java › org › springframework › core › io › buffer › DataBufferUtilsTests.java
spring-framework/spring-core/src/test/java/org/springframework/core/io/buffer/DataBufferUtilsTests.java at main · spring-projects/spring-framework
November 10, 2020 - DataBuffer baz = stringBuffer("baz"); Flux<DataBuffer> flux = Flux.just(foo, bar, baz); Mono<DataBuffer> result = DataBufferUtils.join(flux); · StepVerifier.create(result) .consumeNextWith(buf -> { assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("foobarbaz"); release(buf); }) .verifyComplete(); } ·
🌐
Java67
java67.com › 2015 › 06 › how-to-convert-bytebuffer-to-string-in-java-example.html
How to convert ByteBuffer to String in Java [Example] | Java67
Same ByteBuffer can be used to read and write data. If you want to read from ByteBuffer just call the flip() method and it will convert ByteBuffer into reading mode. In this article, you will learn how to convert ByteBuffer to String in Java.
🌐
GitHub
github.com › spring-projects › spring-framework › blob › main › spring-core › src › main › java › org › springframework › core › io › buffer › DataBuffer.java
spring-framework/spring-core/src/main/java/org/springframework/core/io/buffer/DataBuffer.java at main · spring-projects/spring-framework
String toString(int index, int length, Charset charset); · · /** * A dedicated iterator type that ensures the lifecycle of iterated · * {@link ByteBuffer} elements. This iterator must be used in a · * try-with-resources clause or ...
Author: spring-projects
🌐
GitHub
github.com › spring-projects › spring-framework › issues › 30765
Alternative to deprecated toByteBuffer() method to get byteBuffer from a DataBuffer · Issue #30765 · spring-projects/spring-framework
June 28, 2023 - try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { Channels.newChannel(byteArrayOutputStream).write(dataBuffer.toByteBuffer().asReadOnlyBuffer()); String requestBody = IOUtils.toString(byteArrayOutputStream.toByteArray(), "UTF-8"); log.trace("Request body = {} ", requestBody); } catch (IOException e) { e.printStackTrace(); } Reactions are currently unavailable ·
Author: spring-projects
Top answer
1 of 6
33

This is really not as complicated as other answers imply.

The only way to stream the data without buffering it all in memory is to use a pipe, as @jin-kwon suggested. However, it can be done very simply by using Spring's BodyExtractors and DataBufferUtils utility classes.

Example:

private InputStream readAsInputStream(String url) throws IOException {
    PipedOutputStream osPipe = new PipedOutputStream();
    PipedInputStream isPipe = new PipedInputStream(osPipe);

    ClientResponse response = webClient.get().uri(url)
        .accept(MediaType.APPLICATION.XML)
        .exchange()
        .block();
    final int statusCode = response.rawStatusCode();
    // check HTTP status code, can throw exception if needed
    // ....

    Flux<DataBuffer> body = response.body(BodyExtractors.toDataBuffers())
        .doOnError(t -> {
            log.error("Error reading body.", t);
            // close pipe to force InputStream to error,
            // otherwise the returned InputStream will hang forever if an error occurs
            try(isPipe) {
              //no-op
            } catch (IOException ioe) {
                log.error("Error closing streams", ioe);
            }
        })
        .doFinally(s -> {
            try(osPipe) {
              //no-op
            } catch (IOException ioe) {
                log.error("Error closing streams", ioe);
            }
        });

    DataBufferUtils.write(body, osPipe)
        .subscribe(DataBufferUtils.releaseConsumer());

    return isPipe;
}

If you don't care about checking the response code or throwing an exception for a failure status code, you can skip the block() call and intermediate ClientResponse variable by using

flatMap(r -> r.body(BodyExtractors.toDataBuffers()))

instead.

2 of 6
10

A slightly modified version of Bk Santiago's answer makes use of reduce() instead of collect(). Very similar, but doesn't require an extra class:

Java:

body.reduce(new InputStream() {
    public int read() { return -1; }
  }, (s: InputStream, d: DataBuffer) -> new SequenceInputStream(s, d.asInputStream())
).flatMap(inputStream -> /* do something with single InputStream */

Or Kotlin:

body.reduce(object : InputStream() {
  override fun read() = -1
}) { s: InputStream, d -> SequenceInputStream(s, d.asInputStream()) }
  .flatMap { inputStream -> /* do something with single InputStream */ }

Benefit of this approach over using collect() is simply you don't need to have a different class to gather things up.

I created a new empty InputStream(), but if that syntax is confusing, you can also replace it with ByteArrayInputStream("".toByteArray()) instead to create an empty ByteArrayInputStream as your initial value instead.