Search code examples
javaspring-bootmavengraalvmgraalvm-native-image

How to correctly pass --initialize-at-build-time, --trace-class-initialization to native compilation using Maven and Spring Boot


I am trying to compile my Spring Boot project to native (information below), but I am stuck with the following error:

[INFO]     [creator]     Build resources:
[INFO]     [creator]      - 9.77GB of memory (63.1% of 15.47GB system memory, determined at start)
[INFO]     [creator]      - 20 thread(s) (100.0% of 20 available processor(s), determined at start)
[INFO]     [creator]     Feb 29, 2024 9:02:02 AM org.springframework.data.jpa.repository.query.QueryEnhancerFactory <clinit>
[INFO]     [creator]     INFO: Hibernate is in classpath; If applicable, HQL parser will be used.
[INFO]     [creator]     SLF4J(W): No SLF4J providers were found.
[INFO]     [creator]     SLF4J(W): Defaulting to no-operation (NOP) logger implementation
[INFO]     [creator]     SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
[INFO]     [creator]     [2/8] Performing analysis...  [*]                               (68.3s @ 5.50GB)
[INFO]     [creator]        55,295 reachable types   (92.0% of   60,129 total)
[INFO]     [creator]        87,563 reachable fields  (64.1% of  136,691 total)
[INFO]     [creator]       271,068 reachable methods (63.2% of  429,166 total)
[INFO]     [creator]        17,065 types, 2,896 fields, and 34,625 methods registered for reflection
[INFO]     [creator]     
[INFO]     [creator]     Error: Classes that should be initialized at run time got initialized during image building:
[INFO]     [creator]      ch.qos.logback.core.subst.Token was unintentionally initialized at build time. To see why ch.qos.logback.core.subst.Token got initialized use --trace-class-initialization=ch.qos.logback.core.subst.Token
[INFO]     [creator]     ch.qos.logback.core.joran.util.PropertySetter$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.joran.util.PropertySetter$1 got initialized use --trace-class-initialization=ch.qos.logback.core.joran.util.PropertySetter$1
[INFO]     [creator]     ch.qos.logback.core.model.processor.ImplicitModelHandler$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.model.processor.ImplicitModelHandler$1 got initialized use --trace-class-initialization=ch.qos.logback.core.model.processor.ImplicitModelHandler$1
[INFO]     [creator]     org.apache.logging.log4j.spi.Provider was unintentionally initialized at build time. To see why org.apache.logging.log4j.spi.Provider got initialized use --trace-class-initialization=org.apache.logging.log4j.spi.Provider
[INFO]     [creator]     org.apache.logging.log4j.util.LoaderUtil was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.LoaderUtil got initialized use --trace-class-initialization=org.apache.logging.log4j.util.LoaderUtil
[INFO]     [creator]     org.apache.commons.logging.impl.Jdk14Logger was unintentionally initialized at build time. To see why org.apache.commons.logging.impl.Jdk14Logger got initialized use --trace-class-initialization=org.apache.commons.logging.impl.Jdk14Logger
[INFO]     [creator]     ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules was unintentionally initialized at build time. To see why ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules got initialized use --trace-class-initialization=ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules
[INFO]     [creator]     org.apache.logging.log4j.spi.StandardLevel was unintentionally initialized at build time. To see why org.apache.logging.log4j.spi.StandardLevel got initialized use --trace-class-initialization=org.apache.logging.log4j.spi.StandardLevel
[INFO]     [creator]     org.apache.logging.log4j.util.Constants was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.Constants got initialized use --trace-class-initialization=org.apache.logging.log4j.util.Constants
[INFO]     [creator]     org.apache.commons.logging.LogFactory was unintentionally initialized at build time. To see why org.apache.commons.logging.LogFactory got initialized use --trace-class-initialization=org.apache.commons.logging.LogFactory
[INFO]     [creator]     ch.qos.logback.core.rolling.helper.FileNamePattern was unintentionally initialized at build time. To see why ch.qos.logback.core.rolling.helper.FileNamePattern got initialized use --trace-class-initialization=ch.qos.logback.core.rolling.helper.FileNamePattern
[INFO]     [creator]     ch.qos.logback.core.rolling.helper.RollingCalendar was unintentionally initialized at build time. To see why ch.qos.logback.core.rolling.helper.RollingCalendar got initialized use --trace-class-initialization=ch.qos.logback.core.rolling.helper.RollingCalendar
[INFO]     [creator]     ch.qos.logback.core.util.FileSize was unintentionally initialized at build time. To see why ch.qos.logback.core.util.FileSize got initialized use --trace-class-initialization=ch.qos.logback.core.util.FileSize
[INFO]     [creator]     org.apache.logging.log4j.util.PropertySource$Util was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.PropertySource$Util got initialized use --trace-class-initialization=org.apache.logging.log4j.util.PropertySource$Util
[INFO]     [creator]     org.apache.logging.log4j.util.OsgiServiceLocator was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.OsgiServiceLocator got initialized use --trace-class-initialization=org.apache.logging.log4j.util.OsgiServiceLocator
[INFO]     [creator]     ch.qos.logback.core.util.SimpleInvocationGate was unintentionally initialized at build time. To see why ch.qos.logback.core.util.SimpleInvocationGate got initialized use --trace-class-initialization=ch.qos.logback.core.util.SimpleInvocationGate
[INFO]     [creator]     ch.qos.logback.core.pattern.parser.Parser was unintentionally initialized at build time. To see why ch.qos.logback.core.pattern.parser.Parser got initialized use --trace-class-initialization=ch.qos.logback.core.pattern.parser.Parser
[INFO]     [creator]     ch.qos.logback.core.util.Duration was unintentionally initialized at build time. To see why ch.qos.logback.core.util.Duration got initialized use --trace-class-initialization=ch.qos.logback.core.util.Duration
[INFO]     [creator]     org.apache.logging.log4j.spi.AbstractLogger was unintentionally initialized at build time. To see why org.apache.logging.log4j.spi.AbstractLogger got initialized use --trace-class-initialization=org.apache.logging.log4j.spi.AbstractLogger
[INFO]     [creator]     ch.qos.logback.core.model.processor.DefaultProcessor$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.model.processor.DefaultProcessor$1 got initialized use --trace-class-initialization=ch.qos.logback.core.model.processor.DefaultProcessor$1
[INFO]     [creator]     ch.qos.logback.core.subst.Parser$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.subst.Parser$1 got initialized use --trace-class-initialization=ch.qos.logback.core.subst.Parser$1
[INFO]     [creator]     ch.qos.logback.core.subst.NodeToStringTransformer$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.subst.NodeToStringTransformer$1 got initialized use --trace-class-initialization=ch.qos.logback.core.subst.NodeToStringTransformer$1
[INFO]     [creator]     org.apache.logging.log4j.status.StatusLogger was unintentionally initialized at build time. To see why org.apache.logging.log4j.status.StatusLogger got initialized use --trace-class-initialization=org.apache.logging.log4j.status.StatusLogger
[INFO]     [creator]     ch.qos.logback.core.CoreConstants was unintentionally initialized at build time. To see why ch.qos.logback.core.CoreConstants got initialized use --trace-class-initialization=ch.qos.logback.core.CoreConstants
[INFO]     [creator]     org.slf4j.LoggerFactory was unintentionally initialized at build time. To see why org.slf4j.LoggerFactory got initialized use --trace-class-initialization=org.slf4j.LoggerFactory
[INFO]     [creator]     org.slf4j.MarkerFactory was unintentionally initialized at build time. To see why org.slf4j.MarkerFactory got initialized use --trace-class-initialization=org.slf4j.MarkerFactory
[INFO]     [creator]     ch.qos.logback.core.status.InfoStatus was unintentionally initialized at build time. To see why ch.qos.logback.core.status.InfoStatus got initialized use --trace-class-initialization=ch.qos.logback.core.status.InfoStatus
[INFO]     [creator]     ch.qos.logback.core.rolling.helper.Compressor$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.rolling.helper.Compressor$1 got initialized use --trace-class-initialization=ch.qos.logback.core.rolling.helper.Compressor$1
[INFO]     [creator]     ch.qos.logback.core.rolling.helper.RollingCalendar$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.rolling.helper.RollingCalendar$1 got initialized use --trace-class-initialization=ch.qos.logback.core.rolling.helper.RollingCalendar$1
[INFO]     [creator]     ch.qos.logback.classic.PatternLayout was unintentionally initialized at build time. To see why ch.qos.logback.classic.PatternLayout got initialized use --trace-class-initialization=ch.qos.logback.classic.PatternLayout
[INFO]     [creator]     org.apache.logging.log4j.Level was unintentionally initialized at build time. To see why org.apache.logging.log4j.Level got initialized use --trace-class-initialization=org.apache.logging.log4j.Level
[INFO]     [creator]     org.apache.logging.log4j.util.Strings was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.Strings got initialized use --trace-class-initialization=org.apache.logging.log4j.util.Strings
[INFO]     [creator]     org.apache.logging.slf4j.SLF4JProvider was unintentionally initialized at build time. To see why org.apache.logging.slf4j.SLF4JProvider got initialized use --trace-class-initialization=org.apache.logging.slf4j.SLF4JProvider
[INFO]     [creator]     ch.qos.logback.core.status.WarnStatus was unintentionally initialized at build time. To see why ch.qos.logback.core.status.WarnStatus got initialized use --trace-class-initialization=ch.qos.logback.core.status.WarnStatus
[INFO]     [creator]     ch.qos.logback.classic.Logger was unintentionally initialized at build time. To see why ch.qos.logback.classic.Logger got initialized use --trace-class-initialization=ch.qos.logback.classic.Logger
[INFO]     [creator]     ch.qos.logback.core.model.processor.ChainedModelFilter$1 was unintentionally initialized at build time. To see why ch.qos.logback.core.model.processor.ChainedModelFilter$1 got initialized use --trace-class-initialization=ch.qos.logback.core.model.processor.ChainedModelFilter$1
[INFO]     [creator]     ch.qos.logback.classic.Level was unintentionally initialized at build time. To see why ch.qos.logback.classic.Level got initialized use --trace-class-initialization=ch.qos.logback.classic.Level
[INFO]     [creator]     ch.qos.logback.core.status.StatusBase was unintentionally initialized at build time. To see why ch.qos.logback.core.status.StatusBase got initialized use --trace-class-initialization=ch.qos.logback.core.status.StatusBase
[INFO]     [creator]     org.apache.logging.log4j.util.PropertiesUtil was unintentionally initialized at build time. To see why org.apache.logging.log4j.util.PropertiesUtil got initialized use --trace-class-initialization=org.apache.logging.log4j.util.PropertiesUtil
[INFO]     [creator]     org.apache.logging.log4j.simple.SimpleLogger was unintentionally initialized at build time. To see why org.apache.logging.log4j.simple.SimpleLogger got initialized use --trace-class-initialization=org.apache.logging.log4j.simple.SimpleLogger
[INFO]     [creator]     ch.qos.logback.core.util.Loader was unintentionally initialized at build time. To see why ch.qos.logback.core.util.Loader got initialized use --trace-class-initialization=ch.qos.logback.core.util.Loader
[INFO]     [creator]     To see how the classes got initialized, use --trace-class-initialization=ch.qos.logback.core.subst.Token,ch.qos.logback.core.joran.util.PropertySetter$1,ch.qos.logback.core.model.processor.ImplicitModelHandler$1,org.apache.logging.log4j.spi.Provider,org.apache.logging.log4j.util.LoaderUtil,org.apache.commons.logging.impl.Jdk14Logger,ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules,org.apache.logging.log4j.spi.StandardLevel,org.apache.logging.log4j.util.Constants,org.apache.commons.logging.LogFactory,ch.qos.logback.core.rolling.helper.FileNamePattern,ch.qos.logback.core.rolling.helper.RollingCalendar,ch.qos.logback.core.util.FileSize,org.apache.logging.log4j.util.PropertySource$Util,org.apache.logging.log4j.util.OsgiServiceLocator,ch.qos.logback.core.util.SimpleInvocationGate,ch.qos.logback.core.pattern.parser.Parser,ch.qos.logback.core.util.Duration,org.apache.logging.log4j.spi.AbstractLogger,ch.qos.logback.core.model.processor.DefaultProcessor$1,ch.qos.logback.core.subst.Parser$1,ch.qos.logback.core.subst.NodeToStringTransformer$1,org.apache.logging.log4j.status.StatusLogger,ch.qos.logback.core.CoreConstants,org.slf4j.LoggerFactory,org.slf4j.MarkerFactory,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.core.rolling.helper.Compressor$1,ch.qos.logback.core.rolling.helper.RollingCalendar$1,ch.qos.logback.classic.PatternLayout,org.apache.logging.log4j.Level,org.apache.logging.log4j.util.Strings,org.apache.logging.slf4j.SLF4JProvider,ch.qos.logback.core.status.WarnStatus,ch.qos.logback.classic.Logger,ch.qos.logback.core.model.processor.ChainedModelFilter$1,ch.qos.logback.classic.Level,ch.qos.logback.core.status.StatusBase,org.apache.logging.log4j.util.PropertiesUtil,org.apache.logging.log4j.simple.SimpleLogger,ch.qos.logback.core.util.Loader
[INFO]     [creator]     --------------------------------------------------------------------------------
[INFO]     [creator]       18.5s (23.7% of total time) in 147 GCs | Peak RSS: 8.84GB | CPU load: 13.21
[INFO]     [creator]     ================================================================================
[INFO]     [creator]     Finished generating 'io.xhub.cmi.payyou.eservice.StarterApplication' in 1m 17s.
[INFO]     [creator]     unable to invoke layer creator
[INFO]     [creator]     unable to contribute native-image layer
[INFO]     [creator]     error running build
[INFO]     [creator]     exit status 1
[INFO]     [creator]     ERROR: failed to build: exit status 1
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  04:05 min
[INFO] Finished at: 2024-02-29T10:02:53+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.2.3:build-image (default-cli) on project e-service: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:3.2.3:build-image failed: Builder lifecycle 'creator' failed with status code 51 -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.

