Search in sources :

Example 16 with ReactiveAdapter

use of org.springframework.core.ReactiveAdapter in project spring-framework by spring-projects.

the class HandlerMethodArgumentResolverSupport method checkParameterType.

/**
 * Evaluate the {@code Predicate} on the method parameter type or on
 * the generic type within a reactive type wrapper.
 */
protected boolean checkParameterType(MethodParameter parameter, Predicate<Class<?>> predicate) {
    Class<?> type = parameter.getParameterType();
    ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
    if (adapter != null) {
        assertHasValues(adapter, parameter);
        type = parameter.nested().getNestedParameterType();
    }
    return predicate.test(type);
}
Also used : ReactiveAdapter(org.springframework.core.ReactiveAdapter)

Example 17 with ReactiveAdapter

use of org.springframework.core.ReactiveAdapter in project spring-framework by spring-projects.

the class BodyInserters method fromProducer.

/**
 * Inserter to write the given producer of value(s) which must be a {@link Publisher}
 * or another producer adaptable to a {@code Publisher} via
 * {@link ReactiveAdapterRegistry}.
 * <p>Alternatively, consider using the {@code body} shortcuts on
 * {@link org.springframework.web.reactive.function.client.WebClient WebClient} and
 * {@link org.springframework.web.reactive.function.server.ServerResponse ServerResponse}.
 * @param <T> the type of the body
 * @param producer the source of body value(s).
 * @param elementClass the class of values to be produced
 * @return the inserter to write a producer
 * @since 5.2
 */
public static <T> BodyInserter<T, ReactiveHttpOutputMessage> fromProducer(T producer, Class<?> elementClass) {
    Assert.notNull(producer, "'producer' must not be null");
    Assert.notNull(elementClass, "'elementClass' must not be null");
    ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(producer.getClass());
    Assert.notNull(adapter, "'producer' type is unknown to ReactiveAdapterRegistry");
    return (message, context) -> writeWithMessageWriters(message, context, producer, ResolvableType.forClass(elementClass), adapter);
}
Also used : ReactiveAdapter(org.springframework.core.ReactiveAdapter) ServerHttpResponse(org.springframework.http.server.reactive.ServerHttpResponse) ParameterizedTypeReference(org.springframework.core.ParameterizedTypeReference) Publisher(org.reactivestreams.Publisher) MediaType(org.springframework.http.MediaType) MultiValueMap(org.springframework.util.MultiValueMap) Mono(reactor.core.publisher.Mono) DataBuffer(org.springframework.core.io.buffer.DataBuffer) Collectors(java.util.stream.Collectors) ReactiveHttpOutputMessage(org.springframework.http.ReactiveHttpOutputMessage) List(java.util.List) HttpEntity(org.springframework.http.HttpEntity) ServerSentEvent(org.springframework.http.codec.ServerSentEvent) MultipartBodyBuilder(org.springframework.http.client.MultipartBodyBuilder) ClientHttpRequest(org.springframework.http.client.reactive.ClientHttpRequest) Nullable(org.springframework.lang.Nullable) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapterRegistry(org.springframework.core.ReactiveAdapterRegistry) HttpMessageWriter(org.springframework.http.codec.HttpMessageWriter) LinkedMultiValueMap(org.springframework.util.LinkedMultiValueMap) Resource(org.springframework.core.io.Resource) Assert(org.springframework.util.Assert) ReactiveAdapter(org.springframework.core.ReactiveAdapter)

Example 18 with ReactiveAdapter

use of org.springframework.core.ReactiveAdapter in project spring-framework by spring-projects.

the class BodyInserters method writeWithMessageWriters.

