After compiled application to graalvm native image, and set log level for io.netty
to TRACE, such exception will show up(which can't reproduce in jvm application):
2023-08-31T01:27:05.755+08:00 TRACE 55266 --- [ main] io.netty.channel.nio.NioEventLoop : instrumented a special java.util.Set into: sun.nio.ch.EPollSelectorImpl@28fee399
2023-08-31T01:27:05.755+08:00 DEBUG 55266 --- [ main] i.n.c.socket.nio.SelectorProviderUtil : SelectorProvider.openServerSocketChannel(ProtocolFamily) not available, will use default
java.lang.NoSuchMethodException: java.nio.channels.spi.SelectorProvider.openServerSocketChannel(java.net.ProtocolFamily)
at java.base@17.0.8/java.lang.Class.checkMethod(DynamicHub.java:1038) ~[monolith-service:na]
at java.base@17.0.8/java.lang.Class.getMethod(DynamicHub.java:1023) ~[monolith-service:na]
at io.netty.channel.socket.nio.SelectorProviderUtil.findOpenMethod(SelectorProviderUtil.java:39) ~[na:na]
at io.netty.channel.socket.nio.NioServerSocketChannel.<clinit>(NioServerSocketChannel.java:57) ~[monolith-service:4.1.97.Final]
at reactor.netty.resources.DefaultLoopNIO.getChannel(DefaultLoopNIO.java:45) ~[na:na]
at reactor.netty.resources.LoopResources.onChannel(LoopResources.java:243) ~[monolith-service:1.1.10]
at reactor.netty.tcp.TcpResources.onChannel(TcpResources.java:251) ~[monolith-service:1.1.10]
at reactor.netty.transport.TransportConfig.lambda$connectionFactory$1(TransportConfig.java:277) ~[monolith-service:1.1.10]
at reactor.netty.transport.TransportConnector.doInitAndRegister(TransportConnector.java:277) ~[na:na]
at reactor.netty.transport.TransportConnector.bind(TransportConnector.java:87) ~[na:na]
at reactor.netty.transport.ServerTransport.lambda$bind$0(ServerTransport.java:115) ~[monolith-service:1.1.10]
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:58) ~[na:na]
at reactor.core.publisher.Mono.subscribe(Mono.java:4495) ~[monolith-service:3.5.9]
at reactor.core.publisher.Mono.block(Mono.java:1737) ~[monolith-service:3.5.9]
at reactor.netty.transport.ServerTransport.bindNow(ServerTransport.java:149) ~[monolith-service:1.1.10]
at reactor.netty.transport.ServerTransport.bindNow(ServerTransport.java:134) ~[monolith-service:1.1.10]
at org.springframework.boot.web.embedded.netty.NettyWebServer.startHttpServer(NettyWebServer.java:145) ~[monolith-service:3.1.3]
at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:100) ~[monolith-service:3.1.3]
at org.springframework.boot.web.reactive.context.WebServerManager.start(WebServerManager.java:55) ~[na:na]
at org.springframework.boot.web.reactive.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:41) ~[na:na]
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:179) ~[monolith-service:6.0.11]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:357) ~[monolith-service:6.0.11]
at java.base@17.0.8/java.lang.Iterable.forEach(Iterable.java:75) ~[monolith-service:na]
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:156) ~[monolith-service:6.0.11]
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:124) ~[monolith-service:6.0.11]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:958) ~[monolith-service:6.0.11]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:611) ~[monolith-service:6.0.11]
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[monolith-service:3.1.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[monolith-service:3.1.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) ~[monolith-service:3.1.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[monolith-service:3.1.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[monolith-service:3.1.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[monolith-service:3.1.3]
at com.hkmci.masterspace.monolith.ApplicationKt.main(Application.kt:15) ~[monolith-service:na]
at com.hkmci.masterspace.monolith.ApplicationKt.main(Application.kt) ~[monolith-service:na]
Netty code in io.netty.channel.socket.nio.SelectorProviderUtil
:
@SuppressJava6Requirement(reason = "Usage guarded by java version check")
static Method findOpenMethod(String methodName) {
if (PlatformDependent.javaVersion() >= 15) {
try {
return SelectorProvider.class.getMethod(methodName, java.net.ProtocolFamily.class);
} catch (Throwable e) {
logger.debug("SelectorProvider.{}(ProtocolFamily) not available, will use default", methodName, e);
}
}
return null;
}
Netty do reflection operation on SelectorProvider
, and it's not coverd by Spring AOT.
In fact, Netty will invoke two methods in SelectorProvider
:
public SocketChannel openSocketChannel(ProtocolFamily family)
public ServerSocketChannel openServerSocketChannel(ProtocolFamily family)
Adding reflection hints for these two method can eliminate the exception.
Comment From: bclozel
Could you create this issue against the Netty project directly? Netty is managing its own GraalVM metadata directly in the project (see here for example). For other, non-Spring libraries, please check the library itself or the GraalVM reachability metadata repository.