如何以非阻塞方式将Json字符串解析为JsonNode?

时间:2019-06-02 05:29:20

标签: json jackson reactive-programming spring-webflux nonblocking

我正在探索使用Spring Webflux进行反应式编程,因此,我试图使我的代码完全不受阻塞,以获取反应式应用程序的所有好处。

当前,我用于将Json字符串解析为JsonNode以获得特定值(在本例中为elementId)的方法的代码如下:

public Mono<String> readElementIdFromJsonString(String jsonString){
    final JsonNode jsonNode;
    try {
        jsonNode = MAPPER.readTree(jsonString);
    } catch (IOException e) {
        return Mono.error(e);
    }

    final String elementId = jsonNode.get("elementId").asText();

    return Mono.just(elementId);
}

但是,IntelliJ通知我我正在使用不适当的阻塞方法调用,并带有以下代码:

MAPPER.readTree(jsonString);

如何以非阻塞方式实现此代码?我已经看到,从Jackson 2.9+开始,可以以非阻塞异步方式解析Json String,但是我不知道如何使用该API,也找不到如何正确执行该示例的示例。 >

如果您能帮助我解决这个问题,我将非常感谢!

2 个答案:

答案 0 :(得分:0)

我不知道为什么说这是一个阻塞调用,因为据我所知 Jackson 是非阻塞调用。无论如何,如果您不想使用任何其他库,解决此问题的一种方法是使用调度程序。像这样。

public Mono<String> readElementIdFromJsonString(String input)  {

    return Mono.just(Mapper.readTree(input))
               .map(it -> it.get("elementId").asText())
               .onErrorResume( it -> Mono.error(it))
               .subscribeOn(Schedulers.boundedElastic());
}

类似的东西。

答案 1 :(得分:-1)

import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.codec.json.AbstractJackson2Decoder;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import com.fasterxml.jackson.databind.ObjectMapper;

@FunctionalInterface
public interface MessageParser<T> {

    Mono<T> parse(String message);
}

public class JsonNodeParser extends AbstractJackson2Decoder implements MessageParser<JsonNode> {

    private static final MimeType MIME_TYPE = MimeTypeUtils.APPLICATION_JSON;
    private static final ObjectMapper OBJECT_MAPPER = allocateDefaultObjectMapper();

    private final DefaultDataBufferFactory factory;
    private final ResolvableType resolvableType;

    public JsonNodeParser(final Environment env) {
        super(OBJECT_MAPPER, MIME_TYPE);

        this.factory = new DefaultDataBufferFactory();
        this.resolvableType = ResolvableType.forClass(JsonNode.class);

        this.setMaxInMemorySize(100000); // 1MB

        canDecodeJsonNode();
    }

    @Override
    public Mono<JsonNode> parse(final String message) {
        final byte[] bytes = message.getBytes(StandardCharsets.UTF_8);

        return decode(bytes);
    }

    private Mono<JsonNode> decode(final byte[] bytes) {
        final DefaultDataBuffer defaultDataBuffer = this.factory.wrap(bytes);

        return this.decodeToMono(Mono.just(defaultDataBuffer), this.resolvableType, MIME_TYPE, Map.of())
            .ofType(JsonNode.class)
            .subscribeOn(Schedulers.boundedElastic())
            .doFinally((t) -> DataBufferUtils.release(defaultDataBuffer));
    }

    private void canDecodeJsonNode() {
        if (!canDecode(this.resolvableType, MIME_TYPE)) {
            throw new IllegalStateException(String.format("JsonNodeParser doesn't supports the given tar`enter code here`get " +
                "element type [%s] and the MIME type [%s]", this.resolvableType, MIME_TYPE));
        }
    }
}