Interface Multipart


public interface Multipart
A reactive Multipart that represents Multiple part messages.
  • Method Details

    • of

      static Multipart of(BodyPart... parts)
      Returns a new Multipart with the specified BodyParts.
    • of

      static Multipart of(Iterable<? extends BodyPart> parts)
      Returns a new Multipart with the specified BodyParts.
    • of

      static Multipart of(String boundary, BodyPart... parts)
      Returns a new Multipart with the specified boundary and BodyParts.
    • of

      static Multipart of(String boundary, Iterable<? extends BodyPart> parts)
      Returns a new Multipart with the specified boundary and BodyParts.
    • of

      static Multipart of(org.reactivestreams.Publisher<? extends BodyPart> parts)
      Returns a new Multipart with the specified BodyParts.
    • of

      static Multipart of(String boundary, org.reactivestreams.Publisher<? extends BodyPart> parts)
      Returns a new Multipart with the specified BodyParts.
    • from

      static Multipart from(HttpRequest request)
      Returns a decoded Multipart from the specified HttpRequest. You can reactively subscribe to body parts using the Publisher of bodyParts():
      
       import reactor.core.publisher.Flux;
      
       HttpRequest req = ...;
       Multipart multiPart = Multipart.from(req);
      
       Flux.from(multiPart.bodyParts())
           .subscribe(bodyPart -> {
               Flux.from(bodyPart.content())
                   .map(HttpData::toStringUtf8)
                   .collectList()
                   .subscribe(contents -> { ... });
           });
       
      , or aggregate this Multipart using aggregate():
      
       Multipart.from(req).aggregate()
                .thenAccept(multipart -> {
                    for (AggregatedBodyPart bodyPart : multipart.bodyParts()) {
                        String content = bodyPart.contentUtf8();
                        ...
                    }
                });
       
      See Also:
    • from

      static Multipart from(String boundary, org.reactivestreams.Publisher<? extends HttpData> contents)
      Returns a decoded Multipart from the specified boundary and Publisher of HttpData. For instance, Multipart could be decoded from the specified HttpResponse in the following way:
      
       HttpResponse response = ...;
       SplitHttpResponse splitResponse = response.split();
       ResponseHeaders responseHeaders = splitResponse.headers().join();
       ByteStreamMessage responseContents = splitResponse.body();
       MediaType contentType = responseHeaders.contentType();
       if (contentType != null && contentType.isMultipart()) {
           String boundary = Multiparts.getBoundary(contentType);
           Multipart multipart = Multipart.from(boundary, responseContents);
           ...
       } else {
           handleNonMultipartResponse(responseHeaders, responseContents);
       }
       
    • from

      static Multipart from(String boundary, org.reactivestreams.Publisher<? extends HttpData> contents, ByteBufAllocator alloc)
      Returns a decoded Multipart from the specified boundary, Publisher of HttpData and ByteBufAllocator.
    • toHttpRequest

      HttpRequest toHttpRequest(String path)
      Converts this Multipart into a new complete HttpRequest. This method is commonly used to send a multipart request to the specified path of an endpoint.

      For example:

      
       HttpHeaders headers = HttpHeaders.of(HttpHeaderNames.CONTENT_DISPOSITION,
                                            ContentDisposition.of("form-data", "file", "test.txt"));
       byte[] fileData = ...;
       BodyPart filePart = BodyPart.builder()
                                   .headers(headers)
                                   .content(fileData)
                                   .build();
      
       HttpRequest request = Multipart.of(filePart).toHttpRequest("/upload");
       CompletableFuture<AggregatedHttpResponse> response = client.execute(request).aggregate();
       
    • toHttpRequest

      HttpRequest toHttpRequest(RequestHeaders requestHeaders)
      Converts this Multipart into a new complete HttpRequest with the specified RequestHeaders. This method is commonly used to send a multipart request using the specified RequestHeaders.

      For example:

      
       HttpHeaders headers = HttpHeaders.of(HttpHeaderNames.CONTENT_DISPOSITION,
                                            ContentDisposition.of("form-data", "file", "test.txt"));
       byte[] fileData = ...;
       BodyPart filePart = BodyPart.builder()
                                   .headers(headers)
                                   .content(fileData)
                                   .build();
      
       RequestHeaders requestHeaders = RequestHeaders.builder(HttpMethod.POST, "/upload")
                                                     .contentType(MediaType.MULTIPART_RELATED)
                                                     .build();
       HttpRequest request = Multipart.of(filePart).toHttpRequest(requestHeaders);
       CompletableFuture<AggregatedHttpResponse> response = client.execute(request).aggregate();
       
    • toHttpResponse

      HttpResponse toHttpResponse(HttpStatus status)
      Converts this Multipart into a new complete HttpResponse. This method is commonly used to send a multipart response with the specified HttpStatus.

      For example:

      
       HttpHeaders headers = HttpHeaders.of(HttpHeaderNames.CONTENT_DISPOSITION,
                                            ContentDisposition.of("form-data", "file", "test.txt"));
       byte[] fileData = ...;
       BodyPart filePart = BodyPart.builder()
                                   .headers(headers)
                                   .content(fileData)
                                   .build();
      
       HttpResponse response = Multipart.of(filePart).toHttpResponse(HttpStatus.OK);
       
    • toHttpResponse

      HttpResponse toHttpResponse(ResponseHeaders responseHeaders)
      Converts this Multipart into a new complete HttpResponse with the specified ResponseHeaders. This method is commonly used to send a multipart response using the specified ResponseHeaders.

      For example:

      
       HttpHeaders headers = HttpHeaders.of(HttpHeaderNames.CONTENT_DISPOSITION,
                                            ContentDisposition.of("form-data", "file", "test.txt"));
       byte[] fileData = ...;
       BodyPart filePart = BodyPart.builder()
                                   .headers(headers)
                                   .content(fileData)
                                   .build();
      
       ResponseHeaders responseHeaders = ResponseHeaders.builder(HttpStatus.OK)
                                                        .contentType(MediaType.MULTIPART_RELATED)
                                                        .build();
       HttpResponse response = Multipart.of(filePart).toHttpResponse(responseHeaders);
       
    • toStreamMessage

      @CheckReturnValue ByteStreamMessage toStreamMessage()
      Returns a ByteStreamMessage that emits the {bodyParts()} as a stream of HttpData.
    • boundary

      String boundary()
      Returns the boundary string.
    • bodyParts

      @CheckReturnValue StreamMessage<BodyPart> bodyParts()
      Returns all the nested body parts.

      Note: Once a BodyPart is subscribed, you should subscribe to BodyPart.content() before subscribing to the next BodyPart.

      
       import reactor.core.publisher.Flux;
      
       HttpRequest req = ...;
       Multipart multiPart = Multipart.from(req);
      
       // Good:
       Flux.from(multiPart.bodyParts())
           .subscribe(bodyPart -> {
               Flux.from(bodyPart.content()) // Safely subscribe to BodyPart.content()
                   .map(HttpData::toStringUtf8)
                   .collectList()
                   .subscribe(contents -> { ... });
           });
      
       // Bad:
       Flux.from(multiPart.bodyParts())
           .collectList() // This will subscribe BodyPart.content() first before you subscribe to it.
           .subscribe(bodyParts -> {
               bodyParts.forEach(part -> {
                   Flux.from(part.content())
                       .collectList() // Throws IllegalStateException("Only single subscriber is allowed")
                       .subscribe(contents -> { ... });
               });
           });
        
      If you don't know what this means, use aggregate().
    • aggregate

      Aggregates this Multipart. The returned CompletableFuture will be notified when the BodyParts of the Multipart is received fully.

      For example:

      
       HttpRequest req = ...;
       Multipart.from(req).aggregate()
                .thenAccept(multipart -> {
                    for (AggregatedBodyPart bodyPart : multipart.bodyParts()) {
                        String content = bodyPart.contentUtf8();
                        ...
                    }
                });
       
    • aggregate

      Aggregates this Multipart with the specified EventExecutor. The returned CompletableFuture will be notified when the BodyParts of the Multipart is received fully.

      For example:

      
       HttpRequest req = ...;
       EventExecutor executor = ...;
       Multipart.from(req).aggregate(executor)
                .thenAccept(multipart -> {
                    for (AggregatedBodyPart bodyPart : multipart.bodyParts()) {
                        String content = bodyPart.contentUtf8();
                        ...
                    }
                });
       
    • aggregateWithPooledObjects

      CompletableFuture<AggregatedMultipart> aggregateWithPooledObjects(ByteBufAllocator alloc)
      (Advanced users only) Aggregates this Multipart. The returned CompletableFuture will be notified when the BodyParts of the Multipart is received fully. AggregatedHttpObject.content() will return a pooled object, and the caller must ensure to release it. If you don't know what this means, use aggregate().
    • aggregateWithPooledObjects

      CompletableFuture<AggregatedMultipart> aggregateWithPooledObjects(EventExecutor executor, ByteBufAllocator alloc)
      (Advanced users only) Aggregates this Multipart. The returned CompletableFuture will be notified when the BodyParts of the Multipart is received fully. AggregatedHttpObject.content() will return a pooled object, and the caller must ensure to release it. If you don't know what this means, use aggregate().
    • collect

      @UnstableApi default <T> CompletableFuture<List<T>> collect(Function<? super BodyPart,CompletableFuture<? extends T>> function)
      Collects the elements published by this Multipart. The returned CompletableFuture will be notified when the elements are fully consumed.

      Note that if this Multipart was subscribed by other Subscriber already, the returned CompletableFuture will be completed with an IllegalStateException.

      For example:

      
       Path tempDir = ...;
       CompletableFuture<List<Object>> collect =
               Multipart.of(request)
                        .collect(bodyPart -> {
                            if (bodyPart.filename() != null) {
                                final Path path = tempDir.resolve(bodyPart.name());
                                return bodyPart.writeTo(path).thenApply(ignore -> path);
                            }
                            return bodyPart.aggregate().thenApply(AggregatedHttpObject::contentUtf8);
                        });
       
      Parameters:
      function - A Function that processes the BodyPart and returns a future that will complete with the process result. The Function must consume the BodyPart. And If not, collect method will stop processing next BodyPart.
    • collect

      @UnstableApi default <T> CompletableFuture<List<T>> collect(Function<? super BodyPart,CompletableFuture<? extends T>> function, SubscriptionOption... options)
      Collects the elements published by this Multipart. The returned CompletableFuture will be notified when the elements are fully consumed.

      Note that if this Multipart was subscribed by other Subscriber already, the returned CompletableFuture will be completed with an IllegalStateException.