I am using this plugin configuration as suggested from the answers I've seen around Stack Overflow and GitHub issues:

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
    <configuration>
        <buildArgs combine.children="append">
            <buildArg>
                --initialize-at-build-time=ch.qos.logback.core.subst.Token,ch.qos.logback.core.util.SimpleInvocationGate,ch.qos.logback.core.pattern.parser.Parser,ch.qos.logback.classic.model.processor.LogbackClassicDefaultNestedComponentRules,org.apache.logging.log4j.util.Constants,org.apache.commons.logging.impl.Jdk14Logger,org.apache.logging.log4j.util.PropertySource$Util,org.apache.logging.log4j.util.Strings,org.slf4j.MarkerFactory,ch.qos.logback.core.model.processor.ImplicitModelHandler$1,org.apache.logging.log4j.spi.StandardLevel,ch.qos.logback.classic.PatternLayout,org.apache.logging.log4j.util.PropertiesUtil,ch.qos.logback.core.status.InfoStatus,org.slf4j.LoggerFactory,ch.qos.logback.core.model.processor.ChainedModelFilter$1,org.apache.logging.log4j.spi.AbstractLogger,org.apache.logging.log4j.util.OsgiServiceLocator,ch.qos.logback.core.joran.util.PropertySetter$1,org.apache.logging.log4j.Level,ch.qos.logback.classic.Level,ch.qos.logback.core.model.processor.DefaultProcessor$1,ch.qos.logback.core.rolling.helper.FileNamePattern,ch.qos.logback.core.status.StatusBase,ch.qos.logback.classic.Logger,org.apache.logging.log4j.status.StatusLogger,org.apache.logging.slf4j.SLF4JProvider,ch.qos.logback.core.util.FileSize,org.apache.logging.log4j.util.LoaderUtil,ch.qos.logback.core.subst.Parser$1,ch.qos.logback.core.rolling.helper.Compressor$1,ch.qos.logback.core.rolling.helper.RollingCalendar,ch.qos.logback.core.status.WarnStatus,org.apache.logging.log4j.spi.Provider,org.apache.commons.logging.LogFactory,ch.qos.logback.core.subst.NodeToStringTransformer$1,ch.qos.logback.core.rolling.helper.RollingCalendar$1,ch.qos.logback.core.CoreConstants,org.apache.logging.log4j.simple.SimpleLogger,ch.qos.logback.core.util.Duration,ch.qos.logback.core.util.Loader
            </buildArg>
        </buildArgs>
    </configuration>
