Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build time initialization of org.springframework.util.unit.DataSize #4489

Closed
mhalbritter opened this issue Apr 13, 2022 · 9 comments
Closed
Assignees
Labels
bug native-image spring spring related issue
Milestone

Comments

@mhalbritter
Copy link

mhalbritter commented Apr 13, 2022

Hey,

I'm struggling to understand build time initialization. I don't get why the build time initialization of org.springframework.util.unit.DataSize is necessary in our spring-boot native image.

The native image building fails if we don't include --initialize-at-build-time=org.springframework.util.unit.DataSize.

I wasn't able to build a minimal reproducer for this. Here's the full reproducer:

git clone --depth=1 --branch mh/data-size https://github.com/mhalbritter/spring-framework.git
cd spring-framework
./gradlew publishToMavenLocal -xtest -xjavadoc -xdokkaHtmlPartial

git clone --depth=1 --branch aot https://github.com/spring-projects/spring-boot.git
cd spring-boot
./gradlew publishToMavenLocal -xtest -xaggregatedJavadoc -xasciidoctor -xasciidoctorPdf -xzip

git clone https://github.com/snicoll-scratches/demo-native-sample.git
cd demo-native-sample
./mvnw package -Pnative

When running this, i get the error

Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of org.springframework.util.unit.DataSize are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use --trace-object-instantiation=org.springframework.util.unit.DataSize.

When adding the --trace-object-initialization=... from the error message, I get:

Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of org.springframework.util.unit.DataSize are allowed in the image heap as this class should be initialized at image runtime. Object has been initialized without the native-image initialization instrumentation and the stack trace can't be tracked.

Adding --initialize-at-build-time=org.springframework.util.unit.DataSize works, but why is this necessary?

The only thing which we initialize at build time (via native-image.properties file in spring-core.jar) is org.springframework.core.NativeDetector.

I used the latest available 22.1-dev build (https://github.com/graalvm/graalvm-ce-dev-builds/releases/tag/22.1.0-dev-20220411_0809)

openjdk version "17.0.3" 2022-04-19
OpenJDK Runtime Environment GraalVM CE 22.1.0-dev (build 17.0.3+5-jvmci-22.1-b04)
OpenJDK 64-Bit Server VM GraalVM CE 22.1.0-dev (build 17.0.3+5-jvmci-22.1-b04, mixed mode, sharing)

OS is Linux aarch64.

@sdeleuze
Copy link
Collaborator

Please tag this issue with the spring label. FYI we have this issue from the beginning.

@oubidar-Abderrahim oubidar-Abderrahim added the spring spring related issue label Apr 18, 2022
@oubidar-Abderrahim oubidar-Abderrahim self-assigned this Apr 18, 2022
@oubidar-Abderrahim
Copy link
Member

Hi, Thank you for reporting this we will take a look into it and get back to you

@christianwimmer
Copy link
Member

I tried to reproduce, but I get a Java build error on the last step (building demo-native-sample):

ject demo-native-sample: Compilation failure: Compilation failure: 
[ERROR] /home/cwimmer/Downloads/GR-38408/demo-native-sample/src/main/java/com/example/demonativesample/TomcatRuntimeHintsRegistrar.java:[24,36] cannot find symbol
[ERROR]   symbol:   class RuntimeHintsRegistrar
[ERROR]   location: package org.springframework.aot.hint
[ERROR] /home/cwimmer/Downloads/GR-38408/demo-native-sample/src/main/java/com/example/demonativesample/TomcatRuntimeHintsRegistrar.java:[33,46] cannot find symbol
[ERROR]   symbol: class RuntimeHintsRegistrar
[ERROR] /home/cwimmer/Downloads/GR-38408/demo-native-sample/src/main/java/com/example/demonativesample/DemoNativeSampleApplication.java:[7,46] cannot find symbol
[ERROR]   symbol:   class ImportRuntimeHints
[ERROR]   location: package org.springframework.context.annotation
[ERROR] /home/cwimmer/Downloads/GR-38408/demo-native-sample/src/main/java/com/example/demonativesample/DemoNativeSampleApplication.java:[10,2] cannot find symbol
[ERROR]   symbol: class ImportRuntimeHints
[ERROR] /home/cwimmer/Downloads/GR-38408/demo-native-sample/src/main/java/com/example/demonativesample/TomcatRuntimeHintsRegistrar.java:[35,9] method does not override or implement a method from a supertype
[ERROR] -> [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.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

And indeed when looking at https://github.com/mhalbritter/spring-framework/tree/mh/data-size/spring-core/src/main/java/org/springframework/aot/hint there is no file RuntimeHintsRegistrar.java and ImportRuntimeHints.java.

Is there something out of sync with the branches for spring-framework and spring-boot?

@snicoll
Copy link

snicoll commented Apr 28, 2022

Yes, sorry about that. Please remove that tomcat class as well as the import that it references on the main class as neither are necessary to reproduce. Alternatively you could checkout the previous commit.

Thanks for looking at this!

@christianwimmer
Copy link
Member

I can reproduce the problem. This is a corner case triggered by the combination of annotations, enums, and classes that cannot trivially be initialized at image build time:

We are trying to fix this corner case (fyi @loicottet, @vjovanov) but it requires re-working a lot of code that currently accesses annotations eagerly.

But I think you can work around the problem in Spring: you only need to get the field PATTERN out of DataSize in https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/util/unit/DataSize.java#L58
The easiest way is to wrap it in a static inner class. The remaining static final fields in DataSize are not a problem because their initialization can be proven to have no side effects. Putting PATTERN in its own class also has startup benefits on HotSpot: currently every usage of DataSize triggers the expensive compilation of the regular expression. When the field is in a separate class, the compilation only happens when DataSize.parse is invoked the first time (which might be never).

@sbrannen
Copy link

sbrannen commented Jun 3, 2022

Thanks for the analysis and tips, @christianwimmer.

We will start initializing the PATTERN field lazily in Spring Framework 5.3.21.

@sdeleuze
Copy link
Collaborator

@nicolasesprit I am not sure why you are linking this Spring Native (based on Spring Framework 5.3) troubleshooting documentation entry. We modified Spring Framework 6 to workaround this issue as pointed our by @sbrannen. Could you share more details?

@loicottet
Copy link
Member

The underlying issue of initializing annotations at build-time has been patched on master by 9da460f

Native Image automation moved this from To do to Done Jun 17, 2022
@christianwimmer christianwimmer added this to the 22.2 milestone Jun 17, 2022
@sdeleuze
Copy link
Collaborator

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug native-image spring spring related issue
Projects
Native Image
  
Done
Development

No branches or pull requests

7 participants