@SuppressWarnings("unchecked") private static Mono<MultiValueMap<String, String>> initFormData(ServerHttpRequest request, List<HttpMessageReader<?>> readers) { try { MediaType contentType = request.getHeaders().getContentType(); if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) { return ((HttpMessageReader<MultiValueMap<String, String>>) readers.stream() .filter(reader -> reader.canRead(FORM_DATA_TYPE, MediaType.APPLICATION_FORM_URLENCODED)) .findFirst() .orElseThrow(() -> new IllegalStateException("No form data HttpMessageReader."))) .readMono(FORM_DATA_TYPE, request, Hints.none()) .switchIfEmpty(EMPTY_FORM_DATA) .cache(); } } catch (InvalidMediaTypeException ex) { // Ignore } return EMPTY_FORM_DATA; }
/** * Server-side only alternative to * {@link #read(ResolvableType, ReactiveHttpInputMessage, Map)} * with additional context available. * @param actualType the actual type of the target method parameter; * for annotated controllers, the {@link MethodParameter} can be accessed * via {@link ResolvableType#getSource()}. * @param elementType the type of Objects in the output stream * @param request the current request * @param response the current response * @param hints additional information about how to read the body * @return the decoded stream of elements */ default Flux<T> read(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { return read(elementType, request, hints); }
private static <T, S extends Publisher<T>> S readWithMessageReaders( ReactiveHttpInputMessage message, BodyExtractor.Context context, ResolvableType elementType, Function<HttpMessageReader<T>, S> readerFunction, Function<UnsupportedMediaTypeException, S> errorFunction, Supplier<S> emptySupplier) { if (VOID_TYPE.equals(elementType)) { return emptySupplier.get(); } MediaType contentType = Optional.ofNullable(message.getHeaders().getContentType()) .orElse(MediaType.APPLICATION_OCTET_STREAM); return context.messageReaders().stream() .filter(reader -> reader.canRead(elementType, contentType)) .findFirst() .map(BodyExtractors::<T>cast) .map(readerFunction) .orElseGet(() -> { List<MediaType> mediaTypes = context.messageReaders().stream() .flatMap(reader -> reader.getReadableMediaTypes().stream()) .collect(Collectors.toList()); return errorFunction.apply( new UnsupportedMediaTypeException(contentType, mediaTypes, elementType)); }); }
if (reader.canRead(elementType, mediaType)) { Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()); if (adapter != null && adapter.isMultiValue()) { 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) { 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) {
@Override public void reader(HttpMessageReader<?> reader) { boolean canReadToObject = reader.canRead(ResolvableType.forClass(Object.class), null); (canReadToObject ? this.objectReaders : this.typedReaders).add(reader); }
/** * Server-side only alternative to * {@link #readMono(ResolvableType, ReactiveHttpInputMessage, Map)} * with additional, context available. * @param actualType the actual type of the target method parameter; * for annotated controllers, the {@link MethodParameter} can be accessed * via {@link ResolvableType#getSource()}. * @param elementType the type of Objects in the output stream * @param request the current request * @param response the current response * @param hints additional information about how to read the body * @return the decoded stream of elements */ default Mono<T> readMono(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { return readMono(elementType, request, hints); }
/** * Constructor that also accepts a {@link ReactiveAdapterRegistry}. * @param messageReaders readers to convert from the request body * @param adapterRegistry for adapting to other reactive types from Flux and Mono */ protected AbstractMessageReaderArgumentResolver( List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry adapterRegistry) { super(adapterRegistry); Assert.notEmpty(messageReaders, "At least one HttpMessageReader is required"); Assert.notNull(adapterRegistry, "ReactiveAdapterRegistry is required"); this.messageReaders = messageReaders; this.supportedMediaTypes = messageReaders.stream() .flatMap(converter -> converter.getReadableMediaTypes().stream()) .collect(Collectors.toList()); }
.getReaders() .stream() .filter(reader -> reader.canRead(elementType, contentType)) .findFirst() .orElseThrow(() -> new UnsupportedMediaTypeStatusException( Flux<?> flux = httpMessageReader.read(bodyType, elementType, request, response, readHints); return Mono.just(adapter.fromPublisher(flux)); Mono<?> mono = httpMessageReader.readMono(bodyType, elementType, request, response, readHints); if (adapter != null) { return Mono.just(adapter.fromPublisher(mono));
private static <T> HttpMessageReader<T> findReader( ResolvableType elementType, MediaType mediaType, BodyExtractor.Context context) { return context.messageReaders().stream() .filter(messageReader -> messageReader.canRead(elementType, mediaType)) .findFirst() .map(BodyExtractors::<T>cast) .orElseThrow(() -> new IllegalStateException( "No HttpMessageReader for \"" + mediaType + "\" and \"" + elementType + "\"")); }
/** * Server-side only alternative to * {@link #readMono(ResolvableType, ReactiveHttpInputMessage, Map)} * with additional, context available. * @param actualType the actual type of the target method parameter; * for annotated controllers, the {@link MethodParameter} can be accessed * via {@link ResolvableType#getSource()}. * @param elementType the type of Objects in the output stream * @param request the current request * @param response the current response * @param hints additional information about how to read the body * @return the decoded stream of elements */ default Mono<T> readMono(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { return readMono(elementType, request, hints); }
/** * Constructor that also accepts a {@link ReactiveAdapterRegistry}. * @param messageReaders readers to convert from the request body * @param adapterRegistry for adapting to other reactive types from Flux and Mono */ protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry adapterRegistry) { Assert.notEmpty(messageReaders, "At least one HttpMessageReader is required."); Assert.notNull(adapterRegistry, "'adapterRegistry' is required"); this.messageReaders = messageReaders; this.adapterRegistry = adapterRegistry; this.supportedMediaTypes = messageReaders.stream() .flatMap(converter -> converter.getReadableMediaTypes().stream()) .collect(Collectors.toList()); }
if (reader.canRead(elementType, mediaType)) { Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()); exchange.getLogPrefix() + "0..N [" + elementType + "]"); Flux<?> flux = reader.read(actualType, elementType, request, response, readHints); flux = flux.onErrorResume( exchange.getLogPrefix() + "0..1 [" + elementType + "]"); Mono<?> mono = reader.readMono(actualType, elementType, request, response, readHints); mono = mono.onErrorResume(
@SuppressWarnings("unchecked") private static Mono<MultiValueMap<String, Part>> initMultipartData(ServerHttpRequest request, List<HttpMessageReader<?>> readers) { try { MediaType contentType = request.getHeaders().getContentType(); if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) { return ((HttpMessageReader<MultiValueMap<String, Part>>) readers.stream() .filter(reader -> reader.canRead(MULTIPART_DATA_TYPE, MediaType.MULTIPART_FORM_DATA)) .findFirst() .orElseThrow(() -> new IllegalStateException("No multipart HttpMessageReader."))) .readMono(MULTIPART_DATA_TYPE, request, Hints.none()) .switchIfEmpty(EMPTY_MULTIPART_DATA) .cache(); } } catch (InvalidMediaTypeException ex) { // Ignore } return EMPTY_MULTIPART_DATA; } @Override
@Override public void reader(HttpMessageReader<?> reader) { boolean canReadToObject = reader.canRead(ResolvableType.forClass(Object.class), null); (canReadToObject ? this.objectReaders : this.typedReaders).add(reader); }
/** * Server-side only alternative to * {@link #read(ResolvableType, ReactiveHttpInputMessage, Map)} * with additional context available. * @param actualType the actual type of the target method parameter; * for annotated controllers, the {@link MethodParameter} can be accessed * via {@link ResolvableType#getSource()}. * @param elementType the type of Objects in the output stream * @param request the current request * @param response the current response * @param hints additional information about how to read the body * @return the decoded stream of elements */ default Flux<T> read(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { return read(elementType, request, hints); }
private static <T> Mono<T> readToMono(ReactiveHttpInputMessage message, BodyExtractor.Context context, ResolvableType type, HttpMessageReader<T> reader) { return context.serverResponse() .map(response -> reader.readMono(type, type, (ServerHttpRequest) message, response, context.hints())) .orElseGet(() -> reader.readMono(type, message, context.hints())); }
private static <T, S extends Publisher<T>> S readWithMessageReaders( ReactiveHttpInputMessage inputMessage, BodyExtractor.Context context, ResolvableType elementType, Function<HttpMessageReader<T>, S> readerFunction, Function<Throwable, S> unsupportedError) { MediaType contentType = contentType(inputMessage); Supplier<Stream<HttpMessageReader<?>>> messageReaders = context.messageReaders(); return messageReaders.get() .filter(r -> r.canRead(elementType, contentType)) .findFirst() .map(BodyExtractors::<T>cast) .map(readerFunction) .orElseGet(() -> { List<MediaType> supportedMediaTypes = messageReaders.get() .flatMap(reader -> reader.getReadableMediaTypes().stream()) .collect(Collectors.toList()); UnsupportedMediaTypeException error = new UnsupportedMediaTypeException(contentType, supportedMediaTypes); return unsupportedError.apply(error); }); }
if (reader.canRead(elementType, mediaType)) { Map<String, Object> readHints = Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix()); exchange.getLogPrefix() + "0..N [" + elementType + "]"); Flux<?> flux = reader.read(actualType, elementType, request, response, readHints); flux = flux.onErrorResume( exchange.getLogPrefix() + "0..1 [" + elementType + "]"); Mono<?> mono = reader.readMono(actualType, elementType, request, response, readHints); mono = mono.onErrorResume(
@SuppressWarnings("unchecked") private static Mono<MultiValueMap<String, String>> initFormData(ServerHttpRequest request, ServerCodecConfigurer configurer, String logPrefix) { try { MediaType contentType = request.getHeaders().getContentType(); if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) { return ((HttpMessageReader<MultiValueMap<String, String>>) configurer.getReaders().stream() .filter(reader -> reader.canRead(FORM_DATA_TYPE, MediaType.APPLICATION_FORM_URLENCODED)) .findFirst() .orElseThrow(() -> new IllegalStateException("No form data HttpMessageReader."))) .readMono(FORM_DATA_TYPE, request, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix)) .switchIfEmpty(EMPTY_FORM_DATA) .cache(); } } catch (InvalidMediaTypeException ex) { // Ignore } return EMPTY_FORM_DATA; }
private void assertHasMessageReader(List<HttpMessageReader<?>> readers, ResolvableType type, MediaType mediaType) { assertTrue(readers.stream().anyMatch(c -> mediaType == null || c.canRead(type, mediaType))); }