Skip to content

SpringBoot 3 + AOT/native/GraalVM + reactive Redis -> issue at runtime for native binary #2480

@patpatpat123

Description

@patpatpat123

Happy New Year 2023 Spring Data Redis team!

Small issue regarding the new Spring Boot 3 with AOT/native/GraalVM please.

Lately, many talks regarding the new Spring Boot 3 are about the AOT/native/GraalVM.

I went to try migrating a project which was building without GraalVM, to this new paradigm so many are talking about.

Here is the straightforward code of the project (I am not attaching the jar, it is really just those files)

@SpringBootApplication
public class RedisApplication {

	public static void main(String[] args) {
		SpringApplication.run(RedisApplication.class, args);
	}

}
package com.redis.controller;

import com.redis.model.RedisPojo;
import com.redis.repository.RedisRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class RedisController {

    private final RedisRepository redisRepository;

    @Autowired
    public RedisController(RedisRepository redisRepository) {
        this.redisRepository = redisRepository;
    }

    @PostMapping(path = "/save", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Mono<String> save(@RequestBody RedisPojo redisPojo) {
        return redisRepository.save(redisPojo).map(__ -> "Issue with GraalVM");
    }

}

package com.redis.repository;

import com.redis.model.RedisPojo;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;

@Repository
public class RedisRepository {

    private final ReactiveRedisOperations<String, String> reactiveRedisOperations;

    public RedisRepository(ReactiveRedisOperations<String, String> reactiveRedisOperations) {
        this.reactiveRedisOperations = reactiveRedisOperations;
    }

    public Mono<RedisPojo> save(RedisPojo redisPojo) {
        return reactiveRedisOperations.opsForValue().set(redisPojo.input(), redisPojo.output()).map(__ -> redisPojo);
    }

}

package com.redis.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;

@Configuration
public class RedisConfiguration {

    @Bean
    public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory() {
        final RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName("localhost");
        redisStandaloneConfiguration.setPort(6379);
        return new LettuceConnectionFactory(redisStandaloneConfiguration);
    }

    @Bean
    public ReactiveRedisOperations<String, String> reactiveRedisOperations(ReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {
        return new ReactiveStringRedisTemplate(reactiveRedisConnectionFactory);
    }

}

package com.redis.model;

public record RedisPojo(String input, String output) {

}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.0.1</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com</groupId>
	<artifactId>redis</artifactId>
	<version>1.1</version>
	<name>redis</name>
	<description>Demo project for Spring Boot with Redis</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

The GraalVM version is: graalvm-ce-java17-22.3.0

I am building and running on Windows.

While running mvnw.cmd -Pnative native:compile the project builds fine, however, running the native image always yields this error:

target\redis.exe

2023-01-04T20:57:50.976+08:00  INFO 18180 --- [           main] com.redis.RedisApplication               : Starting AOT-processed RedisApplication using Java 17.0.5 with PID 18180
2023-01-04T20:57:50.977+08:00  INFO 18180 --- [           main] com.redis.RedisApplication               : No active profile set, falling back to 1 default profile: "default"
2023-01-04T20:57:51.014+08:00  WARN 18180 --- [           main] .r.c.ReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisController': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'redisRepository': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'reactiveRedisOperations': Unsatisfied dependency expressed through method 'reactiveRedisOperations' parameter 0: Error creating bean with name 'reactiveRedisConnectionFactory': null
2023-01-04T20:57:51.015+08:00 ERROR 18180 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisController': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'redisRepository': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'reactiveRedisOperations': Unsatisfied dependency expressed through method 'reactiveRedisOperations' parameter 0: Error creating bean with name 'reactiveRedisConnectionFactory': null
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:351) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:271) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[redis.exe:6.0.3]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[redis.exe:6.0.3]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[redis.exe:6.0.3]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[redis.exe:3.0.1]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[redis.exe:3.0.1]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[redis.exe:3.0.1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[redis.exe:3.0.1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[redis.exe:3.0.1]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[redis.exe:3.0.1]
        at com.redis.RedisApplication.main(RedisApplication.java:10) ~[redis.exe:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'redisRepository': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'reactiveRedisOperations': Unsatisfied dependency expressed through method 'reactiveRedisOperations' parameter 0: Error creating bean with name 'reactiveRedisConnectionFactory': null
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:351) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:271) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334) ~[na:na]
        ... 21 common frames omitted
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reactiveRedisOperations': Unsatisfied dependency expressed through method 'reactiveRedisOperations' parameter 0: Error creating bean with name 'reactiveRedisConnectionFactory': null
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:351) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:271) ~[na:na]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334) ~[na:na]
        ... 36 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reactiveRedisConnectionFactory': null
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1751) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334) ~[na:na]
        ... 51 common frames omitted
