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

Support for creating native image with GraalVM #2974

Closed
arnzel opened this issue Oct 12, 2019 · 20 comments
Closed

Support for creating native image with GraalVM #2974

arnzel opened this issue Oct 12, 2019 · 20 comments
Labels
feature needs code stale Stale issue or pull request which will be closed soon

Comments

@arnzel
Copy link

arnzel commented Oct 12, 2019

Did anyone tried creating native image with GraalVm ? I tried with following Dockerfile

FROM oracle/graalvm-ce:19.2.0.1
WORKDIR /opt/graalvm
RUN gu install native-image
ARG JARFILE
COPY ${JARFILE} /${JARFILE}
WORKDIR /
RUN native-image -jar ${JARFILE}

and got this error

Fatal error: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Class io.dropwizard.jetty.ConnectorFactory cannot be instantiated reflectively. It must be a non-abst
ract instance type.

@joschi
Copy link
Member

joschi commented Oct 12, 2019

As far as I know, Jersey (and HK2) aren't supporting Graal native images at the moment.

@meshuga
Copy link

meshuga commented Nov 6, 2019

It looks like Dropwizard uses SPI in a way it wasn't intended to be used. When building native image, GraalVM will try to create instances of all classes that implement SPI interfaces, as described in https://github.com/oracle/graal/blob/92f0b657a5f4892f7380517a714bf93d13db2530/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ServiceLoaderFeature.java#L79

It means that for an SPI interface io.dropwizard.jackson.Discoverable, GraalVM will try to create instances of e.g. io.dropwizard.jetty.ConnectorFactory, since it's defined in META-INF/services directory in dropwizard-jetty project. That will fail because ConnectorFactory is an interface.

There are other interfaces that extend Discoverable, which are used by io.dropwizard.jackson.DiscoverableSubtypeResolver. To make Dropwizard work with GraalVM, I think that feature must be adjusted, so that it would drop usage of SPI for that functionality in its current form.

Jersey should be working now oracle/graal#846.

@ccleve
Copy link

ccleve commented Jan 22, 2020

This bug is definitely worth fixing. With Graal we could distribute a Dropwizard app as a native binary, eliminating the need for a shaded jar file. It would even eliminate the need to install a jvm on a target system.

@meshuga
Copy link

meshuga commented Jan 29, 2020

I tried to build a native image of Dropwizard 2.0 with GraalVM CE 19.3.1 with Java 11. The source code is available at https://github.com/meshuga/dropwizard-graal.

To overcome the error described above, I turned off ServiceLoaderFeature and it seems the issue I described above issue can be solved by writing a custom feature that would (no change of Dropwizard internals is needed):

  1. Register the resources by calling Resources.registerResource(...), as done in https://github.com/oracle/graal/blob/0ab4d527916ebec006189a04692bfcb0edff6592/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ServiceLoaderFeature.java#L233
  2. Don't initialise interfaces, that is omit RuntimeReflection.registerForReflectiveInstantiation(implementationClass); call if possible (ref https://github.com/oracle/graal/blob/92f0b657a5f4892f7380517a714bf93d13db2530/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ServiceLoaderFeature.java#L222)

With the feature turned off, I was able to build a native image within 2-4 minutes (on MacBook Pro 2017) with outcoming binary having 27 MB but get a startup error when initializing Hibernate Validator and Joda Time:

java.io.IOException: Resource not found: "org/joda/time/tz/data/ZoneInfoMap" ClassLoader: java.lang.ClassLoader@1083c7928
        at org.joda.time.tz.ZoneInfoProvider.openResource(ZoneInfoProvider.java:225)
        at org.joda.time.tz.ZoneInfoProvider.<init>(ZoneInfoProvider.java:138)
        at org.joda.time.tz.ZoneInfoProvider.<init>(ZoneInfoProvider.java:97)
        at org.joda.time.DateTimeZone.getDefaultProvider(DateTimeZone.java:555)
        at org.joda.time.DateTimeZone.getProvider(DateTimeZone.java:449)
        at org.joda.time.DateTimeZone.forTimeZone(DateTimeZone.java:367)
        at org.joda.time.DateTimeZone.getDefault(DateTimeZone.java:175)
        at com.fasterxml.jackson.datatype.joda.cfg.FormatConfig.<clinit>(FormatConfig.java:22)
        at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
        at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
        at java.lang.Class.ensureInitialized(DynamicHub.java:475)
        at com.fasterxml.jackson.datatype.joda.deser.DateTimeDeserializer.forType(DateTimeDeserializer.java:34)
        at com.fasterxml.jackson.datatype.joda.JodaModule.<init>(JodaModule.java:20)
        at io.dropwizard.jackson.Jackson.configure(Jackson.java:63)
        at io.dropwizard.jackson.Jackson.newObjectMapper(Jackson.java:30)
        at io.dropwizard.setup.Bootstrap.<init>(Bootstrap.java:61)
        at io.dropwizard.Application.run(Application.java:86)
        at com.github.meshuga.GraalApplication.main(GraalApplication.java:10)
Exception in thread "main" javax.validation.ValidationException: Cannot instantiate provider type: class org.hibernate.validator.HibernateValidator
        at javax.validation.Validation$NewProviderInstance.run(Validation.java:422)
        at javax.validation.Validation$NewProviderInstance.run(Validation.java:404)
        at javax.validation.Validation$ProviderSpecificBootstrapImpl.run(Validation.java:240)
        at javax.validation.Validation$ProviderSpecificBootstrapImpl.configure(Validation.java:213)
        at io.dropwizard.validation.BaseValidator.newConfiguration(BaseValidator.java:26)
        at io.dropwizard.jersey.validation.Validators.newConfiguration(Validators.java:33)
        at io.dropwizard.jersey.validation.Validators.newValidatorFactory(Validators.java:26)
        at io.dropwizard.setup.Bootstrap.<init>(Bootstrap.java:64)
        at io.dropwizard.Application.run(Application.java:86)
        at com.github.meshuga.GraalApplication.main(GraalApplication.java:10)