private static <M extends ReactiveHttpOutputMessage> Mono<Void> writeWithMessageWriters(M outputMessage, BodyInserter.Context context, Object body, ResolvableType bodyType, @Nullable ReactiveAdapter adapter) {
    Publisher<?> publisher;
    if (body instanceof Publisher) {
        publisher = (Publisher<?>) body;
    } else if (adapter != null) {
        publisher = adapter.toPublisher(body);
    } else {
        publisher = Mono.just(body);
    }
    MediaType mediaType = outputMessage.getHeaders().getContentType();
    return context.messageWriters().stream().filter(messageWriter -> messageWriter.canWrite(bodyType, mediaType)).findFirst().map(BodyInserters::cast).map(writer -> write(publisher, bodyType, mediaType, outputMessage, context, writer)).orElseGet(() -> Mono.error(unsupportedError(bodyType, context, mediaType)));
}
Also used : ReactiveAdapter(org.springframework.core.ReactiveAdapter) ServerHttpResponse(org.springframework.http.server.reactive.ServerHttpResponse) ParameterizedTypeReference(org.springframework.core.ParameterizedTypeReference) Publisher(org.reactivestreams.Publisher) MediaType(org.springframework.http.MediaType) MultiValueMap(org.springframework.util.MultiValueMap) Mono(reactor.core.publisher.Mono) DataBuffer(org.springframework.core.io.buffer.DataBuffer) Collectors(java.util.stream.Collectors) ReactiveHttpOutputMessage(org.springframework.http.ReactiveHttpOutputMessage) List(java.util.List) HttpEntity(org.springframework.http.HttpEntity) ServerSentEvent(org.springframework.http.codec.ServerSentEvent) MultipartBodyBuilder(org.springframework.http.client.MultipartBodyBuilder) ClientHttpRequest(org.springframework.http.client.reactive.ClientHttpRequest) Nullable(org.springframework.lang.Nullable) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapterRegistry(org.springframework.core.ReactiveAdapterRegistry) HttpMessageWriter(org.springframework.http.codec.HttpMessageWriter) LinkedMultiValueMap(org.springframework.util.LinkedMultiValueMap) Resource(org.springframework.core.io.Resource) Assert(org.springframework.util.Assert) MediaType(org.springframework.http.MediaType) Publisher(org.reactivestreams.Publisher)

Example 19 with ReactiveAdapter

use of org.springframework.core.ReactiveAdapter in project spring-framework by spring-projects.

the class AbstractMessageWriterResultHandler method writeBody.

/**
 * Write a given body to the response with {@link HttpMessageWriter}.
 * @param body the object to write
 * @param bodyParameter the {@link MethodParameter} of the body to write
 * @param actualParam the actual return type of the method that returned the value;
 * could be different from {@code bodyParameter} when processing {@code HttpEntity}
 * for example
 * @param exchange the current exchange
 * @return indicates completion or error
 * @since 5.0.2
 */
@SuppressWarnings({ "unchecked", "rawtypes", "ConstantConditions" })
protected Mono<Void> writeBody(@Nullable Object body, MethodParameter bodyParameter, @Nullable MethodParameter actualParam, ServerWebExchange exchange) {
    ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParameter);
    ResolvableType actualType = (actualParam != null ? ResolvableType.forMethodParameter(actualParam) : bodyType);
    ReactiveAdapter adapter = getAdapterRegistry().getAdapter(bodyType.resolve(), body);
    Publisher<?> publisher;
    ResolvableType elementType;
    ResolvableType actualElementType;
    if (adapter != null) {
        publisher = adapter.toPublisher(body);
        boolean isUnwrapped = KotlinDetector.isSuspendingFunction(bodyParameter.getMethod()) && !COROUTINES_FLOW_CLASS_NAME.equals(bodyType.toClass().getName());
        ResolvableType genericType = isUnwrapped ? bodyType : bodyType.getGeneric();
        elementType = getElementType(adapter, genericType);
        actualElementType = elementType;
    } else {
        publisher = Mono.justOrEmpty(body);
        actualElementType = body != null ? ResolvableType.forInstance(body) : bodyType;
        elementType = (bodyType.toClass() == Object.class && body != null ? actualElementType : bodyType);
    }
    if (elementType.resolve() == void.class || elementType.resolve() == Void.class) {
        return Mono.from((Publisher<Void>) publisher);
    }
    MediaType bestMediaType;
    try {
        bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType));
    } catch (NotAcceptableStatusException ex) {
        HttpStatus statusCode = exchange.getResponse().getStatusCode();
        if (statusCode != null && statusCode.isError()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Ignoring error response content (if any). " + ex.getReason());
            }
            return Mono.empty();
        }
        throw ex;
    }
    if (bestMediaType != null) {
        String logPrefix = exchange.getLogPrefix();
        if (logger.isDebugEnabled()) {
            logger.debug(logPrefix + (publisher instanceof Mono ? "0..1" : "0..N") + " [" + elementType + "]");
        }
        for (HttpMessageWriter<?> writer : getMessageWriters()) {
            if (writer.canWrite(actualElementType, bestMediaType)) {
                return writer.write((Publisher) publisher, actualType, elementType, bestMediaType, exchange.getRequest(), exchange.getResponse(), Hints.from(Hints.LOG_PREFIX_HINT, logPrefix));
            }
        }
    }
    MediaType contentType = exchange.getResponse().getHeaders().getContentType();
    boolean isPresentMediaType = (contentType != null && contentType.equals(bestMediaType));
    Set<MediaType> producibleTypes = exchange.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    if (isPresentMediaType || !CollectionUtils.isEmpty(producibleTypes)) {
        return Mono.error(new HttpMessageNotWritableException("No Encoder for [" + elementType + "] with preset Content-Type '" + contentType + "'"));
    }
    List<MediaType> mediaTypes = getMediaTypesFor(elementType);
    if (bestMediaType == null && mediaTypes.isEmpty()) {
        return Mono.error(new IllegalStateException("No HttpMessageWriter for " + elementType));
    }
    return Mono.error(new NotAcceptableStatusException(mediaTypes));
}
Also used : NotAcceptableStatusException(org.springframework.web.server.NotAcceptableStatusException) HttpStatus(org.springframework.http.HttpStatus) Mono(reactor.core.publisher.Mono) HttpMessageNotWritableException(org.springframework.http.converter.HttpMessageNotWritableException) MediaType(org.springframework.http.MediaType) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapter(org.springframework.core.ReactiveAdapter)

