我正在尝试使用 GraalVM 的
native-image
构建一些软件。我的依赖项包括 google-auth-library-oauth2-http。即使我实际上没有使用库中的任何东西,我的构建也会失败:
➜ gv cat HelloWorld.java
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
➜ javac HelloWorld.java && native-image -cp google-auth-library-oauth2-http-1.20.0.jar -cp . HelloWorld
...
The build process encountered an unexpected error:
> com.oracle.svm.core.util.VMError$HostedError: com.oracle.svm.core.util.UserError$UserException: Image heap writing found a class not seen during static analysis. Did a static field or an object referenced from a static field change during native image generation? For example, a lazily initialized cache could have been initialized during image generation, in which case you need to force eager initialization of the cache before static analysis or reset the cache using a field value recomputation.
class: java.util.concurrent.ConcurrentSkipListMap$Values
reachable through:
object: [Ljava.lang.Class;@1668bbd3 of class: java.lang.Class[]
object: com.oracle.svm.core.code.ImageCodeInfo@1703e50d of class: com.oracle.svm.core.code.ImageCodeInfo
root: com.oracle.svm.core.code.ImageCodeInfo.prepareCodeInfo()
该库本身似乎附带了一些 graalvm 资源,因此作者清楚地记住了这个用例:
➜ gv unzip -l google-auth-library-oauth2-http-1.20.0.jar | grep .json
14581 10-04-2023 00:49 META-INF/native-image/com.google.auth/google-auth-library-oauth2-http/reflect-config.json
但我不太清楚我做错了什么才能让它发挥作用。
检查这是否与“本机图像中的反射
”有关Native Image 对反射有部分支持,需要提前知道反射访问的程序元素。通过
检查和访问程序元素或在运行时使用java.lang.reflect.*
加载类需要为这些程序元素准备额外的元数据。 (注意:这里包含带有Class.forName(String)
的加载类,因为它与反射密切相关。)Class.forName(String)
Native Image 尝试通过静态分析来检测对 Reflection API 的调用来解析目标元素。如果分析失败,则必须使用手动配置来指定在运行时反射访问的程序元素。
错误信息显示,运行时动态使用了静态分析阶段未遇到的类,
native-image
默认无法处理。
您应该尝试提供额外的配置来帮助
native-image
理解并包含这些动态加载的类。该库确实带有 reflect-config.json
,但您可能需要扩展此配置以涵盖所有情况。
尝试修改或扩展库中的 reflect-config.json
文件以包含动态访问的任何缺失的类或成员。构建本机映像时,请使用
-H:ReflectionConfigurationFiles
选项指定反射配置文件的路径。为了将
reflect-config.json
扩展为
google-auth-library-oauth2-http
,您将需要识别可反射访问但现有配置中未涵盖的类和方法。您遇到的错误消息给出了提示:
java.util.concurrent.ConcurrentSkipListMap$Values
。创建一个新的 JSON 文件(命名;例如,
extended-reflect-config.json
)并包含缺少的类及其方法的条目。对于错误中提到的类,JSON 条目将是:
[
{
"name": "java.util.concurrent.ConcurrentSkipListMap$Values",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true
}
// include other missing classes similarly
]
该配置告诉 native-image
包含指定类的所有构造函数和方法(声明的和公共的)。如果现有
reflect-config.json
中还有其他配置,您应该将它们与您的
extended-reflect-config.json
合并,以确保包含所有必要的配置。使用
native-image
构建时,请参考您的
extended-reflect-config.json
:
native-image -cp google-auth-library-oauth2-http-1.20.0.jar -cp . -H:ReflectionConfigurationFiles=extended-reflect-config.json HelloWorld
该过程可能需要一些尝试和错误来识别所有必要的类和方法。
您可以在
Dmitry Chuyko 的“Spring Boot with GraalVM Native Image”中看到类似的案例研究。