Skip to content

Commit

Permalink
Optimize some iterations in BodyExtractor and BodyInserter
Browse files Browse the repository at this point in the history
This commit turns some stream-based iterations back into simpler
enhanced for loops.

For simple use cases like these, where the stream API is merely used to
map/filter + collect to a List, a for loop is more efficient.
This is especially true for small collections like the ones we deal
with in BodyInserters/BodyExtractors here (in the order of 50ns/op vs
5ns/op). These cases are also simple enough that they don't lose in
readability after the conversion.

Closes gh-30136
  • Loading branch information
yuzawa-san authored Mar 22, 2023
1 parent 4e896c8 commit 800b134
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ protected Mono<Void> doCommit(@Nullable Supplier<? extends Publisher<Void>> writ
this.commitActions.add(writeAction);
}

List<? extends Publisher<Void>> actions = this.commitActions.stream()
.map(Supplier::get).toList();
List<Publisher<Void>> actions = new ArrayList<>(this.commitActions.size());
for (Supplier<? extends Publisher<Void>> commitAction : this.commitActions) {
actions.add(commitAction.get());
}

return Flux.concat(actions).then();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,18 +194,16 @@ private static <T, S extends Publisher<T>> S readWithMessageReaders(
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(elementType).stream())
.toList();
return errorFunction.apply(
new UnsupportedMediaTypeException(contentType, mediaTypes, elementType));
});
for (HttpMessageReader<?> messageReader : context.messageReaders()) {
if (messageReader.canRead(elementType, contentType)) {
return readerFunction.apply(cast(messageReader));
}
}
List<MediaType> mediaTypes = context.messageReaders().stream()
.flatMap(reader -> reader.getReadableMediaTypes(elementType).stream())
.toList();
return errorFunction.apply(
new UnsupportedMediaTypeException(contentType, mediaTypes, elementType));
}

private static <T> Mono<T> readToMono(ReactiveHttpInputMessage message, BodyExtractor.Context context,
Expand Down Expand Up @@ -245,12 +243,13 @@ private static <T> Flux<T> unsupportedErrorHandler(
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 + "\""));
for (HttpMessageReader<?> messageReader : context.messageReaders()) {
if (messageReader.canRead(elementType, mediaType)) {
return cast(messageReader);
}
}
throw new IllegalStateException(
"No HttpMessageReader for \"" + mediaType + "\" and \"" + elementType + "\"");
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,12 +373,13 @@ else if (adapter != null) {
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)));
for (HttpMessageWriter<?> messageWriter : context.messageWriters()) {
if (messageWriter.canWrite(bodyType, mediaType)) {
HttpMessageWriter<Object> typedMessageWriter = cast(messageWriter);
return write(publisher, bodyType, mediaType, outputMessage, context, typedMessageWriter);
}
}
return Mono.error(unsupportedError(bodyType, context, mediaType));
}

private static UnsupportedMediaTypeException unsupportedError(ResolvableType bodyType,
Expand Down Expand Up @@ -406,12 +407,13 @@ private static <T> Mono<Void> write(Publisher<? extends T> input, ResolvableType
private static <T> HttpMessageWriter<T> findWriter(
BodyInserter.Context context, ResolvableType elementType, @Nullable MediaType mediaType) {

return context.messageWriters().stream()
.filter(messageWriter -> messageWriter.canWrite(elementType, mediaType))
.findFirst()
.map(BodyInserters::<T>cast)
.orElseThrow(() -> new IllegalStateException(
"No HttpMessageWriter for \"" + mediaType + "\" and \"" + elementType + "\""));
for (HttpMessageWriter<?> messageWriter : context.messageWriters()) {
if (messageWriter.canWrite(elementType, mediaType)) {
return cast(messageWriter);
}
}
throw new IllegalStateException(
"No HttpMessageWriter for \"" + mediaType + "\" and \"" + elementType + "\"");
}

@SuppressWarnings("unchecked")
Expand Down

0 comments on commit 800b134

Please sign in to comment.