Example 20 with ReactiveAdapter

use of org.springframework.core.ReactiveAdapter in project spring-framework by spring-projects.

the class ReactiveTypeHandler method handleValue.

/**
 * Process the given reactive return value and decide whether to adapt it
 * to a {@link ResponseBodyEmitter} or a {@link DeferredResult}.
 * @return an emitter for streaming, or {@code null} if handled internally
 * with a {@link DeferredResult}
 */
@Nullable
public ResponseBodyEmitter handleValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mav, NativeWebRequest request) throws Exception {
    Assert.notNull(returnValue, "Expected return value");
    ReactiveAdapter adapter = this.adapterRegistry.getAdapter(returnValue.getClass());
    Assert.state(adapter != null, () -> "Unexpected return value: " + returnValue);
    ResolvableType elementType = ResolvableType.forMethodParameter(returnType).getGeneric();
    Class<?> elementClass = elementType.toClass();
    Collection<MediaType> mediaTypes = getMediaTypes(request);
    Optional<MediaType> mediaType = mediaTypes.stream().filter(MimeType::isConcrete).findFirst();
    if (adapter.isMultiValue()) {
        if (mediaTypes.stream().anyMatch(MediaType.TEXT_EVENT_STREAM::includes) || ServerSentEvent.class.isAssignableFrom(elementClass)) {
            logExecutorWarning(returnType);
            SseEmitter emitter = new SseEmitter(STREAMING_TIMEOUT_VALUE);
            new SseEmitterSubscriber(emitter, this.taskExecutor).connect(adapter, returnValue);
            return emitter;
        }
        if (CharSequence.class.isAssignableFrom(elementClass)) {
            logExecutorWarning(returnType);
            ResponseBodyEmitter emitter = getEmitter(mediaType.orElse(MediaType.TEXT_PLAIN));
            new TextEmitterSubscriber(emitter, this.taskExecutor).connect(adapter, returnValue);
            return emitter;
        }
        for (MediaType type : mediaTypes) {
            for (MediaType streamingType : JSON_STREAMING_MEDIA_TYPES) {
                if (streamingType.includes(type)) {
                    logExecutorWarning(returnType);
                    ResponseBodyEmitter emitter = getEmitter(streamingType);
                    new JsonEmitterSubscriber(emitter, this.taskExecutor).connect(adapter, returnValue);
                    return emitter;
                }
            }
        }
    }
    // Not streaming...
    DeferredResult<Object> result = new DeferredResult<>();
    new DeferredResultSubscriber(result, adapter, elementType).connect(adapter, returnValue);
    WebAsyncUtils.getAsyncManager(request).startDeferredResultProcessing(result, mav);
    return null;
}
Also used : ServerSentEvent(org.springframework.http.codec.ServerSentEvent) MediaType(org.springframework.http.MediaType) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapter(org.springframework.core.ReactiveAdapter) DeferredResult(org.springframework.web.context.request.async.DeferredResult) Nullable(org.springframework.lang.Nullable)

Aggregations

ReactiveAdapter (org.springframework.core.ReactiveAdapter)41 ResolvableType (org.springframework.core.ResolvableType)16 Mono (reactor.core.publisher.Mono)14 ReactiveAdapterRegistry (org.springframework.core.ReactiveAdapterRegistry)13 List (java.util.List)12 Assert (org.springframework.util.Assert)12 MethodParameter (org.springframework.core.MethodParameter)11 Nullable (org.springframework.lang.Nullable)11 MediaType (org.springframework.http.MediaType)10 Map (java.util.Map)8 Publisher (org.reactivestreams.Publisher)8 Flux (reactor.core.publisher.Flux)8 DataBuffer (org.springframework.core.io.buffer.DataBuffer)7 ArrayList (java.util.ArrayList)6 Collections (java.util.Collections)6 BindingContext (org.springframework.web.reactive.BindingContext)6 ServerWebExchange (org.springframework.web.server.ServerWebExchange)6 Collectors (java.util.stream.Collectors)5 HttpEntity (org.springframework.http.HttpEntity)5 HttpMessageWriter (org.springframework.http.codec.HttpMessageWriter)5