Caused by: java.lang.InstantiationException: Type `org.hibernate.validator.HibernateValidator` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
        at java.lang.Class.newInstance(DynamicHub.java:796)
        at javax.validation.Validation$NewProviderInstance.run(Validation.java:419)
        ... 9 more

I think after all, it's possible to make Dropwizard run as native image (with narrowed configuration e.g. HTTP only). The compilation time will be biggest issue here since the framework has a lot of transitive dependencies but I think with time, the compilation time of GraalVM will be improved.

Technically, the biggest challenge will be to provide proper support for Jersey and HK2, as @joschi mentioned.

@OneCricketeer
Copy link
Contributor

@OneCricketeer
Copy link
Contributor

If Jersey is the limiting factor, then that just goes back to my rant on #1463

@github-actions github-actions bot added the stale Stale issue or pull request which will be closed soon label Jul 21, 2020
@dropwizard dropwizard deleted a comment from github-actions bot Jul 21, 2020
@joschi joschi added feature needs code and removed stale Stale issue or pull request which will be closed soon labels Jul 21, 2020
@github-actions github-actions bot added the stale Stale issue or pull request which will be closed soon label Oct 20, 2020
@dropwizard dropwizard deleted a comment from github-actions bot Oct 20, 2020
@joschi joschi removed the stale Stale issue or pull request which will be closed soon label Oct 20, 2020
@trnl
Copy link

trnl commented Mar 5, 2021

@OneCricketeer, @meshuga I wonder if you have any updates on it?

@meshuga
Copy link

meshuga commented Mar 7, 2021

I'm no longer working on projects that involve Dropwizard, thus will be hard to test things out on production-like systems.

I checked the timeline of the Jersey roadmap for GraalVM support and it looks like it should be supported in release 2.34 - https://github.com/eclipse-ee4j/jersey/wiki/Road-Map - fingers crossed!

Once done, it should be possible to adjust Dropwizard to create native images. JDBI seems to work with native images (jdbi/jdbi#1797), same with Hibernate (https://in.relation.to/2020/02/14/hibernate-orm-5-4-12/)

@trnl
Copy link

trnl commented Apr 22, 2021

Graal VM support moved to Jersey 2.35.

@subash89
Copy link

@trnl Do you know any issue/jira created on jersey side related to this so that we can follow up on an ETA? I could not find any.

@kenzley
Copy link

kenzley commented Sep 7, 2021

@subash89 The jersey side issue is: eclipse-ee4j/jersey#4547.

It appears that basic graalvm support was added in Jersey 2.35. See: https://github.com/eclipse-ee4j/jersey/blob/master/docs/src/main/docbook/graalvm-native-image.xml.

@joschi
Copy link
Member

joschi commented Sep 7, 2021

Unfortunately, the support for Optional<T> is still broken in Jersey 2.35.
#3969 (comment)

@github-actions
Copy link

github-actions bot commented Mar 7, 2022

This issue is stale because it has been open 90 days with no activity. Remove the "stale" label or comment or this will be closed in 14 days.

@github-actions github-actions bot added the stale Stale issue or pull request which will be closed soon label Mar 7, 2022
@github-actions github-actions bot closed this as completed Apr 5, 2022
@trnl
Copy link

trnl commented Apr 14, 2022

@joschi, can you please reopen the issue? It is still very relevant and actually a big downside for Dropwizard in comparison with other frameworks.

@joschi
Copy link
Member

joschi commented Apr 14, 2022

@trnl Would you be willing to work on the issue if we reopen it?

Looking at the effort it takes for Quarkus, Micronaut, and Spring Native to work properly with GraalVM Native Image, I don't think that we (@dropwizard/committers) will work on it anytime soon.

@trnl
Copy link

trnl commented Apr 14, 2022

@joschi can you elaborate more on the efforts or point out where I can find more information about it?

@joschi
Copy link
Member

joschi commented Apr 14, 2022

@trnl The existence of Spring Native itself, https://info.michael-simons.eu/2020/09/15/about-the-tooling-available-to-create-native-graalvm-images/, https://www.salvis.com/blog/2021/12/29/graalvm-native-image-first-impressions/, etc.

At least I am not willing and able to spend that much time on this.

@zUniQueX
Copy link
Member

zUniQueX commented Jun 7, 2022

Short update: I'm currently testing on the dropwizard-example project, if the approach is maintainable for dropwizard. Currently I'm facing issues with Hibernate, which tends to have problems with GraalVM (see Hibernate 5.4.12 blog post).

@vk-98
Copy link

vk-98 commented Apr 3, 2024

Is there any update on this particular support for GraalVM with Dropwizard?

@meshuga
Copy link

meshuga commented Apr 4, 2024

Hibernate team only focuses on supporting Hibernate with Quarkus but it looks like Hibernate 6 works with graalvm, just need to provide configurations in SPI.

https://discourse.hibernate.org/t/hibernate-6-native-image-from-scratch-no-spring-boot-no-micronaut-no-quarkus/7001

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature needs code stale Stale issue or pull request which will be closed soon
Projects
None yet
Development

No branches or pull requests

10 participants