spring-projects / spring-ai

An Application Framework for AI Engineering
https://docs.spring.io/spring-ai/reference/index.html
Apache License 2.0
3.36k stars 866 forks source link

Native image compilation issue with spring-ai-tika-document-reader dependency #779

Open iAMSagar44 opened 6 months ago

iAMSagar44 commented 6 months ago

I am trying to build a native image of a Spring AI based application using Native Build tools and am getting an error while building the native image. The error is due to the Spring AI Tika document reader dependency, as I am only getting this error when I have this dependency in the pom.xml.

Native image version used -

native-image 21.0.3 2024-04-16
GraalVM Runtime Environment Liberica-NIK-23.1.3-1 (build 21.0.3+10-LTS)
Substrate VM Liberica-NIK-23.1.3-1 (build 21.0.3+10-LTS, serial gc)

Error during native image build -

[2/8] Performing analysis...  [*]                                                                       (45.6s @ 3.92GB)
   43,333 reachable types   (90.2% of   48,052 total)
   79,502 reachable fields  (65.7% of  120,934 total)
  206,455 reachable methods (61.7% of  334,499 total)
   12,065 types, 1,221 fields, and 10,118 methods registered for reflection
       12 native libraries: -framework Accelerate, -framework Carbon, -framework Cocoa, -framework CoreServices, -framework JavaRuntimeSupport, -framework Metal, -framework OpenGL, -framework QuartzCore, -framework Security, m, stdc++

Error: Classes that should be initialized at run time got initialized during image building:
 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
org.apache.commons.logging.impl.SLF4JLogFactory was unintentionally initialized at build time. To see why org.apache.commons.logging.impl.SLF4JLogFactory got initialized use --trace-class-initialization=org.apache.commons.logging.impl.SLF4JLogFactory
To see how the classes got initialized, use --trace-class-initialization=org.apache.commons.logging.LogFactory,org.apache.commons.logging.impl.SLF4JLogFactory

I traced the initialisation of these classes and noticed this in the logs when I tried to build the native-image -

Error: Classes that should be initialized at run time got initialized during image building:
 org.apache.commons.logging.impl.SLF4JLogFactory was unintentionally initialized at build time. org.springframework.beans.factory.support.DisposableBeanAdapter caused initialization of this class with the following trace: 
    at org.apache.commons.logging.impl.SLF4JLogFactory.<clinit>(SLF4JLogFactory.java)
    at jdk.internal.misc.Unsafe.ensureClassInitialized0(Unknown Source)
    at jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1160)
    at jdk.internal.reflect.MethodHandleAccessorFactory.ensureClassInitialized(MethodHandleAccessorFactory.java:300)
    at jdk.internal.reflect.MethodHandleAccessorFactory.newConstructorAccessor(MethodHandleAccessorFactory.java:103)
    at jdk.internal.reflect.ReflectionFactory.newConstructorAccessor(ReflectionFactory.java:200)
    at java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:549)
    at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)
    at jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:304)
    at java.lang.Class.newInstance(Class.java:725)
    at org.apache.commons.logging.LogFactory.createFactory(LogFactory.java:1047)
    at org.apache.commons.logging.LogFactory$2.run(LogFactory.java:960)
    at java.security.AccessController.executePrivileged(AccessController.java:778)
    at java.security.AccessController.doPrivileged(AccessController.java:319)
    at org.apache.commons.logging.LogFactory.newFactory(LogFactory.java:957)
    at org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:552)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:655)
    at org.springframework.beans.factory.support.DisposableBeanAdapter.<clinit>(DisposableBeanAdapter.java:76)

org.apache.commons.logging.LogFactory was unintentionally initialized at build time. org.springframework.beans.factory.support.DisposableBeanAdapter caused initialization of this class with the following trace: 
    at org.apache.commons.logging.LogFactory.<clinit>(LogFactory.java:136)
    at jdk.internal.misc.Unsafe.ensureClassInitialized0(Unknown Source)
    at jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1160)
    at jdk.internal.reflect.MethodHandleAccessorFactory.ensureClassInitialized(MethodHandleAccessorFactory.java:300)
    at jdk.internal.reflect.MethodHandleAccessorFactory.newConstructorAccessor(MethodHandleAccessorFactory.java:103)
    at jdk.internal.reflect.ReflectionFactory.newConstructorAccessor(ReflectionFactory.java:200)
    at java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:549)
    at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)
    at jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:304)
    at java.lang.Class.newInstance(Class.java:725)
    at org.apache.commons.logging.LogFactory.createFactory(LogFactory.java:1047)
    at org.apache.commons.logging.LogFactory$2.run(LogFactory.java:960)
    at java.security.AccessController.executePrivileged(AccessController.java:778)
    at java.security.AccessController.doPrivileged(AccessController.java:319)
    at org.apache.commons.logging.LogFactory.newFactory(LogFactory.java:957)
    at org.apache.commons.logging.LogFactory.getFactory(LogFactory.java:552)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:655)
    at org.springframework.beans.factory.support.DisposableBeanAdapter.<clinit>(DisposableBeanAdapter.java:76)

I also tried registering hints for reflection but couldn't get the application working. Is there a way to resolve this issue?

alexcheng1982 commented 5 months ago

From the error message, the org.apache.commons.logging.LogFactory was initialized at build time, while it should be initialized at run time. You can try to force this class to be initialized at run time using --initialize-at-run-time option.

You can add this option in pom.xml.

<plugin>
      <groupId>org.graalvm.buildtools</groupId>
      <artifactId>native-maven-plugin</artifactId>
      <configuration>
        <buildArgs>
          <buildArg>--initialize-at-run-time=org.apache.commons.logging.LogFactory</buildArg>
        </buildArgs>
      </configuration>
</plugin>

You may need to force more classes to be initialized at run time due to transitive dependencies.