Add support for rendering single value in response
If the request is a single value, we already know, so if we also know that the function returned a single-valued type, then we can render the single value, instead of an array with a single item. See gh-36
This commit is contained in:
@@ -60,8 +60,9 @@ public class FunctionController {
|
|||||||
@PostMapping(path = "/**")
|
@PostMapping(path = "/**")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public ResponseEntity<Flux<?>> post(
|
public ResponseEntity<Flux<?>> post(
|
||||||
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.FunctionHandlerMapping.function") Function<Flux<?>, Flux<?>> function,
|
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.constants.WebRequestConstants.function") Function<Flux<?>, Flux<?>> function,
|
||||||
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.FunctionHandlerMapping.consumer") Consumer<Flux<?>> consumer,
|
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.constants.WebRequestConstants.consumer") Consumer<Flux<?>> consumer,
|
||||||
|
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.constants.WebRequestConstants.input_single") Boolean single,
|
||||||
@RequestBody FluxRequest<?> body) {
|
@RequestBody FluxRequest<?> body) {
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
Flux<?> result = (Flux<?>) function.apply(body.flux());
|
Flux<?> result = (Flux<?>) function.apply(body.flux());
|
||||||
@@ -84,9 +85,9 @@ public class FunctionController {
|
|||||||
@GetMapping(path = "/**")
|
@GetMapping(path = "/**")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object get(
|
public Object get(
|
||||||
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.FunctionHandlerMapping.function") Function<Flux<?>, Flux<?>> function,
|
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.constants.WebRequestConstants.function") Function<Flux<?>, Flux<?>> function,
|
||||||
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.FunctionHandlerMapping.supplier") Supplier<Flux<?>> supplier,
|
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.constants.WebRequestConstants.supplier") Supplier<Flux<?>> supplier,
|
||||||
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.FunctionHandlerMapping.argument") String argument) {
|
@RequestAttribute(required = false, name = "org.springframework.cloud.function.web.flux.constants.WebRequestConstants.argument") String argument) {
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
return value(function, argument);
|
return value(function, argument);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.cloud.function.context.FunctionInspector;
|
import org.springframework.cloud.function.context.FunctionInspector;
|
||||||
import org.springframework.cloud.function.registry.FunctionCatalog;
|
import org.springframework.cloud.function.registry.FunctionCatalog;
|
||||||
import org.springframework.cloud.function.web.flux.request.FluxHandlerMethodArgumentResolver;
|
import org.springframework.cloud.function.web.flux.constants.WebRequestConstants;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.servlet.HandlerMapping;
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
@@ -43,14 +43,6 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
|||||||
public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
||||||
implements InitializingBean {
|
implements InitializingBean {
|
||||||
|
|
||||||
public static final String FUNCTION = FunctionHandlerMapping.class.getName()
|
|
||||||
+ ".function";
|
|
||||||
public static final String CONSUMER = FunctionHandlerMapping.class.getName()
|
|
||||||
+ ".consumer";
|
|
||||||
public static final String SUPPLIER = FunctionHandlerMapping.class.getName()
|
|
||||||
+ ".supplier";
|
|
||||||
public static final String ARGUMENT = FunctionHandlerMapping.class.getName()
|
|
||||||
+ ".argument";
|
|
||||||
private final FunctionCatalog functions;
|
private final FunctionCatalog functions;
|
||||||
|
|
||||||
private final FunctionController controller;
|
private final FunctionController controller;
|
||||||
@@ -95,7 +87,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Found function for GET: " + path);
|
logger.debug("Found function for GET: " + path);
|
||||||
}
|
}
|
||||||
request.setAttribute(FluxHandlerMethodArgumentResolver.HANDLER, function);
|
request.setAttribute(WebRequestConstants.HANDLER, function);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
function = findFunctionForPost(request, path);
|
function = findFunctionForPost(request, path);
|
||||||
@@ -103,7 +95,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Found function for POST: " + path);
|
logger.debug("Found function for POST: " + path);
|
||||||
}
|
}
|
||||||
request.setAttribute(FluxHandlerMethodArgumentResolver.HANDLER, function);
|
request.setAttribute(WebRequestConstants.HANDLER, function);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -116,12 +108,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
|||||||
path = path.startsWith("/") ? path.substring(1) : path;
|
path = path.startsWith("/") ? path.substring(1) : path;
|
||||||
Consumer<Object> consumer = functions.lookupConsumer(path);
|
Consumer<Object> consumer = functions.lookupConsumer(path);
|
||||||
if (consumer != null) {
|
if (consumer != null) {
|
||||||
request.setAttribute(CONSUMER, consumer);
|
request.setAttribute(WebRequestConstants.CONSUMER, consumer);
|
||||||
return consumer;
|
return consumer;
|
||||||
}
|
}
|
||||||
Function<Object, Object> function = functions.lookupFunction(path);
|
Function<Object, Object> function = functions.lookupFunction(path);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
request.setAttribute(FUNCTION, function);
|
request.setAttribute(WebRequestConstants.FUNCTION, function);
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -134,7 +126,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
|||||||
path = path.startsWith("/") ? path.substring(1) : path;
|
path = path.startsWith("/") ? path.substring(1) : path;
|
||||||
Supplier<Object> supplier = functions.lookupSupplier(path);
|
Supplier<Object> supplier = functions.lookupSupplier(path);
|
||||||
if (supplier != null) {
|
if (supplier != null) {
|
||||||
request.setAttribute(SUPPLIER, supplier);
|
request.setAttribute(WebRequestConstants.SUPPLIER, supplier);
|
||||||
return supplier;
|
return supplier;
|
||||||
}
|
}
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
@@ -150,8 +142,8 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping
|
|||||||
: null;
|
: null;
|
||||||
Function<Object, Object> function = functions.lookupFunction(name);
|
Function<Object, Object> function = functions.lookupFunction(name);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
request.setAttribute(FUNCTION, function);
|
request.setAttribute(WebRequestConstants.FUNCTION, function);
|
||||||
request.setAttribute(ARGUMENT, value);
|
request.setAttribute(WebRequestConstants.ARGUMENT, value);
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.cloud.function.web.flux.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common storage for web request attribute names (in a separate package to avoid cycles).
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class WebRequestConstants {
|
||||||
|
|
||||||
|
public static final String FUNCTION = WebRequestConstants.class.getName()
|
||||||
|
+ ".function";
|
||||||
|
public static final String CONSUMER = WebRequestConstants.class.getName()
|
||||||
|
+ ".consumer";
|
||||||
|
public static final String SUPPLIER = WebRequestConstants.class.getName()
|
||||||
|
+ ".supplier";
|
||||||
|
public static final String ARGUMENT = WebRequestConstants.class.getName()
|
||||||
|
+ ".argument";
|
||||||
|
public static final String HANDLER = WebRequestConstants.class.getName() + ".handler";
|
||||||
|
public static final String INPUT_SINGLE = WebRequestConstants.class.getName()
|
||||||
|
+ ".input_single";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import org.apache.commons.logging.Log;
|
|||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.cloud.function.context.FunctionInspector;
|
import org.springframework.cloud.function.context.FunctionInspector;
|
||||||
|
import org.springframework.cloud.function.web.flux.constants.WebRequestConstants;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@@ -52,9 +53,6 @@ public class FluxHandlerMethodArgumentResolver
|
|||||||
private static Log logger = LogFactory
|
private static Log logger = LogFactory
|
||||||
.getLog(FluxHandlerMethodArgumentResolver.class);
|
.getLog(FluxHandlerMethodArgumentResolver.class);
|
||||||
|
|
||||||
public static final String HANDLER = FluxHandlerMethodArgumentResolver.class.getName()
|
|
||||||
+ ".HANDLER";
|
|
||||||
|
|
||||||
private final ObjectMapper mapper;
|
private final ObjectMapper mapper;
|
||||||
|
|
||||||
private FunctionInspector inspector;
|
private FunctionInspector inspector;
|
||||||
@@ -74,7 +72,8 @@ public class FluxHandlerMethodArgumentResolver
|
|||||||
public Object resolveArgument(MethodParameter parameter,
|
public Object resolveArgument(MethodParameter parameter,
|
||||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
|
ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
|
||||||
WebDataBinderFactory binderFactory) throws Exception {
|
WebDataBinderFactory binderFactory) throws Exception {
|
||||||
Object handler = webRequest.getAttribute(HANDLER, NativeWebRequest.SCOPE_REQUEST);
|
Object handler = webRequest.getAttribute(WebRequestConstants.HANDLER,
|
||||||
|
NativeWebRequest.SCOPE_REQUEST);
|
||||||
Class<?> type = inspector.getInputType(inspector.getName(handler));
|
Class<?> type = inspector.getInputType(inspector.getName(handler));
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
type = Object.class;
|
type = Object.class;
|
||||||
@@ -96,6 +95,7 @@ public class FluxHandlerMethodArgumentResolver
|
|||||||
.constructCollectionLikeType(ArrayList.class, type));
|
.constructCollectionLikeType(ArrayList.class, type));
|
||||||
}
|
}
|
||||||
catch (JsonMappingException e) {
|
catch (JsonMappingException e) {
|
||||||
|
nativeRequest.setAttribute(WebRequestConstants.INPUT_SINGLE, true);
|
||||||
body = Arrays.asList(
|
body = Arrays.asList(
|
||||||
mapper.readValue(nativeRequest.getContentAsByteArray(), type));
|
mapper.readValue(nativeRequest.getContentAsByteArray(), type));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.function.web.flux.response;
|
package org.springframework.cloud.function.web.flux.response;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -24,18 +25,21 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.el.stream.Optional;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
|
|
||||||
import org.springframework.cloud.function.context.FunctionInspector;
|
import org.springframework.cloud.function.context.FunctionInspector;
|
||||||
import org.springframework.cloud.function.web.flux.request.FluxHandlerMethodArgumentResolver;
|
import org.springframework.cloud.function.web.flux.constants.WebRequestConstants;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
|
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
|
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler;
|
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler;
|
||||||
|
|
||||||
@@ -50,19 +54,28 @@ import reactor.core.publisher.Mono;
|
|||||||
*/
|
*/
|
||||||
public class FluxReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
|
public class FluxReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
|
||||||
|
|
||||||
private static Log logger = LogFactory
|
private static Log logger = LogFactory.getLog(FluxReturnValueHandler.class);
|
||||||
.getLog(FluxReturnValueHandler.class);
|
|
||||||
|
|
||||||
private ResponseBodyEmitterReturnValueHandler delegate;
|
private ResponseBodyEmitterReturnValueHandler delegate;
|
||||||
|
private RequestResponseBodyMethodProcessor single;
|
||||||
private long timeout = 1000L;
|
private long timeout = 1000L;
|
||||||
private static final MediaType EVENT_STREAM = MediaType.valueOf("text/event-stream");
|
private static final MediaType EVENT_STREAM = MediaType.valueOf("text/event-stream");
|
||||||
|
|
||||||
private FunctionInspector inspector;
|
private FunctionInspector inspector;
|
||||||
|
|
||||||
|
private MethodParameter singleReturnType;
|
||||||
|
|
||||||
public FluxReturnValueHandler(FunctionInspector inspector,
|
public FluxReturnValueHandler(FunctionInspector inspector,
|
||||||
List<HttpMessageConverter<?>> messageConverters) {
|
List<HttpMessageConverter<?>> messageConverters) {
|
||||||
this.inspector = inspector;
|
this.inspector = inspector;
|
||||||
this.delegate = new ResponseBodyEmitterReturnValueHandler(messageConverters);
|
this.delegate = new ResponseBodyEmitterReturnValueHandler(messageConverters);
|
||||||
|
this.single = new RequestResponseBodyMethodProcessor(messageConverters);
|
||||||
|
Method method = ReflectionUtils.findMethod(getClass(), "singleValue");
|
||||||
|
singleReturnType = new MethodParameter(method, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseEntity<Object> singleValue() {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,24 +133,46 @@ public class FluxReturnValueHandler implements AsyncHandlerMethodReturnValueHand
|
|||||||
}
|
}
|
||||||
Publisher<?> flux = (Publisher<?>) adaptFrom;
|
Publisher<?> flux = (Publisher<?>) adaptFrom;
|
||||||
|
|
||||||
Object handler = webRequest.getAttribute(
|
Object handler = webRequest.getAttribute(WebRequestConstants.HANDLER,
|
||||||
FluxHandlerMethodArgumentResolver.HANDLER,
|
|
||||||
NativeWebRequest.SCOPE_REQUEST);
|
NativeWebRequest.SCOPE_REQUEST);
|
||||||
Class<?> type = inspector.getOutputType(inspector.getName(handler));
|
Class<?> type = inspector.getOutputType(inspector.getName(handler));
|
||||||
|
|
||||||
|
Boolean inputSingle = (Boolean) webRequest.getAttribute(
|
||||||
|
WebRequestConstants.INPUT_SINGLE, NativeWebRequest.SCOPE_REQUEST);
|
||||||
|
if (inputSingle!=null && inputSingle && isOutputSingle(handler)) {
|
||||||
|
single.handleReturnValue(Flux.from(flux).blockFirst(), singleReturnType,
|
||||||
|
mavContainer, webRequest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MediaType mediaType = null;
|
MediaType mediaType = null;
|
||||||
if (isPlainText(webRequest) && CharSequence.class.isAssignableFrom(type)) {
|
if (isPlainText(webRequest) && CharSequence.class.isAssignableFrom(type)) {
|
||||||
mediaType = MediaType.TEXT_PLAIN;
|
mediaType = MediaType.TEXT_PLAIN;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
mediaType = findMediaType(webRequest);
|
mediaType = findMediaType(webRequest);
|
||||||
}
|
}
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Handling return value " + type + " with media type: " + mediaType);
|
logger.debug(
|
||||||
|
"Handling return value " + type + " with media type: " + mediaType);
|
||||||
}
|
}
|
||||||
delegate.handleReturnValue(getEmitter(timeout, flux, mediaType), returnType,
|
delegate.handleReturnValue(getEmitter(timeout, flux, mediaType), returnType,
|
||||||
mavContainer, webRequest);
|
mavContainer, webRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOutputSingle(Object handler) {
|
||||||
|
String name = inspector.getName(handler);
|
||||||
|
Class<?> type = inspector.getOutputType(name);
|
||||||
|
Class<?> wrapper = inspector.getOutputWrapper(name);
|
||||||
|
if (wrapper==type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Mono.class.equals(wrapper) || Optional.class.equals(wrapper)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private MediaType findMediaType(NativeWebRequest webRequest) {
|
private MediaType findMediaType(NativeWebRequest webRequest) {
|
||||||
List<MediaType> accepts = Arrays.asList(MediaType.ALL);
|
List<MediaType> accepts = Arrays.asList(MediaType.ALL);
|
||||||
MediaType mediaType = null;
|
MediaType mediaType = null;
|
||||||
|
|||||||
@@ -283,6 +283,25 @@ public class RestApplicationTests {
|
|||||||
.isEqualTo("[{\"value\":\"FOO\"}]");
|
.isEqualTo("[{\"value\":\"FOO\"}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bareUppercaseFoos() throws Exception {
|
||||||
|
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||||
|
.post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class);
|
||||||
|
assertThat(result.getBody())
|
||||||
|
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bareUppercaseFoo() throws Exception {
|
||||||
|
// Single Foo can be parsed and returns a single value if the function is defined that way
|
||||||
|
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||||
|
.post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body("{\"value\":\"foo\"}"), String.class);
|
||||||
|
assertThat(result.getBody())
|
||||||
|
.isEqualTo("{\"value\":\"FOO\"}");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void bareUppercase() throws Exception {
|
public void bareUppercase() throws Exception {
|
||||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||||
@@ -382,6 +401,11 @@ public class RestApplicationTests {
|
|||||||
.map(value -> new Foo(value.getValue().trim().toUpperCase()));
|
.map(value -> new Foo(value.getValue().trim().toUpperCase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Function<Foo, Foo> bareUpFoos() {
|
||||||
|
return value -> new Foo(value.getValue().trim().toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Function<Flux<Integer>, Flux<String>> wrap() {
|
public Function<Flux<Integer>, Flux<String>> wrap() {
|
||||||
return flux -> flux.log().map(value -> ".." + value + "..");
|
return flux -> flux.log().map(value -> ".." + value + "..");
|
||||||
|
|||||||
Reference in New Issue
Block a user