Skip to content

Commit 9d04c04

Browse files
committed
Allow empty body with no content type in BodyExtractors
Issue: SPR-15758
1 parent d2c6ea5 commit 9d04c04

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ static <T> BodyExtractor<Mono<T>, ReactiveHttpInputMessage> toMono(ResolvableTyp
103103
return reader.readMono(elementType, inputMessage, context.hints());
104104
}
105105
},
106-
Mono::error,
106+
ex -> (inputMessage.getHeaders().getContentType() == null) ?
107+
Mono.from(permitEmptyOrFail(inputMessage, ex)) : Mono.error(ex),
107108
Mono::empty);
108109
}
109110

@@ -138,6 +139,7 @@ public static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(Parame
138139
return toFlux(ResolvableType.forType(typeReference.getType()));
139140
}
140141

142+
@SuppressWarnings("unchecked")
141143
static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(ResolvableType elementType) {
142144
Assert.notNull(elementType, "'elementType' must not be null");
143145
return (inputMessage, context) -> readWithMessageReaders(inputMessage, context,
@@ -152,10 +154,18 @@ static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(ResolvableTyp
152154
return reader.read(elementType, inputMessage, context.hints());
153155
}
154156
},
155-
Flux::error,
157+
ex -> (inputMessage.getHeaders().getContentType() == null) ?
158+
permitEmptyOrFail(inputMessage, ex) : Flux.error(ex),
156159
Flux::empty);
157160
}
158161

162+
@SuppressWarnings("unchecked")
163+
private static <T> Flux<T> permitEmptyOrFail(ReactiveHttpInputMessage message, UnsupportedMediaTypeException ex) {
164+
return message.getBody().doOnNext(buffer -> {
165+
throw ex;
166+
}).map(o -> (T) o);
167+
}
168+
159169
/**
160170
* Return a {@code BodyExtractor} that reads form data into a {@link MultiValueMap}.
161171
* @return a {@code BodyExtractor} that reads form data
@@ -225,7 +235,8 @@ public static BodyExtractor<Flux<DataBuffer>, ReactiveHttpInputMessage> toDataBu
225235

226236
private static <T, S extends Publisher<T>> S readWithMessageReaders(
227237
ReactiveHttpInputMessage inputMessage, BodyExtractor.Context context, ResolvableType elementType,
228-
Function<HttpMessageReader<T>, S> readerFunction, Function<Throwable, S> unsupportedError,
238+
Function<HttpMessageReader<T>, S> readerFunction,
239+
Function<UnsupportedMediaTypeException, S> unsupportedError,
229240
Supplier<S> empty) {
230241

231242
if (VOID_TYPE.equals(elementType)) {

spring-webflux/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
5757
import org.springframework.util.MultiValueMap;
5858

59-
import static org.junit.Assert.*;
59+
import static org.junit.Assert.assertEquals;
60+
import static org.junit.Assert.assertNull;
61+
import static org.junit.Assert.assertTrue;
6062
import static org.springframework.http.codec.json.Jackson2CodecSupport.JSON_VIEW_HINT;
6163

6264
/**
@@ -169,6 +171,17 @@ public void toMonoWithHints() throws Exception {
169171
.verify();
170172
}
171173

174+
@Test // SPR-15758
175+
public void toMonoWithEmptyBodyAndNoContentType() throws Exception {
176+
BodyExtractor<Mono<Map<String, String>>, ReactiveHttpInputMessage> extractor =
177+
BodyExtractors.toMono(new ParameterizedTypeReference<Map<String, String>>() {});
178+
179+
MockServerHttpRequest request = MockServerHttpRequest.post("/").body(Flux.empty());
180+
Mono<Map<String, String>> result = extractor.extract(request, this.context);
181+
182+
StepVerifier.create(result).expectComplete().verify();
183+
}
184+
172185
@Test
173186
public void toFlux() throws Exception {
174187
BodyExtractor<Flux<String>, ReactiveHttpInputMessage> extractor = BodyExtractors.toFlux(String.class);

0 commit comments

Comments
 (0)