vaadin / flow

Vaadin Flow is a Java framework binding Vaadin web components to Java. This is part of Vaadin 10+.
Apache License 2.0
622 stars 166 forks source link

Missing native-image hints for PWA icon #19123

Closed javier-godoy closed 1 day ago

javier-godoy commented 7 months ago

Description of the bug

Running a Vaadin 24.3.7 application with @PWA and a custom icon (located at src/main/resources/META-INF/resources/icons/icon.png), compiled into a native image using GraalVM 21 results in the following errors. Interestingly, the Tracing Agent did not provide the anticipated hints during initial testing.

java.lang.NoClassDefFoundError: Could not initialize class java.awt.GraphicsEnvironment$LocalGE
        at java.desktop@21.0.2/java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:106) ~[addons-demos-24-native.exe:na]
        at java.desktop@21.0.2/java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1182) ~[addons-demos-24-native.exe:na]
        at com.vaadin.flow.server.PwaIcon.drawIconImage(PwaIcon.java:268) ~[na:na]
java.lang.NoSuchMethodError: sun.awt.windows.WToolkit.windowsSettingChange()V
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions$Support.getMethodID(JNIFunctions.java:1341) ~[na:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions$Support.getMethodID(JNIFunctions.java:1326) ~[na:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions.GetMethodID(JNIFunctions.java:431) ~[na:na]
        at java.desktop@21.0.2/sun.awt.windows.WToolkit.initIDs(Native Method) ~[na:na]
        at java.desktop@21.0.2/sun.awt.windows.WToolkit.<clinit>(WToolkit.java:190) ~[na:na]
        at java.desktop@21.0.2/sun.awt.Win32GraphicsEnvironment.<clinit>(Win32GraphicsEnvironment.java:60) ~[na:na]
        at java.desktop@21.0.2/sun.awt.PlatformGraphicsInfo.createGE(PlatformGraphicsInfo.java:34) ~[na:na]
        at java.desktop@21.0.2/java.awt.GraphicsEnvironment$LocalGE.createGE(GraphicsEnvironment.java:93) ~[na:na]
        at java.desktop@21.0.2/java.awt.GraphicsEnvironment$LocalGE.<clinit>(GraphicsEnvironment.java:84) ~[na:na]
        at java.desktop@21.0.2/java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:106) ~[addons-demos-24-native.exe:na]
        at java.desktop@21.0.2/java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1182) ~[addons-demos-24-native.exe:na]
        at com.vaadin.flow.server.PwaIcon.drawIconImage(PwaIcon.java:268) ~[na:na]

#16307 also mentions the following hint, which in my case was produced by the Tracing Agent:

{
  "name":"sun.java2d.Disposer",
  "methods":[{"name":"addRecord","parameterTypes":["java.lang.Object","long","long"] }]
}

Expected behavior

In 2022 @mstahv said that "Vaadin don’t yet come with these hints", but now there is VaadinHintsRegistrar and the documentation does not mention a word about hints, so I'm inclined to think that I could expect it to work.

Icon generation in native apps seems to be a known issue, though https://github.com/vaadin/flow/issues/16307#issuecomment-1602241827.

Minimal reproducible example

A Vaadin 24.3.7 application with @PWA and a custom icon.

Versions

mcollovati commented 7 months ago

Looking at Quarkus AwtProcessor it seems that there have been some changes in GraalVM 23 related to AWT. For example this block of code https://github.com/quarkusio/quarkus/blob/4b8a27a5d591841d579a1b8ea1041b5fa481e8cf/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java#L276-L287

that points to https://github.com/oracle/graal/issues/4921.

Link to the Quarkus commit https://github.com/quarkusio/quarkus/commit/a3546217ba0de66dea6d1744e22434edaee24fe1

javier-godoy commented 7 months ago

In my case it was a Spring Boot application. I'm fine with maintaining the hints locally, but maybe they should be added to the framework.

mcollovati commented 7 months ago

I mentioned the Quarkus class only because the hints in Flow were updated based on it

javier-godoy commented 7 months ago

I was able to reproduce NoSuchMethodError: sun.awt.windows.WToolkit.windowsSettingChange()V by playing a sound in the browser:

//https://gist.github.com/literallylara/7ece1983fab47365108c47119afb51c7
//(C) Lara Sophie Schütt 2016, CC0 
for(var i=44100*0.1,d="";i--;)d+=String.fromCharCode(~~((Math.sin(i/44100*2*Math.PI*800)+1)*128)); 
bellSound = "data:Audio/WAV;base64,"+btoa("RIFFdataWAVEfmt "+atob("EAAAAAEAAQBErAAARKwAAAEACABkYXRh/////w==")+d);
new Audio(bellSound).play();

Collect Metadata with the Tracing Agent

  1. Start the application with Tracing Agent, open application in browser, terminate. jni-config before playing sound

  2. Start the application with Tracing Agent, open application in browser, open developer tools, execute script above, terminate. jni-config after playing sound

(Browser requests icons/icon-180x180.png when playing a sound)

Required hints

The required hints (in jni-config-after, but neither in jni-config-before, nor provided by VaadinBeanFactoryInitializationAotProcessor) are:

