Java Code Examples for org.springframework.core.ReactiveAdapter#isMultiValue()

The following examples show how to use org.springframework.core.ReactiveAdapter#isMultiValue() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: PayloadMethodArgumentResolver.java    From spring-analysis-note with MIT License 4 votes vote down vote up
private Mono<Object> decodeContent(MethodParameter parameter, Message<?> message,
		boolean isContentRequired, Flux<DataBuffer> content, MimeType mimeType) {

	ResolvableType targetType = ResolvableType.forMethodParameter(parameter);
	Class<?> resolvedType = targetType.resolve();
	ReactiveAdapter adapter = (resolvedType != null ? getAdapterRegistry().getAdapter(resolvedType) : null);
	ResolvableType elementType = (adapter != null ? targetType.getGeneric() : targetType);
	isContentRequired = isContentRequired || (adapter != null && !adapter.supportsEmpty());
	Consumer<Object> validator = getValidator(message, parameter);

	Map<String, Object> hints = Collections.emptyMap();

	for (Decoder<?> decoder : this.decoders) {
		if (decoder.canDecode(elementType, mimeType)) {
			if (adapter != null && adapter.isMultiValue()) {
				Flux<?> flux = content
						.map(buffer -> decoder.decode(buffer, elementType, mimeType, hints))
						.onErrorResume(ex -> Flux.error(handleReadError(parameter, message, ex)));
				if (isContentRequired) {
					flux = flux.switchIfEmpty(Flux.error(() -> handleMissingBody(parameter, message)));
				}
				if (validator != null) {
					flux = flux.doOnNext(validator);
				}
				return Mono.just(adapter.fromPublisher(flux));
			}
			else {
				// Single-value (with or without reactive type wrapper)
				Mono<?> mono = content.next()
						.map(buffer -> decoder.decode(buffer, elementType, mimeType, hints))
						.onErrorResume(ex -> Mono.error(handleReadError(parameter, message, ex)));
				if (isContentRequired) {
					mono = mono.switchIfEmpty(Mono.error(() -> handleMissingBody(parameter, message)));
				}
				if (validator != null) {
					mono = mono.doOnNext(validator);
				}
				return (adapter != null ? Mono.just(adapter.fromPublisher(mono)) : Mono.from(mono));
			}
		}
	}

	return Mono.error(new MethodArgumentResolutionException(
			message, parameter, "Cannot decode to [" + targetType + "]" + message));
}
 
Example 2
Source File: ReactiveReturnValueHandler.java    From spring-analysis-note with MIT License 4 votes vote down vote up
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
	ReactiveAdapter adapter = this.adapterRegistry.getAdapter(returnType.getParameterType(), returnValue);
	return (adapter != null && !adapter.isMultiValue() && !adapter.isNoValue());
}
 
Example 3
Source File: AbstractView.java    From spring-analysis-note with MIT License 4 votes vote down vote up
/**
 * By default, resolve async attributes supported by the
 * {@link ReactiveAdapterRegistry} to their blocking counterparts.
 * <p>View implementations capable of taking advantage of reactive types
 * can override this method if needed.
 * @return {@code Mono} for the completion of async attributes resolution
 */
protected Mono<Void> resolveAsyncAttributes(Map<String, Object> model) {
	List<String> names = new ArrayList<>();
	List<Mono<?>> valueMonos = new ArrayList<>();

	for (Map.Entry<String, ?> entry : model.entrySet()) {
		Object value =  entry.getValue();
		if (value == null) {
			continue;
		}
		ReactiveAdapter adapter = this.adapterRegistry.getAdapter(null, value);
		if (adapter != null) {
			names.add(entry.getKey());
			if (adapter.isMultiValue()) {
				Flux<Object> fluxValue = Flux.from(adapter.toPublisher(value));
				valueMonos.add(fluxValue.collectList().defaultIfEmpty(Collections.emptyList()));
			}
			else {
				Mono<Object> monoValue = Mono.from(adapter.toPublisher(value));
				valueMonos.add(monoValue.defaultIfEmpty(NO_VALUE));
			}
		}
	}

	if (names.isEmpty()) {
		return Mono.empty();
	}

	return Mono.zip(valueMonos,
			values -> {
				for (int i=0; i < values.length; i++) {
					if (values[i] != NO_VALUE) {
						model.put(names.get(i), values[i]);
					}
					else {
						model.remove(names.get(i));
					}
				}
				return NO_VALUE;
			})
			.then();
}
 