Caused by: java.lang.ExceptionInInitializerError: null
        at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder$1.provider(DnsServerAddressStreamProviders.java:150) ~[na:na]
        at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder$1.<init>(DnsServerAddressStreamProviders.java:130) ~[na:na]
        at io.netty.resolver.dns.DnsServerAddressStreamProviders$DefaultProviderHolder.<clinit>(DnsServerAddressStreamProviders.java:128) ~[na:na]
        at io.netty.resolver.dns.DnsServerAddressStreamProviders.unixDefault(DnsServerAddressStreamProviders.java:117) ~[na:na]
        at io.netty.resolver.dns.DnsServerAddressStreamProviders.platformDefault(DnsServerAddressStreamProviders.java:113) ~[na:na]
        at io.netty.resolver.dns.DnsNameResolverBuilder.<init>(DnsNameResolverBuilder.java:60) ~[na:na]
        at io.lettuce.core.resource.AddressResolverGroupProvider$DefaultDnsAddressResolverGroupWrapper.<clinit>(AddressResolverGroupProvider.java:56) ~[na:na]
        at io.lettuce.core.resource.AddressResolverGroupProvider.<clinit>(AddressResolverGroupProvider.java:35) ~[na:na]
        at io.lettuce.core.resource.DefaultClientResources.<clinit>(DefaultClientResources.java:112) ~[redis.exe:6.2.2.RELEASE]
        at io.lettuce.core.AbstractRedisClient.<init>(AbstractRedisClient.java:122) ~[redis.exe:6.2.2.RELEASE]
        at io.lettuce.core.RedisClient.<init>(RedisClient.java:99) ~[redis.exe:6.2.2.RELEASE]
        at io.lettuce.core.RedisClient.create(RedisClient.java:136) ~[redis.exe:6.2.2.RELEASE]
        at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.lambda$createClient$7(LettuceConnectionFactory.java:1178) ~[redis.exe:3.0.0]
        at java.base@17.0.5/java.util.Optional.orElseGet(Optional.java:364) ~[redis.exe:na]
        at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.createClient(LettuceConnectionFactory.java:1178) ~[redis.exe:3.0.0]
        at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory.afterPropertiesSet(LettuceConnectionFactory.java:324) ~[redis.exe:3.0.0]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797) ~[redis.exe:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747) ~[redis.exe:6.0.3]
        ... 61 common frames omitted
Caused by: java.lang.NullPointerException: null
        at java.base@17.0.5/sun.net.dns.ResolverConfigurationImpl.stringToList(ResolverConfigurationImpl.java:69) ~[na:na]
        at java.base@17.0.5/sun.net.dns.ResolverConfigurationImpl.loadConfig(ResolverConfigurationImpl.java:136) ~[na:na]
        at java.base@17.0.5/sun.net.dns.ResolverConfigurationImpl.nameservers(ResolverConfigurationImpl.java:159) ~[na:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.serversForUrls(DnsContextFactory.java:149) ~[redis.exe:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.getContext(DnsContextFactory.java:81) ~[redis.exe:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.urlToContext(DnsContextFactory.java:120) ~[redis.exe:na]
        at jdk.naming.dns@17.0.5/com.sun.jndi.dns.DnsContextFactory.getInitialContext(DnsContextFactory.java:64) ~[redis.exe:na]
        at java.naming@17.0.5/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:732) ~[redis.exe:na]
        at java.naming@17.0.5/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305) ~[redis.exe:na]
        at java.naming@17.0.5/javax.naming.InitialContext.init(InitialContext.java:236) ~[redis.exe:na]
        at java.naming@17.0.5/javax.naming.InitialContext.<init>(InitialContext.java:208) ~[redis.exe:na]
        at java.naming@17.0.5/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:130) ~[redis.exe:na]
        at io.netty.resolver.dns.DirContextUtils.addNameServers(DirContextUtils.java:49) ~[na:na]
        at io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider.<clinit>(DefaultDnsServerAddressStreamProvider.java:53) ~[na:na]
        ... 79 common frames omitted

To avoid confusion, I am building and running fine the same code with openJDK, and any other JDK. Actually, even with GraalVM, but not using the native, it compiles and runs fine.

Only when compiling native, and running native, for Reactive Elastic, the issue occurs, 100% of the time.

Could you please help fixing this issue? Or maybe suggest what type of Registrar I need please?

Thank you

Metadata

Metadata

Assignees

No one assigned

    Labels

    for: external-projectFor an external project and not something we can fix

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions