gpt4 book ai didi

java - 热衷于从 spring 响应式(Reactive) ClientRequest 获取字符串形式的正文?

转载 作者:行者123 更新时间:2023-12-01 17:29:09 59 4
gpt4 key购买 nike

在测试方法中,接收 org.springframework.web.reactive.function.client.ClientRequest 的实例。

我想验证它的 HttpMethod、URI 和正文。

很明显如何获取除 body 之外的所有内容。

ClientRequest request = makeInstance(...);

assertEquals(HttpMethod.POST, request.method());
assertEquals("somewhere/else", request.url().toString());

// ? unclear how to extract body using the BodyInserter

BodyInserter<?, ? super ClientHttpRequest> inserter = request.body();

inserter.insert(%outputMessage%, %context%);

我在Spring的来源中找到了how BodyInserters are tested 。如何创建 BodyInserter.Context (第二个参数)或多或少很清楚,但我不明白如何构造第一个参数,因此可以通过它提取请求正文。

请展示一种从 ClientRequest 实例获取请求正文的传统(或至少可用)方法。

最佳答案

对于这样一个简单的情况来说有点复杂,但我花了 5 个类来从 ClientRequest 中提取正文。

这似乎太多了,我仍然很好奇是否有一个简短的解决方案来解决这个问题。欢迎您对此问题提出另一个答案,以便我接受。

不幸的是,必须说的是 ClientRequestBodyInserters 的设计以及来自 org.springframework.web.reactive 的大多数其他内容。** *还有很大的改进空间。目前它只是一堆接口(interface),每个接口(interface)都有大量方法,并且通常需要花费大量精力来测试代码,具体取决于这些类。

让这个方法发挥作用的主要目标:

static <T> T extractBody(ClientRequest request, Class<T> clazz) {

InsertionReceiver<T> receiver = InsertionReceiver.forClass(clazz);
return receiver.receiveValue(request.body());
}

这是InsertionReceiver的实现:

<小时/>
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.web.reactive.function.BodyInserter;

public interface InsertionReceiver<T> {

T receiveValue(BodyInserter<?, ? extends ReactiveHttpOutputMessage> bodyInserter);

static <T> InsertionReceiver<T> forClass(Class<T> clazz) {
return new SimpleValueReceiver<>(clazz);
}
}
<小时/>
  • import java.util.concurrent.atomic.AtomicReference;
    import org.springframework.http.ReactiveHttpOutputMessage;
    import org.springframework.web.reactive.function.BodyInserter;

    class SimpleValueReceiver<T> implements InsertionReceiver<T> {

    private static final Object DUMMY = new Object();

    private final Class<T> clazz;
    private final AtomicReference<Object> reference;

    SimpleValueReceiver(Class<T> clazz) {
    this.clazz = clazz;
    this.reference = new AtomicReference<>(DUMMY);
    }

    @Override
    public T receiveValue(BodyInserter<?, ? extends ReactiveHttpOutputMessage> bodyInserter) {
    demandValueFrom(bodyInserter);

    return receivedValue();
    }

    private void demandValueFrom(BodyInserter<?, ? extends ReactiveHttpOutputMessage> bodyInserter) {
    var inserter = (BodyInserter<?, ReactiveHttpOutputMessage>) bodyInserter;

    inserter.insert(
    MinimalHttpOutputMessage.INSTANCE,
    new SingleWriterContext(new WriteToConsumer<>(reference::set))
    );
    }

    private T receivedValue() {
    Object value = reference.get();
    reference.set(DUMMY);

    T validatedValue;

    if (value == DUMMY) {
    throw new RuntimeException("Value was not received, Check your inserter worked properly");
    } else if (!clazz.isAssignableFrom(value.getClass())) {
    throw new RuntimeException(
    "Value has unexpected type ("
    + value.getClass().getTypeName()
    + ") instead of (" + clazz.getTypeName() + ")");
    } else {
    validatedValue = clazz.cast(value);
    }

    return validatedValue;
    }
    }
    <小时/>
  • class WriteToConsumer<T> implements HttpMessageWriter<T> {

    private final Consumer<T> consumer;
    private final List<MediaType> mediaTypes;

    WriteToConsumer(Consumer<T> consumer) {
    this.consumer = consumer;
    this.mediaTypes = Collections.singletonList(MediaType.ALL);
    }

    @Override
    public List<MediaType> getWritableMediaTypes() {
    return mediaTypes;
    }

    @Override
    public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
    return true;
    }

    @Override
    public Mono<Void> write(
    Publisher<? extends T> inputStream,
    ResolvableType elementType,
    MediaType mediaType,
    ReactiveHttpOutputMessage message,
    Map<String, Object> hints
    ) {
    inputStream.subscribe(new OneValueConsumption<>(consumer));
    return Mono.empty();
    }
    }
    <小时/>
  • class MinimalHttpOutputMessage implements ReactiveHttpOutputMessage {

    public static MinimalHttpOutputMessage INSTANCE = new MinimalHttpOutputMessage();

    private MinimalHttpOutputMessage() {
    }

    @Override
    public HttpHeaders getHeaders() {
    return HttpHeaders.EMPTY;
    }

    // other overridden methods are omitted as they do nothing,
    // i.e. return null, false, or have empty bodies
    }
    <小时/>
  • class OneValueConsumption<T> implements Subscriber<T> {

    private final Consumer<T> consumer;
    private int remainedAccepts;

    public OneValueConsumption(Consumer<T> consumer) {
    this.consumer = Objects.requireNonNull(consumer);
    this.remainedAccepts = 1;
    }

    @Override
    public void onSubscribe(Subscription s) {
    s.request(1);
    }

    @Override
    public void onNext(T o) {
    if (remainedAccepts > 0) {
    consumer.accept(o);
    remainedAccepts -= 1;
    } else {
    throw new RuntimeException("No more values can be consumed");
    }
    }

    @Override
    public void onError(Throwable t) {
    throw new RuntimeException("Single value was not consumed", t);
    }

    @Override
    public void onComplete() {
    // nothing
    }
    }
    <小时/>
  • class SingleWriterContext implements BodyInserter.Context {

    private final List<HttpMessageWriter<?>> singleWriterList;

    SingleWriterContext(HttpMessageWriter<?> writer) {
    this.singleWriterList = List.of(writer);
    }

    @Override
    public List<HttpMessageWriter<?>> messageWriters() {
    return singleWriterList;
    }

    @Override
    public Optional<ServerHttpRequest> serverRequest() {
    return Optional.empty();
    }

    @Override
    public Map<String, Object> hints() {
    return null;
    }
    }

    关于java - 热衷于从 spring 响应式(Reactive) ClientRequest 获取字符串形式的正文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61156827/

    59 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com