Example 4
Source File: ViewResolutionResultHandler.java    From spring-analysis-note with MIT License 4 votes vote down vote up
@Override
@SuppressWarnings("unchecked")
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
	Mono<Object> valueMono;
	ResolvableType valueType;
	ReactiveAdapter adapter = getAdapter(result);

	if (adapter != null) {
		if (adapter.isMultiValue()) {
			throw new IllegalArgumentException(
					"Multi-value reactive types not supported in view resolution: " + result.getReturnType());
		}

		valueMono = (result.getReturnValue() != null ?
				Mono.from(adapter.toPublisher(result.getReturnValue())) : Mono.empty());

		valueType = (adapter.isNoValue() ? ResolvableType.forClass(Void.class) :
				result.getReturnType().getGeneric());
	}
	else {
		valueMono = Mono.justOrEmpty(result.getReturnValue());
		valueType = result.getReturnType();
	}

	return valueMono
			.switchIfEmpty(exchange.isNotModified() ? Mono.empty() : NO_VALUE_MONO)
			.flatMap(returnValue -> {

				Mono<List<View>> viewsMono;
				Model model = result.getModel();
				MethodParameter parameter = result.getReturnTypeSource();
				Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext());

				Class<?> clazz = valueType.toClass();
				if (clazz == Object.class) {
					clazz = returnValue.getClass();
				}

				if (returnValue == NO_VALUE || clazz == void.class || clazz == Void.class) {
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}
				else if (CharSequence.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
					viewsMono = resolveViews(returnValue.toString(), locale);
				}
				else if (Rendering.class.isAssignableFrom(clazz)) {
					Rendering render = (Rendering) returnValue;
					HttpStatus status = render.status();
					if (status != null) {
						exchange.getResponse().setStatusCode(status);
					}
					exchange.getResponse().getHeaders().putAll(render.headers());
					model.addAllAttributes(render.modelAttributes());
					Object view = render.view();
					if (view == null) {
						view = getDefaultViewName(exchange);
					}
					viewsMono = (view instanceof String ? resolveViews((String) view, locale) :
							Mono.just(Collections.singletonList((View) view)));
				}
				else if (Model.class.isAssignableFrom(clazz)) {
					model.addAllAttributes(((Model) returnValue).asMap());
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}
				else if (Map.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
					model.addAllAttributes((Map<String, ?>) returnValue);
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}
				else if (View.class.isAssignableFrom(clazz)) {
					viewsMono = Mono.just(Collections.singletonList((View) returnValue));
				}
				else {
					String name = getNameForReturnValue(parameter);
					model.addAttribute(name, returnValue);
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}

				updateBindingContext(result.getBindingContext(), exchange);

				return viewsMono.flatMap(views -> render(views, model.asMap(), exchange));
			});
}
 
Example 5
Source File: AbstractMessageReaderArgumentResolver.java    From spring-analysis-note with MIT License 4 votes vote down vote up
/**
 * Read the body from a method argument with {@link HttpMessageReader}.
 * @param bodyParam represents the element type for the body
 * @param actualParam the actual method argument type; possibly different
 * from {@code bodyParam}, e.g. for an {@code HttpEntity} argument
 * @param isBodyRequired true if the body is required
 * @param bindingContext the binding context to use
 * @param exchange the current exchange
 * @return a Mono with the value to use for the method argument
 * @since 5.0.2
 */
