You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GraalVM Native Image运行失败:EclipseStore导致无法访问Collections$SetFromMap

GraalVM构建Spring Boot Native Image时EclipseStore引发的反射访问异常问题

环境信息

  • GraalVM版本:21.0.5(适配Java 21)
  • Java版本:Java 21
  • Spring Boot版本:3.3.5
  • 操作系统:Sonoma 14.6.1

问题详情

引入EclipseStore 2.0.0依赖后,构建Native Image并运行时出现以下反射访问异常:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field final java.util.Map java.util.Collections$SetFromMap.m accessible: module java.base does not "opens java.util" to unnamed module @60a7e509
    at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
    at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:183)
    at java.base/java.lang.reflect.Field.setAccessible(Field.java:177)
    at org.eclipse.serializer.reflect.XReflect.setAccessible(XReflect.java:110)
    ...

该异常表明应用通过反射访问JDK内部类时,被Java模块系统阻止。

已尝试的解决方案

  • 构建时添加--add-opens参数:在pom.xml中配置--add-opens=java.base/java.util=ALL-UNNAMED;
  • 运行时传递--add-opens参数:通过-H:AdditionalRuntimeOptions将参数传入运行时;
  • 注册反射提示:在RuntimeHints.java中注册java.util.Collections$SetFromMap类及所有成员;
  • 使用反射配置文件:创建reflect-config.json配置反射规则。

以上尝试均未解决问题。

疑问

  1. 如何正确配置GraalVM与Java模块系统,允许反射访问java.util.Collections$SetFromMap?
  2. 该问题是否由EclipseStore与Java 21/GraalVM 21.0.5不兼容导致?
  3. 是否存在不依赖JDK内部类的替代解决方案?

相关代码与配置

EclipseAccountAdapter类代码

public class EclipseAccountAdapter {
    private final EmbeddedStorageManager storageManager;
    private static final Logger log = LoggerFactory.getLogger(EclipseAccountAdapter.class);
    private final ApplicationContext context;

    public EclipseAccountAdapter(EmbeddedStorageManager storageManager, ApplicationContext context) {
        this.storageManager = storageManager;
        this.context = context;
        initializeRoot();
    }

    private void initializeRoot() {
        if (storageManager.root() == null) {
            log.info("Initializing root.");
            storageManager.setRoot(new DataRoot());
            storageManager.storeRoot();
        }
    }

    @Write
    public int save(Account account, StorerType storerType) {
        getRoot().accounts().add(account);
        store(getRoot().accounts().usernameToAccount(), storerType);
        return getRoot().accounts().all().size();
    }

    @Read
    public List<Account> findAll() {
        return new ArrayList<>(getRoot().accounts().all());
    }

    private DataRoot getRoot() {
        return (DataRoot) storageManager.root();
    }

    private void store(final Object object, StorerType storerType) {
        try {
            switch (storerType) {
                case LAZY: {
                    Storer lazyStorer = storageManager.createLazyStorer();
                    lazyStorer.store(object);
                    lazyStorer.commit();
                    break;
                }
                case EAGER: {
                    Storer eagerStorer = storageManager.createEagerStorer();
                    eagerStorer.store(object);
                    eagerStorer.commit();
                }
                default:
                    storageManager.store(object);
            }
        } catch (final Throwable t) {
            onStorageFailure(t);
        }
    }

    private void onStorageFailure(final Throwable t) {
        if (storageManager != null && storageManager.isRunning()) {
            try {
                log.error("Storage error! Shutting down storage...", t);
                SpringApplication.exit(context, () -> 0);
            } catch (final Throwable throwable) {
                log.error(throwable.getMessage(), throwable);
            }
        }
        DataRoot root = getRoot();
        if (root != null) {
            root.clear();
        }
    }
}

pom.xml片段

<dependencies>
    <!-- Spring Boot and GraalVM dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.eclipse.store</groupId>
        <artifactId>storage-embedded</artifactId>
        <version>2.0.0</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.graalvm.buildtools</groupId>
            <artifactId>native-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

完整堆栈信息

2024-10-27T08:01:30.632-05:00  INFO 19610 --- [nativeImageTest] [           main] d.n.nativeImageTest.ServiceConfig        : Initializing EmbeddedStorageManager...
2024-10-27T08:01:30.634-05:00  WARN 19610 --- [nativeImageTest] [           main] w.s.c.ServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accountController': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'eclipseAccountAdapter': Unsatisfied dependency expressed through method 'eclipseAccountAdapter' parameter 0: Error creating bean with name 'injectStorageTest': Instantiation of supplied bean failed
2024-10-27T08:01:30.634-05:00  INFO 19610 --- [nativeImageTest] [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accountController': Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'eclipseAccountAdapter': Unsatisfied dependency expressed through method 'eclipseAccountAdapter' parameter 0: Error creating bean with name 'injectStorageTest': Instantiation of supplied bean failed
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'eclipseAccountAdapter': Unsatisfied dependency expressed through method 'eclipseAccountAdapter' parameter 0: Error creating bean with name 'injectStorageTest': Instantiation of supplied bean failed
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'injectStorageTest': Instantiation of supplied bean failed
Caused by: org.eclipse.serializer.exceptions.NoSuchNestedClassRuntimeException: No nested class java.util.Collections$SetFromMap found in class java.util.Collections
    at org.eclipse.serializer.reflect.XReflect.getDeclaredNestedClass(XReflect.java:416)
    at org.eclipse.serializer.persistence.binary.java.util.BinaryHandlerSetFromMap.New(BinaryHandlerSetFromMap.java:39)

内容的提问来源于stack exchange,提问作者Nathan Lively

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:04:54