</plugin>

But without luck; it seems like the arg is ignored.

Please note that I ve tried several combination of the environment buildArgs.arg and other configurations but without effect.

I am using:

  • Spring Boot 3.2.3
  • Java 21

When building, the creator downloads and uses this image:

[INFO]     [creator]         Using Java version 21 extracted from MANIFEST.MF
[INFO]     [creator]       BellSoft Liberica NIK 21.0.2: Contributing to layer
[INFO]     [creator]         Downloading from https://download.bell-sw.com/vm/23.1.2/bellsoft-liberica-vm-core-openjdk21.0.2+14-23.1.2+1-linux-amd64.tar.gz
[INFO]     [creator]         Verifying checksum
[INFO]     [creator]         Expanding to /layers/paketo-buildpacks_bellsoft-liberica/native-image-svm

This issue seems similar, but I don't have any snowflake dependencies in my classpath.

How can I pass --initialize-at-build-time and/or --trace-class-initialization to my Maven build?

I am using the following command as per the docs:

mvn -Pnative spring-boot:build-image

Solution

  • You're using buildpacks to build a native image from your application so the Native Image Maven plugin isn't involved in the image's compilation. It does, however, provide some metadata that's fed into the building of the image so you should leave its declaration in your pom.xml.

    If you refer to the README for the native image buildpack, you'll see that the BP_NATIVE_IMAGE_BUILD_ARGUMENTS environment variable allows you to pass arguments to the native-image command:

    Arguments to pass to directly to the native-image command. These arguments must be valid and correctly formed or the native-image command will fail.

    If you refer to the documentation for Spring Boot's Maven plugin, it describes how to pass environment variables to the builder and its buildpacks. In your case, you would configure things something like this:

    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <image>
                <env>
                    <BP_NATIVE_IMAGE_BUILD_ARGUMENTS>--trace-class-initialization=…</BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                </env>
            </image>
        </configuration>
    </plugin>