ReactiveAdapter adapter = getAdapterRegistry().getAdapter(bodyType.resolve(), body); publisher = adapter.toPublisher(body); ResolvableType genericType = bodyType.getGeneric(); elementType = getElementType(adapter, genericType); MediaType bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType)); if (bestMediaType != null) { String logPrefix = exchange.getLogPrefix(); (publisher instanceof Mono ? "0..1" : "0..N") + " [" + elementType + "]"); for (HttpMessageWriter<?> writer : getMessageWriters()) { if (writer.canWrite(elementType, bestMediaType)) { return writer.write((Publisher) publisher, actualType, elementType, bestMediaType, if (getMediaTypesFor(elementType).isEmpty()) { return Mono.error(new IllegalStateException("No writer for : " + elementType)); return Mono.error(new NotAcceptableStatusException(getMediaTypesFor(elementType)));
/** * Write a given body to the response with {@link HttpMessageWriter}. * @param body the object to write * @param bodyParameter the {@link MethodParameter} of the body to write * @param exchange the current exchange * @return indicates completion or error * @see #writeBody(Object, MethodParameter, MethodParameter, ServerWebExchange) */ protected Mono<Void> writeBody(@Nullable Object body, MethodParameter bodyParameter, ServerWebExchange exchange) { return this.writeBody(body, bodyParameter, null, exchange); }
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(valueClass, body); .doOnSubscribe(sub -> updateResponseStatus(bodyParameter, exchange)); MediaType bestMediaType = selectMediaType(exchange, () -> getProducibleMediaTypes(elementType)); if (bestMediaType != null) { for (HttpMessageWriter<?> messageWriter : getMessageWriters()) { if (messageWriter.canWrite(elementType, bestMediaType)) { Mono<Void> bodyWriter = (messageWriter instanceof ServerHttpMessageWriter ? messageWriter.write((Publisher) publisher, elementType, bestMediaType, response, Collections.emptyMap())); return bodyWriter.doOnSubscribe(sub -> updateResponseStatus(bodyParameter, exchange)); if (getProducibleMediaTypes(elementType).isEmpty()) { return Mono.error(new IllegalStateException( "No converter for return value type: " + elementType)); return Mono.error(new NotAcceptableStatusException(getProducibleMediaTypes(elementType)));
private List<MediaType> getMediaTypesFor(ResolvableType elementType) { return getMessageWriters().stream() .filter(converter -> converter.canWrite(elementType, null)) .flatMap(converter -> converter.getWritableMediaTypes().stream()) .collect(Collectors.toList()); }
private List<MediaType> getProducibleMediaTypes(ResolvableType elementType) { return getMessageWriters().stream() .filter(converter -> converter.canWrite(elementType, null)) .flatMap(converter -> converter.getWritableMediaTypes().stream()) .collect(Collectors.toList()); }
@Test // SPR-13631 public void useDefaultCharset() throws Exception { this.exchange.getAttributes().put(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Collections.singleton(APPLICATION_JSON)); String body = "foo"; MethodParameter type = on(TestController.class).resolveReturnType(String.class); this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); }
@Test // SPR-12894 public void useDefaultContentType() throws Exception { Resource body = new ClassPathResource("logo.png", getClass()); MethodParameter type = on(TestController.class).resolveReturnType(Resource.class); this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5)); assertEquals("image/png", this.exchange.getResponse().getHeaders().getFirst("Content-Type")); }
private void testVoid(Object body, MethodParameter returnType) { this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5)); assertNull(this.exchange.getResponse().getHeaders().get("Content-Type")); StepVerifier.create(this.exchange.getResponse().getBody()) .expectErrorMatches(ex -> ex.getMessage().startsWith("No content was written")).verify(); }
@Test // SPR-12811 public void jacksonTypeOfListElement() throws Exception { MethodParameter returnType = on(TestController.class).resolveReturnType(List.class, ParentClass.class); List<ParentClass> body = Arrays.asList(new Foo("foo"), new Bar("bar")); this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); assertResponseBody("[{\"type\":\"foo\",\"parentProperty\":\"foo\"}," + "{\"type\":\"bar\",\"parentProperty\":\"bar\"}]"); }
@Test // SPR-13318 public void jacksonTypeWithSubTypeOfListElement() throws Exception { MethodParameter returnType = on(TestController.class).resolveReturnType(List.class, Identifiable.class); List<SimpleBean> body = Arrays.asList(new SimpleBean(123L, "foo"), new SimpleBean(456L, "bar")); this.resultHandler.writeBody(body, returnType, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); assertResponseBody("[{\"id\":123,\"name\":\"foo\"},{\"id\":456,\"name\":\"bar\"}]"); }
@Test // SPR-13318 public void jacksonTypeWithSubType() throws Exception { SimpleBean body = new SimpleBean(123L, "foo"); MethodParameter type = on(TestController.class).resolveReturnType(Identifiable.class); this.resultHandler.writeBody(body, type, this.exchange).block(Duration.ofSeconds(5)); assertEquals(APPLICATION_JSON_UTF8, this.exchange.getResponse().getHeaders().getContentType()); assertResponseBody("{\"id\":123,\"name\":\"foo\"}"); }
@Test // SPR-13135 public void unsupportedReturnType() throws Exception { ByteArrayOutputStream body = new ByteArrayOutputStream(); MethodParameter type = on(TestController.class).resolveReturnType(OutputStream.class); HttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder()); Mono<Void> mono = initResultHandler(writer).writeBody(body, type, this.exchange); StepVerifier.create(mono).expectError(IllegalStateException.class).verify(); }