@Override public Mono<Void> setComplete() { return writeWith(Flux.empty()); }
@Override public MockServerHttpRequest build() { return body(Flux.empty()); }
void registerAdapter(ReactiveAdapterRegistry registry) { // TODO: remove reflection when build requires JDK 9+ try { String publisherName = "java.util.concurrent.Flow.Publisher"; Class<?> publisherClass = ClassUtils.forName(publisherName, getClass().getClassLoader()); String adapterName = "reactor.adapter.JdkFlowAdapter"; Class<?> flowAdapterClass = ClassUtils.forName(adapterName, getClass().getClassLoader()); Method toFluxMethod = flowAdapterClass.getMethod("flowPublisherToFlux", publisherClass); Method toFlowMethod = flowAdapterClass.getMethod("publisherToFlowPublisher", Publisher.class); Object emptyFlow = ReflectionUtils.invokeMethod(toFlowMethod, null, Flux.empty()); registry.registerReactiveType( ReactiveTypeDescriptor.multiValue(publisherClass, () -> emptyFlow), source -> (Publisher<?>) ReflectionUtils.invokeMethod(toFluxMethod, null, source), publisher -> ReflectionUtils.invokeMethod(toFlowMethod, null, publisher) ); } catch (Throwable ex) { // Ignore } } }
@Override public Mono<Void> setComplete() { return doCommit(() -> Mono.defer(() -> this.writeHandler.apply(Flux.empty()))); }
@Override public MockServerHttpRequest build() { return body(Flux.empty()); }
@Override public Mono<Void> setComplete() { return writeWith(Flux.empty()); }
private HttpMessageWriter<String> getWriter(MimeType... mimeTypes) { return getWriter(Flux.empty(), mimeTypes); }
@Override public Mono<Void> setComplete() { return doCommit(() -> Mono.defer(() -> this.writeHandler.apply(Flux.empty()))); }
@SuppressWarnings("unchecked") private <T> Flux<DataBuffer> encodeData(@Nullable T data, ResolvableType valueType, MediaType mediaType, DataBufferFactory factory, Map<String, Object> hints) { if (data == null) { return Flux.empty(); } if (data instanceof String) { String text = (String) data; return Flux.from(encodeText(StringUtils.replace(text, "\n", "\ndata:") + "\n", mediaType, factory)); } if (this.encoder == null) { return Flux.error(new CodecException("No SSE encoder configured and the data is not String.")); } return ((Encoder<T>) this.encoder) .encode(Mono.just(data), factory, valueType, mediaType, hints) .concatWith(encodeText("\n", mediaType, factory)); }
/** * Test a {@link Decoder#decode decode} scenario where the input stream is empty. * The output is expected to be empty as well. * * @param outputType the desired output type * @param mimeType the mime type to use for decoding. May be {@code null}. * @param hints the hints used for decoding. May be {@code null}. */ protected void testDecodeEmpty(ResolvableType outputType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { Flux<DataBuffer> input = Flux.empty(); Flux<?> result = this.decoder.decode(input, outputType, mimeType, hints); StepVerifier.create(result) .verifyComplete(); }
/** * Test a {@link Decoder#decodeToMono decode} scenario where the input stream is empty. * The output is expected to be empty as well. * * @param outputType the desired output type * @param mimeType the mime type to use for decoding. May be {@code null}. * @param hints the hints used for decoding. May be {@code null}. */ protected void testDecodeToMonoEmpty(ResolvableType outputType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { Flux<DataBuffer> input = Flux.empty(); Mono<?> result = this.decoder.decodeToMono(input, outputType, mimeType, hints); StepVerifier.create(result) .verifyComplete(); }
/** * Test a {@link Encoder#encode encode} scenario where the input stream is empty. * The output is expected to be empty as well. * * @param inputType the input type * @param mimeType the mime type to use for decoding. May be {@code null}. * @param hints the hints used for decoding. May be {@code null}. */ protected void testEncodeEmpty(ResolvableType inputType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { Flux<?> input = Flux.empty(); Flux<DataBuffer> result = encoder().encode(input, this.bufferFactory, inputType, mimeType, hints); StepVerifier.create(result) .verifyComplete(); }
private void testSseResponse(boolean expectSseEmitter) throws Exception { ResponseBodyEmitter emitter = handleValue(Flux.empty(), Flux.class, forClass(String.class)); assertEquals(expectSseEmitter, emitter instanceof SseEmitter); resetRequest(); }
@Test public void decodeToMonoWithEmptyFlux() { Flux<DataBuffer> input = Flux.empty(); testDecodeToMono(input, String.class, step -> step .expectComplete() .verify()); }
@Test public void decodeEmptyFlux() { Flux<DataBuffer> input = Flux.empty(); testDecode(input, String.class, step -> step .expectComplete() .verify()); }
@Test public void completionBeforeFirstItem() throws Exception { Mono<Void> completion = Flux.<String>empty().as(this::sendOperator); Signal<Void> signal = completion.materialize().block(); assertNotNull(signal); assertTrue("Unexpected signal: " + signal, signal.isOnComplete()); assertEquals(0, this.writer.items.size()); assertTrue(this.writer.completed); }
@Override public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) { String path = request.getURI().getPath(); switch (path) { case "/write-and-flush": return response.writeAndFlushWith( testInterval(Duration.ofMillis(50), 2) .map(longValue -> wrap("data" + longValue + "\n", response)) .map(Flux::just) .mergeWith(Flux.never())); case "/write-and-complete": return response.writeWith( chunks1K().take(64).map(s -> wrap(s, response))); case "/write-and-never-complete": // Reactor requires at least 50 to flush, Tomcat/Undertow 8, Jetty 1 return response.writeWith( chunks1K().take(64).map(s -> wrap(s, response)).mergeWith(Flux.never())); default: return response.writeWith(Flux.empty()); } }
@Test // SPR-15758 public void toMonoWithEmptyBodyAndNoContentType() { BodyExtractor<Mono<Map<String, String>>, ReactiveHttpInputMessage> extractor = BodyExtractors.toMono(new ParameterizedTypeReference<Map<String, String>>() {}); MockServerHttpRequest request = MockServerHttpRequest.post("/").body(Flux.empty()); Mono<Map<String, String>> result = extractor.extract(request, this.context); StepVerifier.create(result).expectComplete().verify(); }
private void testEmitterContentType(String expected) throws Exception { ServletServerHttpResponse message = new ServletServerHttpResponse(this.servletResponse); ResponseBodyEmitter emitter = handleValue(Flux.empty(), Flux.class, forClass(String.class)); emitter.extendResponse(message); assertEquals(expected, message.getHeaders().getContentType().toString()); resetRequest(); }
@Test public void voidReturnType() throws Exception { testVoid(null, on(TestController.class).resolveReturnType(void.class)); testVoid(Mono.empty(), on(TestController.class).resolveReturnType(Mono.class, Void.class)); testVoid(Flux.empty(), on(TestController.class).resolveReturnType(Flux.class, Void.class)); testVoid(Completable.complete(), on(TestController.class).resolveReturnType(Completable.class)); testVoid(Observable.empty(), on(TestController.class).resolveReturnType(Observable.class, Void.class)); MethodParameter type = on(TestController.class).resolveReturnType(io.reactivex.Completable.class); testVoid(io.reactivex.Completable.complete(), type); type = on(TestController.class).resolveReturnType(io.reactivex.Observable.class, Void.class); testVoid(io.reactivex.Observable.empty(), type); type = on(TestController.class).resolveReturnType(Flowable.class, Void.class); testVoid(Flowable.empty(), type); }