Search code examples
spring-webfluxgraalvmgraalvm-native-imagespring-shell

GraalVM native-image works within IDE (java17) but does not when native-image is built


I have a spring shell application that does pretty simple stuff like sending a get request from the terminal.

pom.xml dependencies

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
      <groupId>org.springframework.shell</groupId>
      <artifactId>spring-shell-starter</artifactId>
</dependency>

It works perfectly fine when I build it or run it through IDE with standard java17. but when I build a native image and try to run the same function I get

Exception in thread "main" java.lang.ExceptionInInitializerError
        at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder$1.provider(DnsServerAddressStreamProviders.java:150)
        at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder$1.<init>(DnsServerAddressStreamProviders.java:130)
        at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder.<clinit>(DnsServerAddressStreamProviders.java:128)
        at io.netty.resolver.dns.DnsServerAddressStreamProviders.unixDefault(DnsServerAddressStreamProviders.java:117)
        at io.netty.resolver.dns.DnsServerAddressStreamProviders.platformDefault(DnsServerAddressStreamProviders.java:113)
        at io.netty.resolver.dns.DnsNameResolverBuilder.<init>(DnsNameResolverBuilder.java:67)
        at reactor.netty.transport.NameResolverProvider.newNameResolverGroup(NameResolverProvider.java:541)
        at reactor.netty.tcp.TcpResources.getOrCreateDefaultResolver(TcpResources.java:315)
        at reactor.netty.http.HttpResources.getOrCreateDefaultResolver(HttpResources.java:162)
        at reactor.netty.http.client.HttpClientConfig.defaultAddressResolverGroup(HttpClientConfig.java:406)
        at reactor.netty.transport.ClientTransportConfig.resolverInternal(ClientTransportConfig.java:228)
        at reactor.netty.http.client.HttpClientConfig.resolverInternal(HttpClientConfig.java:460)
        at reactor.netty.http.client.HttpClientConnect$MonoHttpConnect.lambda$subscribe$0(HttpClientConnect.java:269)
        at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61)
        at reactor.core.publisher.FluxRetryWhen.subscribe(FluxRetryWhen.java:80)
        at reactor.core.publisher.MonoRetryWhen.subscribeOrReturn(MonoRetryWhen.java:46)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:63)
        at reactor.netty.http.client.HttpClientConnect$MonoHttpConnect.subscribe(HttpClientConnect.java:276)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76)
        at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55)
        at reactor.core.publisher.Mono.subscribe(Mono.java:4512)
        at reactor.core.publisher.Mono.block(Mono.java:1727)
        at nabil.req.commands.HttpCommands.request(HttpCommands.java:36)
        at nabil.req.commands.HttpCommands.get(HttpCommands.java:44)
        at [email protected]/java.lang.reflect.Method.invoke(Method.java:568)
        at org.springframework.shell.command.invocation.InvocableShellMethod.doInvoke(InvocableShellMethod.java:306)
        at org.springframework.shell.command.invocation.InvocableShellMethod.invoke(InvocableShellMethod.java:232)
        at org.springframework.shell.command.CommandExecution$DefaultCommandExecution.evaluate(CommandExecution.java:227)
        at org.springframework.shell.Shell.evaluate(Shell.java:248)
        at org.springframework.shell.Shell.run(Shell.java:159)
        at org.springframework.shell.jline.NonInteractiveShellRunner.run(NonInteractiveShellRunner.java:146)
        at org.springframework.shell.DefaultShellApplicationRunner.run(DefaultShellApplicationRunner.java:65)
        at org.springframework.boot.SpringApplication.lambda$callRunner$4(SpringApplication.java:794)
        at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83)
        at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60)
        at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88)
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:806)
        at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:794)
        at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:782)
        at [email protected]/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
        at [email protected]/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357)
        at [email protected]/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
        at [email protected]/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at [email protected]/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
        at [email protected]/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
        at [email protected]/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at [email protected]/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
        at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:782)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:341)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1358)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1347)
        at nabil.req.ReqApplication.main(ReqApplication.java:12)
Caused by: java.lang.NullPointerException
        at [email protected]/sun.net.dns.ResolverConfigurationImpl.stringToList(ResolverConfigurationImpl.java:69)
        at [email protected]/sun.net.dns.ResolverConfigurationImpl.loadConfig(ResolverConfigurationImpl.java:136)
        at [email protected]/sun.net.dns.ResolverConfigurationImpl.nameservers(ResolverConfigurationImpl.java:159)
        at [email protected]/com.sun.jndi.dns.DnsContextFactory.serversForUrls(DnsContextFactory.java:149)
        at [email protected]/com.sun.jndi.dns.DnsContextFactory.getContext(DnsContextFactory.java:81)
        at [email protected]/com.sun.jndi.dns.DnsContextFactory.urlToContext(DnsContextFactory.java:120)
        at [email protected]/com.sun.jndi.dns.DnsContextFactory.getInitialContext(DnsContextFactory.java:64)
        at [email protected]/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:732)
        at [email protected]/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
        at [email protected]/javax.naming.InitialContext.init(InitialContext.java:236)
        at [email protected]/javax.naming.InitialContext.<init>(InitialContext.java:208)
        at [email protected]/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:130)
        at io.netty.resolver.dns.DirContextUtils.addNameServers(DirContextUtils.java:49)
        at io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.<clinit>(DefaultDnsServerAddressStreamProvider.java:55)
        ... 52 more

I can surely say that its related to the native-image build. and somehow can't find a solution to it.


Solution

  • This seems to be a known issue for some operating systems.

    According to this reply, a workaround is to use the following jni-config.json metadata file (this file must be put in META-INF/native-image)

    [
      {
        "name":"sun.net.dns.ResolverConfigurationImpl",
        "fields":[
          {"name":"os_searchlist"},
          {"name":"os_nameservers"}
        ]
      }
    ]
    

    in conjunction with --initialize-at-run-time=sun.net.dns.ResolverConfigurationImpl