-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Spring Framework: 7.0.3
In the following snippet, (on Windows) and JDK 25, handling the request hangs forever in DataBufferUtils.write():
@RestController
@SpringBootApplication
public class Demo21Application {
public static void main(String[] args) {
SpringApplication.run(Demo21Application.class, args);
}
@GetMapping("/")
Mono<Void> get(ServerWebExchange exchange) {
DataBufferFactory bf = exchange.getResponse().bufferFactory();
DataBuffer buf = bf.allocateBuffer(64);
buf.write("hello world", StandardCharsets.UTF_8);
return DataBufferUtils.write(Mono.just(buf), Path.of("out.txt"));
}
}Running the same on Java 21 succeeds.
The issue is that an exception is thrown in this line (writing is true at this point):
spring-framework/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java
Line 1208 in 02cdd36
| this.channel.write(byteBuffer, pos, attachment, this); |
The exception is caught by reactor and given into hookOnError here:
spring-framework/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java
Lines 1213 to 1219 in 02cdd36
| protected void hookOnError(Throwable throwable) { | |
| this.error.set(throwable); | |
| if (!this.writing.get()) { | |
| this.sink.error(throwable); | |
| } | |
| } |
But since
writing is still true, the exception is swallowed and sink never terminates.
The underlying root cause seems to be an issue with Netty and/or Java (see netty/netty#15324), but the exception handling in WriteCompletionHandler is insufficient.
java.lang.UnsupportedOperationException: ByteBuffer derived from closeable shared sessions not supported
at java.base/java.nio.DirectByteBuffer.address(DirectByteBuffer.java:319)
at java.base/sun.nio.ch.WindowsAsynchronousFileChannelImpl$WriteTask.run(WindowsAsynchronousFileChannelImpl.java:629)
at java.base/sun.nio.ch.WindowsAsynchronousFileChannelImpl.implWrite(WindowsAsynchronousFileChannelImpl.java:745)
at java.base/sun.nio.ch.AsynchronousFileChannelImpl.write(AsynchronousFileChannelImpl.java:251)
at org.springframework.core.io.buffer.DataBufferUtils$WriteCompletionHandler.hookOnNext(DataBufferUtils.java:1208)
at org.springframework.core.io.buffer.DataBufferUtils$WriteCompletionHandler.hookOnNext(DataBufferUtils.java:1172)
at reactor.core.publisher.BaseSubscriber.onNext(BaseSubscriber.java:164)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2565)
at reactor.core.publisher.BaseSubscriber.request(BaseSubscriber.java:218)
at org.springframework.core.io.buffer.DataBufferUtils$WriteCompletionHandler.hookOnSubscribe(DataBufferUtils.java:1197)
at reactor.core.publisher.BaseSubscriber.onSubscribe(BaseSubscriber.java:152)
at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:69)
at org.springframework.core.io.buffer.DataBufferUtils.lambda$write$1(DataBufferUtils.java:340)
at reactor.core.publisher.FluxCreate.subscribe(FluxCreate.java:97)
at reactor.core.publisher.Flux.subscribe(Flux.java:8888)
at reactor.core.publisher.Flux.subscribeWith(Flux.java:9009)
at reactor.core.publisher.Flux.subscribe(Flux.java:8853)
at org.springframework.core.io.buffer.DataBufferUtils.lambda$write$2(DataBufferUtils.java:369)
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:166)
at reactor.core.publisher.MonoZip$ZipCoordinator.signal(MonoZip.java:296)
at reactor.core.publisher.MonoZip$ZipInner.onNext(MonoZip.java:480)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:184)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2565)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:142)
at reactor.core.publisher.MonoZip$ZipInner.onSubscribe(MonoZip.java:472)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:155)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:56)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoZip$ZipCoordinator.request(MonoZip.java:219)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:195)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onSubscribe(MonoIgnoreThen.java:135)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:118)
at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:129)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:54)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:244)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:207)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onComplete(MonoFlatMap.java:190)
at reactor.core.publisher.Operators.complete(Operators.java:137)
at reactor.core.publisher.MonoZip.subscribe(MonoZip.java:121)
at reactor.core.publisher.Mono.subscribe(Mono.java:4569)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:268)
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:166)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:80)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:83)
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerNext(FluxConcatMapNoPrefetch.java:259)
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:870)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:246)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:307)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:130)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onNext(MonoPeekTerminal.java:184)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2565)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.request(MonoPeekTerminal.java:142)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:172)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onSubscribe(MonoFlatMap.java:293)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onSubscribe(MonoPeekTerminal.java:155)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:56)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:166)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:211)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2565)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:144)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:195)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2361)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2235)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:118)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:178)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:56)
at reactor.core.publisher.Mono.subscribe(Mono.java:4569)
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onNext(FluxConcatMapNoPrefetch.java:207)
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:335)
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:294)
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.innerComplete(FluxConcatMapNoPrefetch.java:275)
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onComplete(FluxConcatMap.java:894)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:251)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:326)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
at reactor.core.publisher.Operators.complete(Operators.java:137)
at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:166)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:211)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2565)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:144)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:195)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.request(Operators.java:2325)
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.request(FluxConcatMapNoPrefetch.java:339)
at reactor.core.publisher.MonoNext$NextSubscriber.request(MonoNext.java:109)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2361)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2235)
at reactor.core.publisher.MonoNext$NextSubscriber.onSubscribe(MonoNext.java:71)
at reactor.core.publisher.FluxConcatMapNoPrefetch$FluxConcatMapNoPrefetchSubscriber.onSubscribe(FluxConcatMapNoPrefetch.java:164)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:200)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:82)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:54)
at reactor.core.publisher.Mono.subscribe(Mono.java:4569)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:268)
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:75)
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:56)
at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1344)
at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:730)
at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:489)
at reactor.netty.http.server.HttpServerOperations.handleDefaultHttpRequest(HttpServerOperations.java:863)
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:789)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:115)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:356)
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:283)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:354)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:434)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:361)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:325)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:249)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:354)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:172)
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445)
at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:388)
at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:596)
at io.netty.channel.nio.NioIoHandler.processSelectedKeysPlain(NioIoHandler.java:541)
at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:514)
at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:484)
at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225)
at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1195)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:1474)
Here's a reproducer with a test that succeeds on Java 21 and fails on Java 25: demo21.zip
