I am trying to build some software using GraalVM's native-image
. My dependencies include google-auth-library-oauth2-http. My build fails even when I don't actually use anything from the library:
➜ 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()
The library itself seems to come with some graalvm resources, so the authors clearly keep this use-case in mind:
➜ 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
But I can't quite figure out what I am doing wrong to make it work.
Check if this is related to "Reflection in Native Image
The error message shows that a class not encountered during the static analysis phase is being used dynamically at runtime, which
native-image
cannot handle by default.You should try and provide additional configuration to help
native-image
understand and include these dynamically loaded classes. The library does come with areflect-config.json
, but you might need to extend this configuration to cover all cases.Try and modify or extend the
reflect-config.json
file in the library to include any missing classes or members that are dynamically accessed.When building your native image, specify the path to the reflection configuration file using the
-H:ReflectionConfigurationFiles
option.For extending the
reflect-config.json
forgoogle-auth-library-oauth2-http
, you will need to identify the classes and methods that are accessed reflectively but are not covered in the existing configuration. The error message you encountered gives a hint:java.util.concurrent.ConcurrentSkipListMap$Values
.Create a new JSON file (named; for instance,
extended-reflect-config.json
) and include entries for the missing classes and their methods.For the class mentioned in the error, the JSON entry would be:
That configuration tells
native-image
to include all constructors and methods (both declared and public) of the specified class.If there are other configurations in the existing
reflect-config.json
, you should merge them with yourextended-reflect-config.json
to make sure all necessary configurations are included.When building with
native-image
, reference yourextended-reflect-config.json
:That process may require some trial and error to identify all the necessary classes and methods.
You can see a similar case study in "Spring Boot with GraalVM Native Image" from Dmitry Chuyko.