protected Mono<Object> readBody(MethodParameter bodyParam, @Nullable MethodParameter actualParam,
		boolean isBodyRequired, BindingContext bindingContext, ServerWebExchange exchange) {

	ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParam);
	ResolvableType actualType = (actualParam != null ? ResolvableType.forMethodParameter(actualParam) : bodyType);
	Class<?> resolvedType = bodyType.resolve();
	ReactiveAdapter adapter = (resolvedType != null ? getAdapterRegistry().getAdapter(resolvedType) : null);
	ResolvableType elementType = (adapter != null ? bodyType.getGeneric() : bodyType);
	isBodyRequired = isBodyRequired || (adapter != null && !adapter.supportsEmpty());

	ServerHttpRequest request = exchange.getRequest();
	ServerHttpResponse response = exchange.getResponse();

	MediaType contentType = request.getHeaders().getContentType();
	MediaType mediaType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
	Object[] hints = extractValidationHints(bodyParam);

	if (mediaType.isCompatibleWith(MediaType.APPLICATION_FORM_URLENCODED)) {
		return Mono.error(new IllegalStateException(
				"In a WebFlux application, form data is accessed via ServerWebExchange.getFormData()."));
	}

	if (logger.isDebugEnabled()) {
		logger.debug(exchange.getLogPrefix() + (contentType != null ?
				"Content-Type:" + contentType :
				"No Content-Type, using " + MediaType.APPLICATION_OCTET_STREAM));
	}

	for (HttpMessageReader<?> reader : getMessageReaders()) {
		if (reader.canRead(elementType, mediaType)) {
			Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix());
			if (adapter != null && adapter.isMultiValue()) {
				if (logger.isDebugEnabled()) {
					logger.debug(exchange.getLogPrefix() + "0..N [" + elementType + "]");
				}
				Flux<?> flux = reader.read(actualType, elementType, request, response, readHints);
				flux = flux.onErrorResume(ex -> Flux.error(handleReadError(bodyParam, ex)));
				if (isBodyRequired) {
					flux = flux.switchIfEmpty(Flux.error(() -> handleMissingBody(bodyParam)));
				}
				if (hints != null) {
					flux = flux.doOnNext(target ->
							validate(target, hints, bodyParam, bindingContext, exchange));
				}
				return Mono.just(adapter.fromPublisher(flux));
			}
			else {
				// Single-value (with or without reactive type wrapper)
				if (logger.isDebugEnabled()) {
					logger.debug(exchange.getLogPrefix() + "0..1 [" + elementType + "]");
				}
				Mono<?> mono = reader.readMono(actualType, elementType, request, response, readHints);
				mono = mono.onErrorResume(ex -> Mono.error(handleReadError(bodyParam, ex)));
				if (isBodyRequired) {
					mono = mono.switchIfEmpty(Mono.error(() -> handleMissingBody(bodyParam)));
				}
				if (hints != null) {
					mono = mono.doOnNext(target ->
							validate(target, hints, bodyParam, bindingContext, exchange));
				}
				return (adapter != null ? Mono.just(adapter.fromPublisher(mono)) : Mono.from(mono));
			}
		}
	}

	// No compatible reader but body may be empty..

	HttpMethod method = request.getMethod();
	if (contentType == null && method != null && SUPPORTED_METHODS.contains(method)) {
		Flux<DataBuffer> body = request.getBody().doOnNext(buffer -> {
			DataBufferUtils.release(buffer);
			// Body not empty, back to 415..
			throw new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes, elementType);
		});
		if (isBodyRequired) {
			body = body.switchIfEmpty(Mono.error(() -> handleMissingBody(bodyParam)));
		}
		return (adapter != null ? Mono.just(adapter.fromPublisher(body)) : Mono.from(body));
	}

	return Mono.error(new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes, elementType));
}
 
Example 6
Source File: ReactiveTypeHandler.java    From spring-analysis-note with MIT License 4 votes vote down vote up
DeferredResultSubscriber(DeferredResult<Object> result, ReactiveAdapter adapter, ResolvableType elementType) {
	this.result = result;
	this.multiValueSource = adapter.isMultiValue();
	this.values = new CollectedValuesList(elementType);
}
 
Example 7
Source File: ReactiveReturnValueHandler.java    From java-technology-stack with MIT License 4 votes vote down vote up
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
	ReactiveAdapter adapter = this.adapterRegistry.getAdapter(returnType.getParameterType(), returnValue);
	return (adapter != null && !adapter.isMultiValue() && !adapter.isNoValue());
}
 