[
{
  "name":"java.awt.Component"
},
{
  "name":"java.awt.Font",
  "fields":[{"name":"name"}, {"name":"pData"}, {"name":"size"}, {"name":"style"}],
  "methods":[{"name":"getFont","parameterTypes":["java.lang.String"] }, {"name":"getFontPeer","parameterTypes":[] }]
},
{
  "name":"java.awt.desktop.UserSessionEvent$Reason",
  "fields":[{"name":"CONSOLE"}, {"name":"LOCK"}, {"name":"REMOTE"}, {"name":"UNSPECIFIED"}]
},
{
  "name":"sun.awt.AWTAutoShutdown",
  "methods":[{"name":"notifyToolkitThreadBusy","parameterTypes":[] }, {"name":"notifyToolkitThreadFree","parameterTypes":[] }]
},
{
  "name":"sun.awt.SunToolkit",
  "methods":[{"name":"isTouchKeyboardAutoShowEnabled","parameterTypes":[] }]
},
{
  "name":"sun.awt.Win32GraphicsEnvironment",
  "methods":[{"name":"dwmCompositionChanged","parameterTypes":["boolean"] }]
},
{
  "name":"sun.awt.image.SunVolatileImage",
  "fields":[{"name":"volSurfaceManager"}]
},
{
  "name":"sun.awt.image.VolatileSurfaceManager",
  "fields":[{"name":"sdCurrent"}]
},
{
  "name":"sun.awt.windows.WDesktopPeer",
  "methods":[{"name":"systemSleepCallback","parameterTypes":["boolean"] }, {"name":"userSessionCallback","parameterTypes":["boolean","java.awt.desktop.UserSessionEvent$Reason"] }]
},
{
  "name":"sun.awt.windows.WToolkit",
  "methods":[{"name":"displayChanged","parameterTypes":[] }, {"name":"windowsSettingChange","parameterTypes":[] }]
},
{
  "name":"sun.java2d.windows.WindowsFlags",
  "fields":[{"name":"d3dEnabled"}, {"name":"d3dSet"}, {"name":"offscreenSharingEnabled"}, {"name":"setHighDPIAware"}]
}
]

After adding these hints, I was able to play the sound in the native image, with no exceptions being logged when the icon is requested. Note that one of the hints is about sun.awt.Win32GraphicsEnvironment, so it's platform-specific.

So far, I've not been able to reproduce NoClassDefFoundError for java.awt.GraphicsEnvironment$LocalGE

Versions

Vaadin / Flow version: 24.3.7 Java version: GraalVM 22+36.1 OS version: Windows 10.0.19045.4170 Browser: Chrome 123.0.6312.88

mcollovati commented 1 week ago

This should have been fixed in recent Vaadin version.

mcollovati commented 1 week ago

Can't reproduce with 24.5

mshabarov commented 2 days ago

I can't provide a complete proof that it has been tested due to encountering this issue: https://github.com/oracle/graal/issues/4124, I have similar exceptions and I'm using macOS:

java.lang.UnsatisfiedLinkError: Can't load library: awt | java.library.path = [.]

also:

java.lang.NoClassDefFoundError: Could not initialize class javax.imageio.ImageIO

Tested with GraalVM 23.0.1, Vaadin 24.6.0.beta1 and Vaadin Spring Boot skeleton starter. The original exceptions in the description seem to be related to awt as well.

I'd propose to close this ticket, likely it's a GraalVM issue that prevents to use PWA in Vaadin with native-image.

caalador commented 2 days ago

I'm getting the couldn't initialize class on Windows 11 also with GraalVM 23.0.1+11.1, Vaadin 24.5.5 (also 24.5-SNAPSHOT)

java.lang.NoClassDefFoundError: Could not initialize class java.awt.GraphicsEnvironment$LocalGE
        at java.desktop@23.0.1/java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:104) ~[my-app.exe:na]
        at java.desktop@23.0.1/java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1182) ~[my-app.exe:na]
        at com.vaadin.flow.server.PwaIcon.drawIconImage(PwaIcon.java:268) ~[na:na]
        at com.vaadin.flow.server.PwaIcon.write(PwaIcon.java:249) ~[na:na]

This comes when the app is running and service worker requests icons/icon-144x144.png leading to console exception Error while trying to use the following icon from the Manifest: http://localhost:8080/icons/icon-144x144.png (Download error or resource isn't a valid image) can also be triggered with just requesting the icon from the browser for that url.

mshabarov commented 1 day ago

https://github.com/vaadin/flow/pull/20516 to be tested if it helps to fix this issue with PWA icon.

caalador commented 1 day ago

Tested against 24.6-SNAPSHOT and there the exception is not thrown anymore when the images are pregenerated.

mcollovati commented 1 day ago

According to Quarkus code, it seems AWT integration is not yet working in native-image for Windows

https://github.com/quarkusio/quarkus/blob/4864b938f595154ff8c32b0a155d211274e75753/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java#L46C1-L52C1

    @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
    UnsupportedOSBuildItem osSupportCheck() {
        return new UnsupportedOSBuildItem(WINDOWS,
                "Windows AWT integration is not ready in native-image and would result in " +
                        "java.lang.UnsatisfiedLinkError: no awt in java.library.path.");
    }
mstahv commented 1 day ago

Could we just try to fix this "properly"? To me the AWT usage at runtime sounds like a design bug we should fix. It makes some raster images scaling? Shouldn't that be done when doing a production build of the client bundle?

mcollovati commented 1 day ago

Could we just try to fix this "properly"? To me the AWT usage at runtime sounds like a design bug we should fix. It makes some raster images scaling? Shouldn't that be done when doing a production build of the client bundle?

20516 generates PWA icons at build time

mstahv commented 1 day ago

Ah, excellent, so only trying to get it work in older branches?

mshabarov commented 1 day ago

https://github.com/vaadin/flow/pull/20516 is not binary compatible, thus I'd not doing backport in a patch release, but rather in the future minor releases of V14 and V23.

mshabarov commented 1 day ago

Closed based on https://github.com/vaadin/flow/issues/19123#issuecomment-2503256371 testing.