diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java index 9ced229e50..acce1c5dd9 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java @@ -16,6 +16,7 @@ package org.springframework.web.reactive.function; +import java.util.Map; import java.util.function.Supplier; import java.util.stream.Stream; @@ -52,6 +53,11 @@ public interface BodyExtractor { * @return the stream of message readers */ Supplier>> messageReaders(); + + /** + * Return the map of hints to use to customize body extraction. + */ + Map hints(); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java index fd7a0f782b..ccb636379a 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java @@ -65,7 +65,7 @@ public abstract class BodyExtractors { Assert.notNull(elementType, "'elementType' must not be null"); return (request, context) -> readWithMessageReaders(request, context, elementType, - reader -> reader.readMono(elementType, request, Collections.emptyMap()), + reader -> reader.readMono(elementType, request, context.hints()), Mono::error); } @@ -90,7 +90,7 @@ public abstract class BodyExtractors { Assert.notNull(elementType, "'elementType' must not be null"); return (inputMessage, context) -> readWithMessageReaders(inputMessage, context, elementType, - reader -> reader.read(elementType, inputMessage, Collections.emptyMap()), + reader -> reader.read(elementType, inputMessage, context.hints()), Flux::error); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserter.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserter.java index 5cf02291dd..1e5f85e66e 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserter.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserter.java @@ -16,6 +16,7 @@ package org.springframework.web.reactive.function; +import java.util.Map; import java.util.function.Supplier; import java.util.stream.Stream; @@ -54,6 +55,11 @@ public interface BodyInserter { */ Supplier>> messageWriters(); + /** + * Return the map of hints to use for response body conversion. + */ + Map hints(); + } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserters.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserters.java index ee40d43919..15b9405709 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserters.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyInserters.java @@ -16,7 +16,6 @@ package org.springframework.web.reactive.function; -import java.util.Collections; import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -119,7 +118,7 @@ public abstract class BodyInserters { return (response, context) -> { HttpMessageWriter messageWriter = resourceHttpMessageWriter(context); return messageWriter.write(Mono.just(resource), RESOURCE_TYPE, null, - response, Collections.emptyMap()); + response, context.hints()); }; } @@ -146,7 +145,7 @@ public abstract class BodyInserters { return (response, context) -> { HttpMessageWriter> messageWriter = sseMessageWriter(context); return messageWriter.write(eventsPublisher, SERVER_SIDE_EVENT_TYPE, - MediaType.TEXT_EVENT_STREAM, response, Collections.emptyMap()); + MediaType.TEXT_EVENT_STREAM, response, context.hints()); }; } @@ -186,7 +185,7 @@ public abstract class BodyInserters { return (outputMessage, context) -> { HttpMessageWriter messageWriter = sseMessageWriter(context); return messageWriter.write(eventsPublisher, eventType, - MediaType.TEXT_EVENT_STREAM, outputMessage, Collections.emptyMap()); + MediaType.TEXT_EVENT_STREAM, outputMessage, context.hints()); }; } @@ -227,8 +226,7 @@ public abstract class BodyInserters { .findFirst() .map(BodyInserters::cast) .map(messageWriter -> messageWriter - .write(body, bodyType, contentType, m, Collections - .emptyMap())) + .write(body, bodyType, contentType, m, context.hints())) .orElseGet(() -> { List supportedMediaTypes = messageWriters.get() .flatMap(reader -> reader.getWritableMediaTypes().stream()) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestBuilder.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestBuilder.java index 86adb1ae1a..0af5c1b2c2 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestBuilder.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientRequestBuilder.java @@ -22,6 +22,8 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; +import java.util.Collections; +import java.util.Map; import java.util.function.Supplier; import java.util.stream.Stream; @@ -220,6 +222,11 @@ class DefaultClientRequestBuilder implements ClientRequest.BodyBuilder { public Supplier>> messageWriters() { return strategies.messageWriters(); } + + @Override + public Map hints() { + return Collections.emptyMap(); + } }); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java index 4b545996b5..25f2c1c38d 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java @@ -18,6 +18,7 @@ package org.springframework.web.reactive.function.client; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.OptionalLong; import java.util.function.Function; @@ -74,6 +75,10 @@ class DefaultClientResponse implements ClientResponse { public Supplier>> messageReaders() { return strategies.messageReaders(); } + @Override + public Map hints() { + return Collections.emptyMap(); + } }); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java index 4aa8ff97f7..8229082a1b 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java @@ -78,6 +78,11 @@ class DefaultServerRequest implements ServerRequest { @Override public T body(BodyExtractor extractor) { + return body(extractor, Collections.emptyMap()); + } + + @Override + public T body(BodyExtractor extractor, Map hints) { Assert.notNull(extractor, "'extractor' must not be null"); return extractor.extract(request(), new BodyExtractor.Context() { @@ -85,6 +90,10 @@ class DefaultServerRequest implements ServerRequest { public Supplier>> messageReaders() { return DefaultServerRequest.this.strategies.messageReaders(); } + @Override + public Map hints() { + return hints; + } }); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java index b49fcabf2d..820cbe2e99 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java @@ -22,6 +22,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Locale; @@ -62,6 +63,8 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { private final HttpHeaders headers = new HttpHeaders(); + private final Map hints = new HashMap<>(); + public DefaultServerResponseBuilder(HttpStatus statusCode) { this.statusCode = statusCode; @@ -122,6 +125,12 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { return this; } + @Override + public ServerResponse.BodyBuilder hint(String key, Object value) { + this.hints.put(key, value); + return this; + } + @Override public ServerResponse.BodyBuilder lastModified(ZonedDateTime lastModified) { ZonedDateTime gmt = lastModified.withZoneSameInstant(ZoneId.of("GMT")); @@ -182,7 +191,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { public Mono body(BodyInserter inserter) { Assert.notNull(inserter, "'inserter' must not be null"); return Mono - .just(new BodyInserterServerResponse(this.statusCode, this.headers, inserter)); + .just(new BodyInserterServerResponse(this.statusCode, this.headers, inserter, this.hints)); } @Override @@ -276,11 +285,14 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { private final BodyInserter inserter; + private final Map hints; + public BodyInserterServerResponse(HttpStatus statusCode, HttpHeaders headers, - BodyInserter inserter) { + BodyInserter inserter, Map hints) { super(statusCode, headers); this.inserter = inserter; + this.hints = hints; } @Override @@ -292,6 +304,10 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { public Supplier>> messageWriters() { return strategies.messageWriters(); } + @Override + public Map hints() { + return hints; + } }); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java index 457f6ad217..4c0928fb3c 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java @@ -323,6 +323,11 @@ public abstract class RequestPredicates { return this.request.body(extractor); } + @Override + public T body(BodyExtractor extractor, Map hints) { + return this.request.body(extractor, hints); + } + @Override public Mono bodyToMono(Class elementClass) { return this.request.bodyToMono(elementClass); diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java index 67555627cf..8355cdbb0c 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java @@ -31,6 +31,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; import org.springframework.http.MediaType; +import org.springframework.http.codec.json.AbstractJackson2Codec; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.reactive.function.BodyExtractor; @@ -40,6 +41,7 @@ import org.springframework.web.reactive.function.BodyExtractor; * {@link #body(BodyExtractor)} respectively. * * @author Arjen Poutsma + * @author Sebastien Deleuze * @since 5.0 */ public interface ServerRequest { @@ -71,9 +73,20 @@ public interface ServerRequest { * @param extractor the {@code BodyExtractor} that reads from the request * @param the type of the body returned * @return the extracted body + * @see #body(BodyExtractor, Map) */ T body(BodyExtractor extractor); + /** + * Extract the body with the given {@code BodyExtractor} and hints. + * @param extractor the {@code BodyExtractor} that reads from the request + * @param hints the map of hints like {@link AbstractJackson2Codec#JSON_VIEW_HINT} + * to use to customize body extraction + * @param the type of the body returned + * @return the extracted body + */ + T body(BodyExtractor extractor, Map hints); + /** * Extract the body to a {@code Mono}. * @param elementClass the class of element in the {@code Mono} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java index 874556b2a9..9a54c8653e 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/ServerResponse.java @@ -31,6 +31,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.codec.json.AbstractJackson2Codec; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; import org.springframework.web.reactive.function.BodyInserter; @@ -42,6 +43,7 @@ import org.springframework.web.server.ServerWebExchange; * {@linkplain HandlerFunction handler function} or {@linkplain HandlerFilterFunction filter function}. * * @author Arjen Poutsma + * @author Sebastien Deleuze * @since 5.0 */ public interface ServerResponse { @@ -312,6 +314,12 @@ public interface ServerResponse { */ BodyBuilder contentType(MediaType contentType); + /** + * Add a serialization hint like {@link AbstractJackson2Codec#JSON_VIEW_HINT} to + * customize how the body will be serialized. + */ + BodyBuilder hint(String key, Object value); + /** * Set the body of the response to the given {@code Publisher} and return it. This * convenience method combines {@link #body(BodyInserter)} and diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java index eef7f39b56..b907279b35 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java @@ -91,6 +91,11 @@ public class ServerRequestWrapper implements ServerRequest { return this.request.body(extractor); } + @Override + public T body(BodyExtractor extractor, Map hints) { + return this.request.body(extractor, hints); + } + @Override public Mono bodyToMono(Class elementClass) { return this.request.bodyToMono(elementClass); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java index 7e55c751cb..1ade037330 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java @@ -19,10 +19,14 @@ package org.springframework.web.reactive.function; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Supplier; import java.util.stream.Stream; +import com.fasterxml.jackson.annotation.JsonView; import org.junit.Before; import org.junit.Test; import reactor.core.publisher.Flux; @@ -43,13 +47,20 @@ import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.xml.Jaxb2XmlDecoder; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; +import static org.springframework.http.codec.json.AbstractJackson2Codec.JSON_VIEW_HINT; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + /** * @author Arjen Poutsma + * @author Sebastien Deleuze */ public class BodyExtractorsTests { private BodyExtractor.Context context; + private Map hints; + @Before public void createContext() { final List> messageReaders = new ArrayList<>(); @@ -63,8 +74,12 @@ public class BodyExtractorsTests { public Supplier>> messageReaders() { return messageReaders::stream; } + @Override + public Map hints() { + return hints; + } }; - + this.hints = new HashMap(); } @Test @@ -87,6 +102,31 @@ public class BodyExtractorsTests { .verify(); } + @Test + public void toMonoWithHints() throws Exception { + BodyExtractor, ReactiveHttpInputMessage> extractor = BodyExtractors.toMono(User.class); + this.hints.put(JSON_VIEW_HINT, SafeToDeserialize.class); + + DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); + DefaultDataBuffer dataBuffer = + factory.wrap(ByteBuffer.wrap("{\"username\":\"foo\",\"password\":\"bar\"}".getBytes(StandardCharsets.UTF_8))); + Flux body = Flux.just(dataBuffer); + + MockServerHttpRequest request = new MockServerHttpRequest(); + request.getHeaders().setContentType(MediaType.APPLICATION_JSON); + request.setBody(body); + + Mono result = extractor.extract(request, this.context); + + StepVerifier.create(result) + .consumeNextWith(user -> { + assertEquals("foo", user.getUsername()); + assertNull(user.getPassword()); + }) + .expectComplete() + .verify(); + } + @Test public void toFlux() throws Exception { BodyExtractor, ReactiveHttpInputMessage> extractor = BodyExtractors.toFlux(String.class); @@ -107,6 +147,35 @@ public class BodyExtractorsTests { .verify(); } + @Test + public void toFluxWithHints() throws Exception { + BodyExtractor, ReactiveHttpInputMessage> extractor = BodyExtractors.toFlux(User.class); + this.hints.put(JSON_VIEW_HINT, SafeToDeserialize.class); + + DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); + DefaultDataBuffer dataBuffer = + factory.wrap(ByteBuffer.wrap("[{\"username\":\"foo\",\"password\":\"bar\"},{\"username\":\"bar\",\"password\":\"baz\"}]".getBytes(StandardCharsets.UTF_8))); + Flux body = Flux.just(dataBuffer); + + MockServerHttpRequest request = new MockServerHttpRequest(); + request.getHeaders().setContentType(MediaType.APPLICATION_JSON); + request.setBody(body); + + Flux result = extractor.extract(request, this.context); + + StepVerifier.create(result) + .consumeNextWith(user -> { + assertEquals("foo", user.getUsername()); + assertNull(user.getPassword()); + }) + .consumeNextWith(user -> { + assertEquals("bar", user.getUsername()); + assertNull(user.getPassword()); + }) + .expectComplete() + .verify(); + } + @Test public void toFluxUnacceptable() throws Exception { BodyExtractor, ReactiveHttpInputMessage> extractor = BodyExtractors.toFlux(String.class); @@ -125,6 +194,10 @@ public class BodyExtractorsTests { public Supplier>> messageReaders() { return Stream::empty; } + @Override + public Map hints() { + return Collections.emptyMap(); + } }; Flux result = extractor.extract(request, emptyContext); @@ -153,4 +226,39 @@ public class BodyExtractorsTests { .verify(); } + + interface SafeToDeserialize {} + + private static class User { + + @JsonView(SafeToDeserialize.class) + private String username; + + private String password; + + public User() { + } + + public User(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + } + } \ No newline at end of file diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyInsertersTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyInsertersTests.java index a7bff55b38..62db2d422f 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyInsertersTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyInsertersTests.java @@ -21,10 +21,13 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Supplier; import java.util.stream.Stream; +import com.fasterxml.jackson.annotation.JsonView; import org.junit.Before; import org.junit.Test; import reactor.core.publisher.Flux; @@ -51,14 +54,18 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertArrayEquals; +import static org.springframework.http.codec.json.AbstractJackson2Codec.JSON_VIEW_HINT; /** * @author Arjen Poutsma + * @author Sebastien Deleuze */ public class BodyInsertersTests { private BodyInserter.Context context; + private Map hints; + @Before public void createContext() { final List> messageWriters = new ArrayList<>(); @@ -71,19 +78,21 @@ public class BodyInsertersTests { messageWriters .add(new ServerSentEventHttpMessageWriter(Collections.singletonList(jsonEncoder))); - this.context = new BodyInserter.Context() { @Override public Supplier>> messageWriters() { return messageWriters::stream; } + @Override + public Map hints() { + return hints; + } }; - + this.hints = new HashMap(); } - @Test - public void ofObject() throws Exception { + public void ofString() throws Exception { String body = "foo"; BodyInserter inserter = BodyInserters.fromObject(body); @@ -99,6 +108,35 @@ public class BodyInsertersTests { .verify(); } + @Test + public void ofObject() throws Exception { + User body = new User("foo", "bar"); + BodyInserter inserter = BodyInserters.fromObject(body); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = inserter.insert(response, this.context); + StepVerifier.create(result).expectComplete().verify(); + + StepVerifier.create(response.getBodyAsString()) + .expectNext("{\"username\":\"foo\",\"password\":\"bar\"}") + .expectComplete() + .verify(); + } + + @Test + public void ofObjectWithHints() throws Exception { + User body = new User("foo", "bar"); + BodyInserter inserter = BodyInserters.fromObject(body); + this.hints.put(JSON_VIEW_HINT, SafeToSerialize.class); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = inserter.insert(response, this.context); + StepVerifier.create(result).expectComplete().verify(); + + StepVerifier.create(response.getBodyAsString()) + .expectNext("{\"username\":\"foo\"}") + .expectComplete() + .verify(); + } + @Test public void ofPublisher() throws Exception { Flux body = Flux.just("foo"); @@ -180,4 +218,39 @@ public class BodyInsertersTests { } + interface SafeToSerialize {} + + private static class User { + + @JsonView(SafeToSerialize.class) + private String username; + + private String password; + + public User() { + } + + public User(String username, String password) { + this.username = username; + this.password = password; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + } + + } \ No newline at end of file diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java index a886dd51f5..87b73b490e 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/server/MockServerRequest.java @@ -99,6 +99,11 @@ public class MockServerRequest implements ServerRequest { return (S) this.body; } + @Override + public S body(BodyExtractor extractor, Map hints) { + return (S) this.body; + } + @Override @SuppressWarnings("unchecked") public Mono bodyToMono(Class elementClass) { diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java index 142e6b0b6a..a7ca7be6fd 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java @@ -50,7 +50,7 @@ import org.springframework.util.MimeTypeUtils; public class ServerSentEventHttpMessageWriter implements HttpMessageWriter { /** - * Server-Sent Events hint expecting a {@link Boolean} value which when set to true + * Server-Sent Events hint key expecting a {@link Boolean} value which when set to true * will adapt the content in order to comply with Server-Sent Events recommendation. * For example, it will append "data:" after each line break with data encoders * supporting it. diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Codec.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Codec.java index 6d120a907a..aa1b3705bb 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Codec.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Codec.java @@ -38,6 +38,11 @@ import org.springframework.util.MimeType; */ public class AbstractJackson2Codec { + /** + * Hint key to use with a {@link Class} value specifying the JSON View to use to serialize + * or deserialize an object. + * @see Jackson JSON Views + */ public static final String JSON_VIEW_HINT = AbstractJackson2Codec.class.getName() + ".jsonView"; protected static final List JSON_MIME_TYPES = Arrays.asList(