javaspring-bootspring-webflux

How to use Mono<Object> to get value in webflux project


I m building a Java SpringBoot project with webflux. This is the method:

public Mono<ServerResponse> downloadAttachment(final ServerRequest request) {
        String fileName = "prova_B400.png";
        final var idPercorso = request.queryParam("idPercorso")
                .map(Integer::parseInt).orElse(null);
        //mi serve la tripletta
        //1 tipo di storage
        //2 percorso allegati
        //3 nome file
        Mono<MapFile>mapFile= silverMountainService(super.parseUserInfo(request).block()).getMapFile(idPercorso);

        return Mono.zip(parseUserInfo(request), request.bodyToMono(ObjectNode.class))
                .flatMap(t -> {
                    //var dto = t.getT2();
                    return silverMountainService(t.getT1()).downloadMappaPercorso(
                                    StorageType.parse(mapFile.block().storageType),
                                    mapFile.block().omniaClass,
                                    fileName
                            )
                            .flatMap(fileResult -> ServerResponse.ok()
                                    .headers(h -> h.setContentDisposition(
                                            Optional.ofNullable(fileName)
                                                    .filter(StringUtils::isNotBlank)
                                                    .map(filename -> ContentDisposition.attachment().filename(filename).build())
                                                    .orElseGet(() -> ContentDisposition.inline().build() )
                                    ))
                                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                                    .body(BodyInserters.fromValue(fileResult.getContent()))
                            );
                })
                .onErrorResume(CustomHttpException.class, assEx -> {
                    log.error("Error({}): {}", assEx.getErrorId(), assEx.getMessage());
                    return ServerResponse.status(assEx.getHttpStatus()).bodyValue(String.format("ErrorID: %s", assEx.getErrorId()));
                })
                .onErrorResume(Exception.class, ex -> {
                    var errId = UUID.randomUUID().toString();
                    log.error(String.format("Error(%s) %s", errId, ex.getMessage()), ex);
                    return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).bodyValue(String.format("ErrorID: %s", errId));
                });
    }

With this method, I need to get mapFile object thant contains three field to use in "silverMountainService.downloadMappaPercorso".

To compile the project I must use mapFile.block(), but if I try to call this method I receive the following error:

lock()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-6 

How can I change my code?


Solution

  • you have to review your code, to use reactive API methods and avoid using block. General idea is, if you need to use parameter from one publisher, downstream together with other one, create a new method instead of nested structures. I would also suggest to review the logic of working with ServerRequest, every time you manipulate it, a new request will be executed.

    // 1. Mono<MapFile>mapFile manipulation logic
    
    Mono<MapFile>mapFile = super.parseUserInfo(request).map(p->silverMountainService(p))
      .map(o->o.getMapFile(idPercorso))
      .flatMap(mapFile-> additionalCalcualtions(mapFile, request, fileName))
      
    //2. zip logic
    
      Mono<ServerResponse> additionalCalcualtions(MapFile mapFile, ServerRequest request, String fileName){
              return Mono.zip(parseUserInfo(request), request.bodyToMono(ObjectNode.class))
                    .flatMap(t -> {
                        //var dto = t.getT2();
                        return silverMountainService(t.getT1()).downloadMappaPercorso(StorageType.parse(mapFile.storageType),mapFile.omniaClass, fileName
                                )
                                .flatMap(fileResult -> ServerResponse.ok()
                                        .headers(h -> h.setContentDisposition(
                                                Optional.ofNullable(fileName)
                                                        .filter(StringUtils::isNotBlank)
                                                        .map(filename -> ContentDisposition.attachment().filename(filename).build())
                                                        .orElseGet(() -> ContentDisposition.inline().build() )
                                        ))
                                        .contentType(MediaType.APPLICATION_OCTET_STREAM)
                                        .body(BodyInserters.fromValue(fileResult.getContent()))
                                );
                    })
                    .onErrorResume(CustomHttpException.class, assEx -> {
                        log.error("Error({}): {}", assEx.getErrorId(), assEx.getMessage());
                        return ServerResponse.status(assEx.getHttpStatus()).bodyValue(String.format("ErrorID: %s", assEx.getErrorId()));
                    })
                    .onErrorResume(Exception.class, ex -> {
                        var errId = UUID.randomUUID().toString();
                        log.error(String.format("Error(%s) %s", errId, ex.getMessage()), ex);
                        return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).bodyValue(String.format("ErrorID: %s", errId));
                    });
      }