flow icon indicating copy to clipboard operation
flow copied to clipboard

Hilla app with @PWA annotation fails when running as native compiled image on macOS

Open rbrki07 opened this issue 1 year ago • 18 comments

Describe the bug

A Hilla app with @PWA annotation throws an exception when running as native compiled image:

java.lang.UnsatisfiedLinkError: No awt in java.library.path
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.NativeLibrarySupport.loadLibraryRelative(NativeLibrarySupport.java:136) ~[na:na]

Expected-behavior

A Hilla app with @PWA annotation should not throw unexpected exceptions when running as native compiled image.

Reproduction

Create a new Hilla project:

npx @hilla/cli@latest init --next hilla-native-pwa

Add @PWA(name = "Hilla PWA", shortName = "PWA") to src/main/java/com/example/application/Application.java.

Compile Hilla app to native image:

./mvnw clean package -Pproduction -Pnative native:compile

Run Hilla app as native compiled image:

./target/hilla-native-pwa

System Info

Hilla: 24.4.0.beta5 Hilla CLI: 2.0.1 Java: 21.0.2 (OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 - build 21.0.2+13-jvmci-23.1-b30) OS: macOS Sonoma 14.4.1 (23E224)

rbrki07 avatar May 31 '24 16:05 rbrki07

vaadin/flow#19457 should fix the issue, but it is not yet released. You can try it out with 24.4-SNAPSHOT

mcollovati avatar May 31 '24 18:05 mcollovati

Thank you for the reference @mcollovati. I'll give it a try.

rbrki07 avatar Jun 01 '24 07:06 rbrki07

I forked vaadin/flow, did mvn clean install -DskipTests in the fork, and then I added flow-server with version 24.5-SNAPSHOT in the pom.xml of the project hilla-native-pwa:

    <dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>flow-server</artifactId>
            <version>24.5-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin</artifactId>
        </dependency>
      ...

After that, I created the native image again:

./mvnw clean package -Pproduction -Pnative native:compile

And then started it again:

./target/hilla-native-pwa

Now there is another error:

2024-06-01T12:01:38.281+02:00 ERROR 20447 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Servlet execution threw an exception] with root cause

java.lang.NoClassDefFoundError: Could not initialize class javax.imageio.ImageIO
        at com.vaadin.flow.server.PwaRegistry.getBaseImage(PwaRegistry.java:369) ~[na:na]

rbrki07 avatar Jun 01 '24 10:06 rbrki07

The fix is in the vaadin-spring artifact

mcollovati avatar Jun 01 '24 10:06 mcollovati

BTW, there should also be a first alpha for Vaadin 24.5 that you can try without having to build flow locally

mcollovati avatar Jun 01 '24 10:06 mcollovati

Also, if you are want to build flow locally but use Vaadin platform 24.4, maybe better build from the 24.4 branch instead of main

mcollovati avatar Jun 01 '24 10:06 mcollovati

Alright, obviously I was on the wrong path 😅 Thanks for your advice, you seem to know your repos, modules, artefacts and versions 👍 I'll give it another try later.

rbrki07 avatar Jun 01 '24 10:06 rbrki07

Ok, next try with 24.5.0.alpha1:

  • npx @hilla/cli@latest init --next hilla-native-pwa
  • Change vaadin.version in pom.xml to 24.5.0.alpha1
  • Add @PWA(name = "Hilla PWA", shortName = "PWA") to src/main/java/com/example/application/Application.java
  • ./mvnw clean package -Pproduction -Pnative native:compile
  • ./target/hilla-native-pwa

Error:

2024-06-01T16:48:41.927+02:00 ERROR 23332 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[springServlet]        : Servlet.service() for servlet [springServlet] threw exception

java.lang.UnsatisfiedLinkError: No awt in java.library.path
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.NativeLibrarySupport.loadLibraryRelative(NativeLibrarySupport.java:136) ~[na:na]
...
2024-06-01T16:48:41.956+02:00 ERROR 23332 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[springServlet]        : Servlet.service() for servlet [springServlet] threw exception

java.lang.NoClassDefFoundError: Could not initialize class javax.imageio.ImageIO
        at com.vaadin.flow.server.PwaRegistry.getBaseImage(PwaRegistry.java:369) ~[na:na]
...

rbrki07 avatar Jun 01 '24 14:06 rbrki07

That's weird. I tried it and it worked for me

mcollovati avatar Jun 01 '24 14:06 mcollovati

I tested with GraalVM CE 21 and 22, and the native executable works fine with both. No errors at runtime and the application is working. I'm on Linux, I don't know if that makes a difference.

mcollovati avatar Jun 01 '24 15:06 mcollovati

https://github.com/oracle/graal/issues/4124 could be related

mcollovati avatar Jun 01 '24 15:06 mcollovati

I tried again after a reboot and without any other interfering processes, but the error remains. I'll try it on Linux within the next days.

rbrki07 avatar Jun 01 '24 15:06 rbrki07

I can confirm, that I don't get the described errors, when I create the native executable using Linux. I leave it to you @mcollovati to close this ticket or leave it open. Thank you, for your help on this 🫶

rbrki07 avatar Jun 02 '24 05:06 rbrki07

Thanks for testing. I'll change a bit the title to mention MacOS and transfer the issue to the flow repo for further investigation.

mcollovati avatar Jun 02 '24 06:06 mcollovati

There is one more thing I noticed, and I don't understand: Let's say I managed to create a native executable using Linux like described above. The next step would be to create a Docker image using this native executable. A simple Dockerfile could look like this:

FROM debian:bookworm-slim

WORKDIR /app

COPY target/hilla-native-pwa /app/hilla-native-pwa

CMD ["/app/hilla-native-pwa"]

Creating a Docker image from this Dockerfile works as expected:

docker build -t hilla-native-pwa-native-image .

Now, I'd like to start a new Docker container using this Docker image:

docker run -it --rm -p 8080:8080 hilla-native-pwa-native-image

From the console output, I can see that the app has been started. When I try to access the app in the browser, I'm getting the same UnsatisfiedLinkErrors like described above.

Why is that? Why do I get this error messages? I'm running a native executable inside a Docker container. Why is this native executable complaining about the missing AWT in java.library.path? Do I have to create a Docker image that provides AWT, because the native executable depends on it, but does not contain it?

rbrki07 avatar Jun 02 '24 11:06 rbrki07

I am not completely sure, and I can't check right now, but probably the executable is dinamically linked, so the required libraries should be present at runtime (there should be some library file in the target directory). IIRC, there should also be a native compilation option to make the executable statically linked, but I never tried it.

mcollovati avatar Jun 02 '24 12:06 mcollovati

Yes, you are right 😄 There are a couple of library files (.so) in the target directory of the project, after I did ./mvnw clean package -Pproduction -Pnative native:compile. If I change my Dockerfile to copy those library files...

FROM debian:bookworm-slim

WORKDIR /app

COPY target/*.so /app/
COPY target/hilla-native-pwa /app/hilla-native-pwa

CMD ["/app/hilla-native-pwa"]

... everything works fine! The Docker image is created as desired and when I start a Docker container from that image I can access the Hilla PWA without errors 🙌

rbrki07 avatar Jun 02 '24 13:06 rbrki07

Would the correct fix here be to produce the images at production build time and not have a dependency on awt?

Artur- avatar Jun 05 '24 07:06 Artur-

This ticket/PR has been released with Vaadin 24.6.0.

vaadin-bot avatar Dec 17 '24 13:12 vaadin-bot