AOT failed with 'className cannot be null' - Spring Cloud version: 2022.0.0 - Spring Boot version: 3.0.1 - Java version: jdk17 - Spring Cloud Alibaba version: 2022.0.0.0-RC1

Exception

Exception in thread "main" java.lang.IllegalArgumentException: className cannot be null
    at org.springframework.util.Assert.notNull(Assert.java:204)
    at org.springframework.cloud.openfeign.aot.FeignClientBeanFactoryInitializationAotProcessor$AotContribution.lambda$applyTo$1(FeignClientBeanFactoryInitializationAotProcessor.java:117)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
    at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1779)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at org.springframework.cloud.openfeign.aot.FeignClientBeanFactoryInitializationAotProcessor$AotContribution.applyTo(FeignClientBeanFactoryInitializationAotProcessor.java:124)
    at org.springframework.context.aot.BeanFactoryInitializationAotContributions.applyTo(BeanFactoryInitializationAotContributions.java:78)
    at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58)
    at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67)
    at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
    at org.springframework.context.aot.ContextAotProcessor.performAotProcessing(ContextAotProcessor.java:106)
    at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:84)
    at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:49)
    at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82)
    at org.springframework.boot.SpringApplicationAotProcessor.main(SpringApplicationAotProcessor.java:76)

Feign Client

/**
 * 用户接口。
 *
 * @author Ben
 * @version 1.0.0
 * @since 2022/12/28
 */
@FeignClient(
        name = "springcloud-service-manager",
        contextId = "userFeignService",
        path = "/user",
        fallbackFactory = UserService.UserServiceFallbackFactory.class)
public interface UserService {

    /**
     * 获取当前用户信息。
     * @return 当前用户信息。
     */
    @GetMapping("/me")
    User me();

    /**
     * 根据请求令牌获取用户信息。
     * @param accessToken 请求令牌。
     * @return 用户信息。
     */
    @GetMapping("/whoami")
    User whoami(@RequestParam String accessToken);

    /**
     * 新增用户。
     * @param user 用户对象。
     * @return 保存成功的用户对象。
     */
    @PostMapping
    User add(@RequestBody User user);

    /**
     * 删除用户。
     * @param id 用户ID。
     */
    @DeleteMapping("/{id}")
    void delete(@PathVariable Long id);

    /**
     * 更新用户。
     * @param id 用户ID。
     * @param user 用户信息。
     * @return 用户存在时返回更新后的对象,否则返回 {@literal null} 。
     */
    @PutMapping("/{id}")
    User update(@PathVariable Long id, @RequestBody User user);

    /**
     * 修改密码。
     * @param id 用户ID。
     * @param oldPassword 当前密码。
     * @param newPassword 新密码。
     */
    @PutMapping("/{id}/password")
    void changePassword(@PathVariable Long id, @RequestParam String oldPassword, @RequestParam String newPassword);

    /**
     * 获取用户。
     * @param id 用户ID。
     * @return 用户存在时返回对象,否则返回 {@literal null} 。
     */
    @GetMapping("/{id}")
    User get(@PathVariable Long id);

    /**
     * 根据用户名获取用户。
     * @param username 用户名。
     * @return 用户存在时返回对象,否则返回 {@literal null} 。
     */
    @GetMapping("/username/{username}")
    User getByUsername(@PathVariable String username);

    /**
     * 统计用户数。
     * @param condition 查询条件。
     * @return 符合条件的用户数。
     */
    @GetMapping("/count")
    long count(@SpringQueryMap UserCondition condition);

    /**
     * 查询用户列表。
     * @param condition 查询条件。
     * @param sort 排序规则。
     * @return 用户列表。
     */
    @GetMapping("/list")
    List<User> getList(@SpringQueryMap UserCondition condition, Sort sort);

    /**
     * 查询用户分页数据。
     * @param condition 查询条件。
     * @param pageable 分页信息。
     * @return 用户分页数据。
     */
    @GetMapping("/page")
    Page<User> getPage(@SpringQueryMap UserCondition condition, Pageable pageable);