Example 8
Source File: AbstractView.java    From java-technology-stack with MIT License 4 votes vote down vote up
/**
 * By default, resolve async attributes supported by the
 * {@link ReactiveAdapterRegistry} to their blocking counterparts.
 * <p>View implementations capable of taking advantage of reactive types
 * can override this method if needed.
 * @return {@code Mono} for the completion of async attributes resolution
 */
protected Mono<Void> resolveAsyncAttributes(Map<String, Object> model) {
	List<String> names = new ArrayList<>();
	List<Mono<?>> valueMonos = new ArrayList<>();

	for (Map.Entry<String, ?> entry : model.entrySet()) {
		Object value =  entry.getValue();
		if (value == null) {
			continue;
		}
		ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(null, value);
		if (adapter != null) {
			names.add(entry.getKey());
			if (adapter.isMultiValue()) {
				Flux<Object> fluxValue = Flux.from(adapter.toPublisher(value));
				valueMonos.add(fluxValue.collectList().defaultIfEmpty(Collections.emptyList()));
			}
			else {
				Mono<Object> monoValue = Mono.from(adapter.toPublisher(value));
				valueMonos.add(monoValue.defaultIfEmpty(NO_VALUE));
			}
		}
	}

	if (names.isEmpty()) {
		return Mono.empty();
	}

	return Mono.zip(valueMonos,
			values -> {
				for (int i=0; i < values.length; i++) {
					if (values[i] != NO_VALUE) {
						model.put(names.get(i), values[i]);
					}
					else {
						model.remove(names.get(i));
					}
				}
				return NO_VALUE;
			})
			.then();
}
 
Example 9
Source File: ViewResolutionResultHandler.java    From java-technology-stack with MIT License 4 votes vote down vote up
@Override
@SuppressWarnings("unchecked")
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
	Mono<Object> valueMono;
	ResolvableType valueType;
	ReactiveAdapter adapter = getAdapter(result);

	if (adapter != null) {
		if (adapter.isMultiValue()) {
			throw new IllegalArgumentException(
					"Multi-value reactive types not supported in view resolution: " + result.getReturnType());
		}

		valueMono = (result.getReturnValue() != null ?
				Mono.from(adapter.toPublisher(result.getReturnValue())) : Mono.empty());

		valueType = (adapter.isNoValue() ? ResolvableType.forClass(Void.class) :
				result.getReturnType().getGeneric());
	}
	else {
		valueMono = Mono.justOrEmpty(result.getReturnValue());
		valueType = result.getReturnType();
	}

	return valueMono
			.switchIfEmpty(exchange.isNotModified() ? Mono.empty() : NO_VALUE_MONO)
			.flatMap(returnValue -> {

				Mono<List<View>> viewsMono;
				Model model = result.getModel();
				MethodParameter parameter = result.getReturnTypeSource();
				Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext());

				Class<?> clazz = valueType.toClass();
				if (clazz == Object.class) {
					clazz = returnValue.getClass();
				}

				if (returnValue == NO_VALUE || clazz == void.class || clazz == Void.class) {
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}
				else if (CharSequence.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
					viewsMono = resolveViews(returnValue.toString(), locale);
				}
				else if (Rendering.class.isAssignableFrom(clazz)) {
					Rendering render = (Rendering) returnValue;
					HttpStatus status = render.status();
					if (status != null) {
						exchange.getResponse().setStatusCode(status);
					}
					exchange.getResponse().getHeaders().putAll(render.headers());
					model.addAllAttributes(render.modelAttributes());
					Object view = render.view();
					if (view == null) {
						view = getDefaultViewName(exchange);
					}
					viewsMono = (view instanceof String ? resolveViews((String) view, locale) :
							Mono.just(Collections.singletonList((View) view)));
				}
				else if (Model.class.isAssignableFrom(clazz)) {
					model.addAllAttributes(((Model) returnValue).asMap());
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}
				else if (Map.class.isAssignableFrom(clazz) && !hasModelAnnotation(parameter)) {
					model.addAllAttributes((Map<String, ?>) returnValue);
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}
				else if (View.class.isAssignableFrom(clazz)) {
					viewsMono = Mono.just(Collections.singletonList((View) returnValue));
				}
				else {
					String name = getNameForReturnValue(parameter);
					model.addAttribute(name, returnValue);
					viewsMono = resolveViews(getDefaultViewName(exchange), locale);
				}

				updateBindingContext(result.getBindingContext(), exchange);

				return viewsMono.flatMap(views -> render(views, model.asMap(), exchange));
			});
}
 
