How can I read Flux<DataBuffer> content?

868 Views Asked by At

I want to read mulitpart/formdata, one part is application/JSON. I can't get them to Map<String,String>, Is there any way to parse Part to String?

private Map<String, String> getFormData(String path, MultiValueMap<String, Part> partMultiValueMap) {
    if (partMultiValueMap != null) {
        Map<String, String> formData = new HashMap<>();
        Map<String, Part> multiPartMap = partMultiValueMap.toSingleValueMap();
        for (Map.Entry<String, Part> partEntry : multiPartMap.entrySet()) {
            Part part = partEntry.getValue();
            if (part instanceof FormFieldPart) {
                formData.put(partEntry.getKey(), ((FormFieldPart) part).value());
            } else {
                String bodyString = bufferToStr(part.content());
                formData.put(partEntry.getKey(), bodyString);

            }
        }
        return formData;
    }
    return null;
}

extra Flux

private String bufferToStr(Flux<DataBuffer> content){
    AtomicReference<String> res = new AtomicReference<>();
    content.subscribe(buffer -> {
        byte[] bytes = new byte[buffer.readableByteCount()];
        buffer.read(bytes);
        DataBufferUtils.release(buffer);
        res.set(new String(bytes, StandardCharsets.UTF_8));
    });
    return res.get();
}

Subscribe is async; bufferToStr value may be null?

1

There are 1 best solutions below

1
kerbermeister On BEST ANSWER

You could do it in non-blocking way with StringDecoder

Basically you could write your code to return Mono<Map<>>

Note: I'm using Pair class here to return key-value and later collect them to Map

Pair I'm using here is from package org.springframework.data.util.Pair

public Mono<Map<String, String>> getFormData(MultiValueMap<String, Part> partMultiValueMap) {
    Map<String, Part> multiPartMap = partMultiValueMap.toSingleValueMap();

    return Flux.fromIterable(multiPartMap.entrySet())
            .flatMap(entry -> {
                Part part = entry.getValue();
                if (part instanceof FormFieldPart) {
                    return Mono.just(
                            Pair.of(entry.getKey(), ((FormFieldPart) part).value()) // return Pair
                    );
                } else {
                    return decodePartToString(part.content()) // decoding DataBuffers to string
                            .flatMap(decodedString ->
                                    Mono.just(Pair.of(entry.getKey(), decodedString))); // return Pair
                }
            })
            .collectMap(Pair::getFirst, Pair::getSecond); // map and collect pairs to Map<>
}

private Mono<String> decodePartToString(Flux<DataBuffer> dataBufferFlux) {
    StringDecoder stringDecoder = StringDecoder.textPlainOnly();

    return stringDecoder.decodeToMono(dataBufferFlux,
            ResolvableType.NONE,
            MimeTypeUtils.TEXT_PLAIN,
            Collections.emptyMap()
    );
}