    /**
     * 获取 <code>status</code> 属性选项。
     * @return 选项列表。
     */
    @GetMapping("/status/options")
    List<Map<Object, Object>> getStatusOptions();

    @Component
    @Slf4j
    class UserServiceFallbackFactory implements FallbackFactory<UserService> {

        @Override
        public UserService create(Throwable cause) {

            return new UserService() {

                @Override
                public User me() {
                    log.error("服务熔断", cause);
                    return null;
                }

                @Override
                public User whoami(String accessToken) {
                    log.error("服务熔断: accessToken={}", accessToken, cause);
                    return null;
                }

                @Override
                public User add(User user) {
                    log.error("服务熔断: user={}", user, cause);
                    return null;
                }

                @Override
                public void delete(Long id) {
                    log.error("服务熔断: id={}", id, cause);
                }

                @Override
                public User update(Long id, User user) {
                    log.error("服务熔断: id={},user={}", id, user, cause);
                    return null;
                }

                @Override
                public void changePassword(Long id, String oldPassword, String newPassword) {
                    log.error("服务熔断: id={},oldPassword={},newPassword={}", id, oldPassword, newPassword, cause);
                }

                @Override
                public User get(Long id) {
                    log.error("服务熔断: id={}", id, cause);
                    return null;
                }

                @Override
                public User getByUsername(String username) {
                    log.error("服务熔断: username={}", username, cause);
                    return null;
                }

                @Override
                public long count(UserCondition condition) {
                    log.error("服务熔断: condition={}", condition, cause);
                    return 0;
                }

                @Override
                public List<User> getList(UserCondition condition, Sort sort) {
                    log.error("服务熔断: condition={},sort={}", condition, sort, cause);
                    return List.of();
                }

                @Override
                public Page<User> getPage(UserCondition condition, Pageable pageable) {
                    log.error("服务熔断: condition={},pageable={}", condition, pageable, cause);
                    return new PageImpl<>(List.of(), pageable, 0L);
                }

                @Override
                public List<Map<Object, Object>> getStatusOptions() {
                    log.error("服务熔断", cause);
                    return List.of();
                }
            };
        }

    }

}

Code Position

@Override
public void applyTo(GenerationContext generationContext,
        BeanFactoryInitializationCode beanFactoryInitializationCode) {
    ProxyHints proxyHints = generationContext.getRuntimeHints().proxies();
    Set<String> feignClientRegistrationMethods = feignClientBeanDefinitions.values().stream()
            .map(beanDefinition -> {
                Assert.notNull(beanDefinition, "beanDefinition cannot be null");
                Assert.isInstanceOf(GenericBeanDefinition.class, beanDefinition);
                GenericBeanDefinition registeredBeanDefinition = (GenericBeanDefinition) beanDefinition;
                MutablePropertyValues feignClientProperties = registeredBeanDefinition.getPropertyValues();
                String className = (String) feignClientProperties.get("type");
                Assert.notNull(className, "className cannot be null");

My pom.xml

<?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>com.stark.springcloud</groupId>
        <artifactId>spring-cloud-alibaba</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>springcloud-auth-server</artifactId>

    <properties>
        <spring-boot.build-image.imageName>192.168.41.24/spring-cloud-alibaba/${project.artifactId}:${project.version}</spring-boot.build-image.imageName>
    </properties>

    <dependencies>
        <!-- spring-authorization-server start -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- spring-authorization-server end -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        </dependency>
        <!-- openfeign start -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>
        <!-- openfeign end -->
        <!-- sentinel start -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!-- sentinel end -->
        <dependency>
            <groupId>com.stark.springcloud</groupId>
            <artifactId>springcloud-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

My application.yml

spring:
  application:
    name: springcloud-auth-server
  profiles:
    active: dev
  cloud:
    refresh:
      enabled: false
    openfeign:
      client:
        refresh-enabled: false
      lazy-attributes-resolution: false

Maven command

mvn clean -Pnative spring-boot:build-image

Comment From: OlgaMaciaszek

Hello @benfromchina, please provide a minimal, complete, verifiable example that reproduces the issue, as a link to a repo with a small executable app instead of separate code fragments.

Comment From: spring-cloud-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-cloud-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.