Example 10
Source File: AbstractMessageReaderArgumentResolver.java    From java-technology-stack with MIT License 4 votes vote down vote up
/**
 * Read the body from a method argument with {@link HttpMessageReader}.
 * @param bodyParam represents the element type for the body
 * @param actualParam the actual method argument type; possibly different
 * from {@code bodyParam}, e.g. for an {@code HttpEntity} argument
 * @param isBodyRequired true if the body is required
 * @param bindingContext the binding context to use
 * @param exchange the current exchange
 * @return a Mono with the value to use for the method argument
 * @since 5.0.2
 */
protected Mono<Object> readBody(MethodParameter bodyParam, @Nullable MethodParameter actualParam,
		boolean isBodyRequired, BindingContext bindingContext, ServerWebExchange exchange) {

	ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParam);
	ResolvableType actualType = (actualParam != null ? ResolvableType.forMethodParameter(actualParam) : bodyType);
	Class<?> resolvedType = bodyType.resolve();
	ReactiveAdapter adapter = (resolvedType != null ? getAdapterRegistry().getAdapter(resolvedType) : null);
	ResolvableType elementType = (adapter != null ? bodyType.getGeneric() : bodyType);
	isBodyRequired = isBodyRequired || (adapter != null && !adapter.supportsEmpty());

	ServerHttpRequest request = exchange.getRequest();
	ServerHttpResponse response = exchange.getResponse();

	MediaType contentType = request.getHeaders().getContentType();
	MediaType mediaType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
	Object[] hints = extractValidationHints(bodyParam);

	if (logger.isDebugEnabled()) {
		logger.debug(exchange.getLogPrefix() + (contentType != null ?
				"Content-Type:" + contentType :
				"No Content-Type, using " + MediaType.APPLICATION_OCTET_STREAM));
	}

	for (HttpMessageReader<?> reader : getMessageReaders()) {
		if (reader.canRead(elementType, mediaType)) {
			Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix());
			if (adapter != null && adapter.isMultiValue()) {
				if (logger.isDebugEnabled()) {
					logger.debug(exchange.getLogPrefix() + "0..N [" + elementType + "]");
				}
				Flux<?> flux = reader.read(actualType, elementType, request, response, readHints);
				flux = flux.onErrorResume(ex -> Flux.error(handleReadError(bodyParam, ex)));
				if (isBodyRequired) {
					flux = flux.switchIfEmpty(Flux.error(() -> handleMissingBody(bodyParam)));
				}
				if (hints != null) {
					flux = flux.doOnNext(target ->
							validate(target, hints, bodyParam, bindingContext, exchange));
				}
				return Mono.just(adapter.fromPublisher(flux));
			}
			else {
				// Single-value (with or without reactive type wrapper)
				if (logger.isDebugEnabled()) {
					logger.debug(exchange.getLogPrefix() + "0..1 [" + elementType + "]");
				}
				Mono<?> mono = reader.readMono(actualType, elementType, request, response, readHints);
				mono = mono.onErrorResume(ex -> Mono.error(handleReadError(bodyParam, ex)));
				if (isBodyRequired) {
					mono = mono.switchIfEmpty(Mono.error(() -> handleMissingBody(bodyParam)));
				}
				if (hints != null) {
					mono = mono.doOnNext(target ->
							validate(target, hints, bodyParam, bindingContext, exchange));
				}
				return (adapter != null ? Mono.just(adapter.fromPublisher(mono)) : Mono.from(mono));
			}
		}
	}

	// No compatible reader but body may be empty..

	HttpMethod method = request.getMethod();
	if (contentType == null && method != null && SUPPORTED_METHODS.contains(method)) {
		Flux<DataBuffer> body = request.getBody().doOnNext(o -> {
			// Body not empty, back to 415..
			throw new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes, elementType);
		});
		if (isBodyRequired) {
			body = body.switchIfEmpty(Mono.error(() -> handleMissingBody(bodyParam)));
		}
		return (adapter != null ? Mono.just(adapter.fromPublisher(body)) : Mono.from(body));
	}

	return Mono.error(new UnsupportedMediaTypeStatusException(mediaType, this.supportedMediaTypes, elementType));
}
 
