From b69cbad38dffa4b7bae7361d5b028602ce31bf0f Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Fri, 9 Jan 2026 11:52:18 +0000 Subject: [PATCH] Fall back on the value type in BodyInserters if necessary Closes gh-36078 --- .../web/reactive/function/BodyInserters.java | 10 ++++-- .../client/support/WebClientAdapterTests.java | 32 ++++++++++++++++++- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java index 25d959b6e1a..003f716510b 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java @@ -98,7 +98,8 @@ public abstract class BodyInserters { public static BodyInserter fromValue(T body) { Assert.notNull(body, "'body' must not be null"); Assert.isNull(registry.getAdapter(body.getClass()), - "'body' should be an object, for reactive types use a variant specifying a publisher/producer and its related element type"); + "'body' should not be a reactive type. " + + "For reactive types use a variant with a publisher/producer and the element type"); return (message, context) -> writeWithMessageWriters(message, context, Mono.just(body), ResolvableType.forInstance(body), null); } @@ -124,9 +125,12 @@ public abstract class BodyInserters { Assert.notNull(body, "'body' must not be null"); Assert.notNull(bodyType, "'bodyType' must not be null"); Assert.isNull(registry.getAdapter(body.getClass()), - "'body' should be an object, for reactive types use a variant specifying a publisher/producer and its related element type"); + "'body' should not be a reactive type. " + + "For reactive types use a variant with a publisher/producer and the element type"); + ResolvableType bodyTypeToUse = (bodyType.getType().equals(Object.class) ? + ResolvableType.forInstance(body) : ResolvableType.forType(bodyType)); return (message, context) -> - writeWithMessageWriters(message, context, Mono.just(body), ResolvableType.forType(bodyType), null); + writeWithMessageWriters(message, context, Mono.just(body), bodyTypeToUse, null); } /** diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientAdapterTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientAdapterTests.java index babb6d0f60f..97066d81e97 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientAdapterTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientAdapterTests.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Function; +import jakarta.xml.bind.annotation.XmlRootElement; import mockwebserver3.MockResponse; import mockwebserver3.MockWebServer; import mockwebserver3.RecordedRequest; @@ -36,6 +37,7 @@ import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -189,6 +191,24 @@ class WebClientAdapterTests { assertThat(request.getBody().utf8()).isEqualTo("[{\"name\":\"John\"},{\"name\":\"Richard\"}]"); } + @Test // gh-36078 + void postObject() throws InterruptedException { + prepareResponse(response -> response.code(201)); + + WebClient webClient = WebClient.builder() + .baseUrl(this.server.url("/").toString()) + .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) + .build(); + + initService(webClient).postObject(new Person("John")); + + RecordedRequest request = server.takeRequest(); + assertThat(request.getMethod()).isEqualTo("POST"); + assertThat(request.getTarget()).isEqualTo("/object"); + assertThat(request.getBody().utf8()).isEqualTo( + "John"); + } + @Test void uriBuilderFactory() throws Exception { String ignoredResponseBody = "hello"; @@ -304,6 +324,9 @@ class WebClientAdapterTests { @PostExchange("/persons") void postPersonSet(@RequestBody Set set); + @PostExchange("/object") + void postObject(@RequestBody Object object); + @GetExchange("/greeting") String getWithUriBuilderFactory(UriBuilderFactory uriBuilderFactory); @@ -316,9 +339,13 @@ class WebClientAdapterTests { } + @XmlRootElement static final class Person { - private final String name; + private String name; + + public Person() { + } Person(String name) { this.name = name; @@ -328,6 +355,9 @@ class WebClientAdapterTests { return this.name; } + public void setName(String name) { + this.name = name; + } } }