Example 11
Source File: ReactiveTypeHandler.java    From java-technology-stack with MIT License 4 votes vote down vote up
DeferredResultSubscriber(DeferredResult<Object> result, ReactiveAdapter adapter, ResolvableType elementType) {
	this.result = result;
	this.multiValueSource = adapter.isMultiValue();
	this.values = new CollectedValuesList(elementType);
}
 
Example 12
Source File: RequestProcessor.java    From spring-cloud-function with Apache License 2.0 4 votes vote down vote up
private Publisher<?> body(Object handler, ServerWebExchange exchange) {
	ResolvableType elementType = ResolvableType
			.forClass(this.inspector.getInputType(handler));

	// we effectively delegate type conversion to FunctionCatalog
	elementType = ResolvableType.forClass(String.class);

	ResolvableType actualType = elementType;

	Class<?> resolvedType = elementType.resolve();
	ReactiveAdapter adapter = (resolvedType != null
			? getAdapterRegistry().getAdapter(resolvedType) : null);

	ServerHttpRequest request = exchange.getRequest();
	ServerHttpResponse response = exchange.getResponse();

	MediaType contentType = request.getHeaders().getContentType();
	MediaType mediaType = (contentType != null ? contentType
			: MediaType.APPLICATION_OCTET_STREAM);

	if (logger.isDebugEnabled()) {
		logger.debug(exchange.getLogPrefix() + (contentType != null
				? "Content-Type:" + contentType
				: "No Content-Type, using " + MediaType.APPLICATION_OCTET_STREAM));
	}
	boolean isBodyRequired = (adapter != null && !adapter.supportsEmpty());

	MethodParameter bodyParam = new MethodParameter(handlerMethod(handler), 0);
	for (HttpMessageReader<?> reader : getMessageReaders()) {
		if (reader.canRead(elementType, mediaType)) {
			Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT,
					exchange.getLogPrefix());
			if (adapter != null && adapter.isMultiValue()) {
				if (logger.isDebugEnabled()) {
					logger.debug(
							exchange.getLogPrefix() + "0..N [" + elementType + "]");
				}
				Flux<?> flux = reader.read(actualType, elementType, request, response,
						readHints);
				flux = flux.onErrorResume(
						ex -> Flux.error(handleReadError(bodyParam, ex)));
				if (isBodyRequired) {
					flux = flux.switchIfEmpty(
							Flux.error(() -> handleMissingBody(bodyParam)));
				}
				return Mono.just(adapter.fromPublisher(flux));
			}
			else {
				// Single-value (with or without reactive type wrapper)
				if (logger.isDebugEnabled()) {
					logger.debug(exchange.getLogPrefix() + "0..1 [" + elementType + "]");
				}
				Mono<?> mono = reader.readMono(actualType, elementType, request,
						response, readHints).doOnNext(v -> {
							if (logger.isDebugEnabled()) {
								logger.debug("received: " + v);
							}
						});
				mono = mono.onErrorResume(
						ex -> Mono.error(handleReadError(bodyParam, ex)));
				if (isBodyRequired) {
					mono = mono.switchIfEmpty(
							Mono.error(() -> handleMissingBody(bodyParam)));
				}
				return (adapter != null ? Mono.just(adapter.fromPublisher(mono))
						: Mono.from(mono));
			}
		}
	}

	return Mono.error(new UnsupportedMediaTypeStatusException(mediaType,
			Arrays.asList(MediaType.APPLICATION_JSON), elementType));
}