hilla
hilla copied to clipboard
fix: add resource pattern for file-routes.json
Description
This should fix that file-routes.json
cannot be loaded from /META-INF/VAADIN/
when Hilla application is executed as native image.
Fixes #2395
Type of change
- [X] Bugfix
- [ ] Feature
Checklist
- [X] I have read the contribution guide: https://vaadin.com/docs/latest/guide/contributing/overview/
- [X] I have added a description following the guideline.
- [X] The issue is created in the corresponding repository and I have referenced it.
- [ ] I have added tests to ensure my change is effective and works as intended.
- [X] New and existing tests are passing locally with my change.
- [X] I have performed self-review and corrected misspellings.
I followed your recommendation @taefi and made the suggested change. Unfortunately, my knowledge about the Hilla project-, build- and test-setup is not sufficient, which means, that I don't know how to verify that the change fixes the issue and I don't know how to add a test case for this particular fix.
I followed your recommendation @taefi and made the suggested change. Unfortunately, my knowledge about the Hilla project-, build- and test-setup is not sufficient, which means, that I don't know how to verify that the change fixes the issue and I don't know how to add a test case for this particular fix.
@rbrki07 while we're looking at this issue, if you're interested in testing your changes locally, it should not be complicated:
- checkout the
main
branch Hilla repo, and make your changes locally (you've already done) - build the repo locally using:
mvn clean install -DskipTests
(from project root, or the changed module(s)) - override the
24.5-SNAPSHOT
(version of the main branch) of the changed module(s) (endpoint
in this case) inpom.xml
of your playground project. - build for native image and run to see if that solved the issue.
For overriding the dependency of the changed module in your playground project, use the latest publicly available version of the Hilla/Vaadin (at this time 24.4.0.beta1
) and put the dependency of the change module(s) on top of the vaadin
dependency (order is important):
<project>
<properties>
<java.version>17</java.version>
<vaadin.version>24.4.0.beta1</vaadin.version>
</properties>
<!-- skipped listing the repositories and pluginRepositories as you already have the prereleases -->
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>hilla-endpoint</artifactId>
<version>24.5-SNAPSHOT</version>
</dependency>
<!-- make sure the dependency of the changed module(s) listed on top of the vaadin managed dependencies -->
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-spring-boot-starter</artifactId>
</dependency>
<!-- rest of the dependencies -->
<dependencies/>
</project>
Maven uses the timestamp of the latest snapshot (either built locally or coming from our regular builds). So, make sure to build Hilla locally right before testing it in your playground project to avoid confusions about which snapshot is in use. Hope this helps.
Thank you @taefi. I will try your instructions and check it locally. I will also apply your suggested changes. I will come back to this pr in a few days, because I'm AFK for a few days.
I followed your instruction @taefi, and I was able to test the change locally 🥳 I tried different variations, but unfortunately none of them worked as desired yet. I will come back to this soon.
Codecov Report
All modified and coverable lines are covered by tests :white_check_mark:
Project coverage is 95.14%. Comparing base (
9be358f
) to head (a380a4a
).
Additional details and impacted files
@@ Coverage Diff @@
## main #2396 +/- ##
=======================================
Coverage 95.14% 95.14%
=======================================
Files 66 66
Lines 4512 4512
Branches 650 650
=======================================
Hits 4293 4293
Misses 178 178
Partials 41 41
Flag | Coverage Δ | |
---|---|---|
unittests | 95.14% <ø> (ø) |
Flags with carried forward coverage won't be shown. Click here to find out more.
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
Thanks for your contribution @marcushellberg!
To test your change, I created a new project using npx @hilla/cli@latest init --next native-image-test
, which uses Vaadin 24.4.0.beta3
. I also applied your change as a patch for HillaHintsRegistrar.java
, like you did in your project travel-tips
: https://github.com/marcushellberg/travel-tips/blob/main/src/main/java/com/vaadin/hilla/springnative/HillaHintsRegistrar.java.
Compiling the app into a native image using mvn clean package -Pproduction -Pnative native:compile
works fine. When I start the app as native image using ./target/native-image-test
, I'm getting an error and the following stack trace:
2024-05-16T22:40:51.950+02:00 ERROR 9183 --- [ main] c.v.hilla.route.ClientRouteRegistry : Failed to load file-routes.json from /META-INF/VAADIN/file-routes.json
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.vaadin.hilla.route.records.ClientViewMenuConfig`: cannot deserialize from Object value (no delegate- or property-based Creator): this appears to be a native image, in which case you may need to configure reflection for the class that is to be deserialized
at [Source: (ByteArrayInputStream); line: 1, column: 80] (through reference chain: java.util.ArrayList[0]->com.vaadin.hilla.route.records.ClientViewConfig["children"]->java.util.ArrayList[0]->com.vaadin.hilla.route.records.ClientViewConfig["menu"])
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1915) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:414) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1355) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1431) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) ~[na:na]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:359) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:129) ~[na:na]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:314) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer._deserializeFromArray(CollectionDeserializer.java:359) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:28) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4825) ~[native-image-test:2.15.4]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3817) ~[native-image-test:2.15.4]
at com.vaadin.hilla.route.ClientRouteRegistry.registerClientRoutes(ClientRouteRegistry.java:162) ~[native-image-test:na]
at com.vaadin.hilla.startup.RouteUnifyingServiceInitListener.serviceInit(RouteUnifyingServiceInitListener.java:101) ~[native-image-test:na]
at com.vaadin.flow.server.VaadinService.lambda$init$0(VaadinService.java:236) ~[native-image-test:24.4.0.beta3]
at [email protected]/java.util.Iterator.forEachRemaining(Iterator.java:133) ~[native-image-test:na]
at [email protected]/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1939) ~[na:na]
at [email protected]/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) ~[native-image-test:na]
at [email protected]/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) ~[native-image-test:na]
at [email protected]/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) ~[na:na]
at com.vaadin.flow.server.VaadinService.lambda$init$1(VaadinService.java:236) ~[native-image-test:24.4.0.beta3]
at com.vaadin.flow.server.VaadinService.runWithServiceContext(VaadinService.java:2372) ~[native-image-test:24.4.0.beta3]
at com.vaadin.flow.server.VaadinService.init(VaadinService.java:234) ~[native-image-test:24.4.0.beta3]
at com.vaadin.flow.spring.SpringVaadinServletService.init(SpringVaadinServletService.java:102) ~[na:na]
at com.vaadin.flow.spring.SpringServlet.createServletService(SpringServlet.java:115) ~[native-image-test:na]
at com.vaadin.flow.server.VaadinServlet.createServletService(VaadinServlet.java:336) ~[native-image-test:24.4.0.beta3]
at com.vaadin.flow.server.VaadinServlet.init(VaadinServlet.java:132) ~[native-image-test:24.4.0.beta3]
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:944) ~[na:na]
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:808) ~[na:na]
at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext.load(TomcatEmbeddedContext.java:84) ~[native-image-test:3.2.5]
at [email protected]/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) ~[na:na]
at [email protected]/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708) ~[na:na]
at [email protected]/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) ~[na:na]
at [email protected]/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) ~[na:na]
at [email protected]/java.util.TreeMap$ValueSpliterator.forEachRemaining(TreeMap.java:3250) ~[na:na]
at [email protected]/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[native-image-test:na]
at [email protected]/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[native-image-test:na]
at [email protected]/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[native-image-test:na]
at [email protected]/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[na:na]
at [email protected]/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[native-image-test:na]
at [email protected]/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[native-image-test:na]
at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext.lambda$deferredLoadOnStartup$0(TomcatEmbeddedContext.java:67) ~[native-image-test:3.2.5]
at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext.doWithThreadContextClassLoader(TomcatEmbeddedContext.java:108) ~[native-image-test:3.2.5]
at org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedContext.deferredLoadOnStartup(TomcatEmbeddedContext.java:66) ~[native-image-test:3.2.5]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.performDeferredLoadOnStartup(TomcatWebServer.java:329) ~[native-image-test:3.2.5]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:237) ~[native-image-test:3.2.5]
at org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:44) ~[na:na]
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:288) ~[native-image-test:6.1.6]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:471) ~[native-image-test:6.1.6]
at [email protected]/java.lang.Iterable.forEach(Iterable.java:75) ~[native-image-test:na]
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:260) ~[native-image-test:6.1.6]
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:205) ~[native-image-test:6.1.6]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:981) ~[native-image-test:6.1.6]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) ~[native-image-test:6.1.6]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[native-image-test:3.2.5]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[native-image-test:3.2.5]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[native-image-test:3.2.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[native-image-test:3.2.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) ~[native-image-test:3.2.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[native-image-test:3.2.5]
at com.example.application.Application.main(Application.java:20) ~[native-image-test:na]
at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH) ~[na:na]
Can you reproduce this?
Adding a runtime hint for ClientViewMenuConfig.class
makes it possible to start a starter created with hilla init --pre
. But there are no menu items visible, and trying to call the HelloWorldEndpoint
results in:
The program tried to reflectively invoke method
public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) without it being registered for runtime reflection.
Add public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) to the reflection metadata to solve this problem.
Adding this to registerHints
in HillaHintsRegistrar.java
hints.resources().registerPattern("file-routes.json");
hints.reflection().registerType(ClientViewConfig.class, MemberCategory.values());
hints.reflection().registerType(ClientViewMenuConfig.class, MemberCategory.values());
hints.reflection().registerType(AvailableViewInfo.class, MemberCategory.values());
results in a startup of a native compiled Hilla app without errors and I even see the menu items 😍
./target/native-image-test
_ _ _ _ _
_ __ __ _| |_(_)_ _____ (_)_ __ ___ __ _ __ _ ___ | |_ ___ ___| |_
| '_ \ / _` | __| \ \ / / _ \_____| | '_ ` _ \ / _` |/ _` |/ _ \_____| __/ _ \/ __| __|
| | | | (_| | |_| |\ V / __/_____| | | | | | | (_| | (_| | __/_____| || __/\__ \ |_
|_| |_|\__,_|\__|_| \_/ \___| |_|_| |_| |_|\__,_|\__, |\___| \__\___||___/\__|
|___/
2024-05-17T10:15:42.475+02:00 INFO 30849 --- [ main] com.example.application.Application : Starting AOT-processed Application using Java 21.0.2 with PID 30849 (/Users/rwilby/Documents/workspaces/hilla/native-image-test/target/native-image-test started by rwilby in /Users/rwilby/Documents/workspaces/hilla/native-image-test)
2024-05-17T10:15:42.475+02:00 INFO 30849 --- [ main] com.example.application.Application : No active profile set, falling back to 1 default profile: "default"
2024-05-17T10:15:42.499+02:00 INFO 30849 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2024-05-17T10:15:42.500+02:00 INFO 30849 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2024-05-17T10:15:42.500+02:00 INFO 30849 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.20]
2024-05-17T10:15:42.511+02:00 INFO 30849 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2024-05-17T10:15:42.511+02:00 INFO 30849 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 36 ms
2024-05-17T10:15:42.531+02:00 INFO 30849 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing AtmosphereFramework
2024-05-17T10:15:42.608+02:00 WARN 30849 --- [ main] o.a.cpr.DefaultAnnotationProcessor : Unable to detect annotations. Application may fail to deploy.
2024-05-17T10:15:42.609+02:00 INFO 30849 --- [ main] c.v.f.s.DefaultDeploymentConfiguration : Vaadin is running in production mode.
2024-05-17T10:15:42.610+02:00 INFO 30849 --- [ main] c.vaadin.flow.spring.SpringInstantiator : The number of beans implementing 'I18NProvider' is 0. Cannot use Spring beans for I18N, falling back to the default behavior
2024-05-17T10:15:42.614+02:00 INFO 30849 --- [ main] com.vaadin.flow.server.Platform : Unable to determine Hilla version. No META-INF/maven/com.vaadin/hilla/pom.properties found
2024-05-17T10:15:42.616+02:00 INFO 30849 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path ''
2024-05-17T10:15:42.616+02:00 INFO 30849 --- [ main] com.example.application.Application : Started Application in 0.167 seconds (process running for 0.183)
2024-05-17T10:15:47.513+02:00 INFO 30849 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-05-17T10:15:47.513+02:00 INFO 30849 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-05-17T10:15:47.514+02:00 INFO 30849 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms
Invoking com.example.application.services.HelloWorldService.sayHello
by using the Say hello
results in the following stack trace:
2024-05-17T10:19:31.135+02:00 ERROR 30849 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed: org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively invoke method public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) without it being registered for runtime reflection. Add public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.] with root cause
org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively invoke method public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) without it being registered for runtime reflection. Add public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.
at org.graalvm.nativeimage.builder/com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils.forQueriedOnlyExecutable(MissingReflectionRegistrationUtils.java:72) ~[na:na]
at [email protected]/java.lang.reflect.Method.acquireMethodAccessor(Method.java:77) ~[native-image-test:na]
at [email protected]/java.lang.reflect.Method.invoke(Method.java:577) ~[native-image-test:na]
at com.vaadin.hilla.EndpointInvoker.invokeVaadinEndpointMethod(EndpointInvoker.java:439) ~[native-image-test:na]
at com.vaadin.hilla.EndpointInvoker.invoke(EndpointInvoker.java:207) ~[native-image-test:na]
at com.vaadin.hilla.EndpointController.serveEndpoint(EndpointController.java:199) ~[native-image-test:na]
at [email protected]/java.lang.reflect.Method.invoke(Method.java:580) ~[native-image-test:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) ~[native-image-test:6.1.6]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[native-image-test:6.1.6]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) ~[native-image-test:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[native-image-test:6.1.6]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[native-image-test:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:206) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[native-image-test:10.1.20]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[native-image-test:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[native-image-test:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[native-image-test:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[native-image-test:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[native-image-test:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[native-image-test:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[na:na]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[na:na]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[native-image-test:10.1.20]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[na:na]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[native-image-test:10.1.20]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[na:na]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[na:na]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[na:na]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[native-image-test:10.1.20]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[na:na]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736) ~[na:na]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[native-image-test:10.1.20]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[na:na]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[na:na]
at [email protected]/java.lang.Thread.runWith(Thread.java:1596) ~[native-image-test:na]
at [email protected]/java.lang.Thread.run(Thread.java:1583) ~[native-image-test:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:833) ~[native-image-test:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211) ~[na:na]
Progress!
I wonder what has changed in calling endpoints. It used to work. Have we changed how endpoints are being called?
I just realized that AvailableViewInfo
and ClientViewMenuConfig
no longer exist due to https://github.com/vaadin/hilla/pull/2425 😞. I think, I have to give it another try with beta4.
The AvailableViewInfo
from Hilla is replaced with com.vaadin.flow.server.menu.AvailableViewInfo
so we probably need to register that instead. Also, instead of ClientViewMenuConfig
we should register com.vaadin.flow.router.MenuData
.
Have we changed how endpoints are being called?
I don't recall any change in that zone. The stacktrace points to this method invocation that uses the reflection API, but the code hasn't changed since early 2022.
This is the code that is supposed to register all needed types for endpoints: https://github.com/vaadin/hilla/blob/8f142a3f43662405160b920710f7bef5a5290004/packages/java/endpoint/src/main/java/com/vaadin/hilla/springnative/HillaHintsRegistrar.java#L56-L79
Well, looking at the above code, it tries to read the open api json from /hilla-openapi.json
which means the root of target/classes
, and while reading it from this location works for registerEndpoints
at a normal PROD mode, it seems that if fails during the native build (the following is from my local build of the native IT project):
Then, obviously it fails to call the endpoint's method at runtime since no methods has been registered during the build.
What is weird is:
- When I look at the
target/classes
thehilla-openapi.json
is there, so why it fails to load it? - How this was working before? I know that
hilla-openapi.json
was atclasses/com/vaadin/hilla/openapi.json
, so previously it was being loaded from/com/vaadin/hilla/openapi.json
, and recently we moved it to the root oftarget/classes
and renamed ithilla-openapi.json
. How is it different for the resource loader? Is-
in the name of the file the culprit? If so, how is fine in EndpointRegisteryInitializer?
It seems that the -
in the file name of hilla-openapi.json
was somehow making it inaccessible to the class/resource loader at the time of native build, even though, it is working fine during a normal PROD runtime. I changed it locally to hillaopenapi.json
and this time I didn't get that error log during the build.
Nope :( It is happening again (though I had a successful native build earlier):
I suspected that timing might be the issue, for instance when that the open api json is not yet available during the native build, but it created during the production build much earlier than the native build is getting started.
I've noticed a weird pattern of having "Resource /hilla-openapi.json is not available" during the native build:
If I change the resource name e.g. from hilla-openapi.json
to hillaopenapi.json
and vice versa (in the Hilla repo), next time I clean & build hilla/packages/java/tests/spring/native
, I don't get the above mentioned error log, but any consequent clean & build would get the same error, but surprizingly, the endpoints are working in both cases. Probably, that registerEndpointTypes
method is being called more than once (for some reason that I don't no yet, need to debug) and the second time that resource is available and it can register the endpoint types. Easiest way of debugging would be to add an info log for the times that it finds the resource, then the users can also see what's happening during the build.
Well, as suspected, adding a log shows when registerEndpointTypes
is called on the second round of spring-boot startup (during the native build) the /hilla-openapi.json
resource is available and that's why the endpoints are working fine in hilla/packages/java/tests/spring/native
:
Still, it could be investigated that why a change of name in hilla-openapi.json
file makes it available in the first run as well (so no "Resource /hilla-openapi.json is not available" is flushed out), but it is not a priority at the moment.
Quality Gate passed
Issues
0 New issues
0 Accepted issues
Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code
I pushed the changes needed for a Vaadin/Hilla 24.4 applications to work with the dynamic menu.
If someone wants to run the native build in hilla/packages/java/tests/spring/native
, they need to add <enforcer.skip>true</enforcer.skip>
to the properties since there are internal convergence issues with the testbech ATM.
For applications with security enabled, there is another runtime issue that should be addressed in Flow.
Hi @taefi,
is there already an issue where you try to fix the problem when calling endpoints, as discussed here: https://github.com/vaadin/hilla/pull/2396#issuecomment-2117188338? Using beta4 I still get this error, when I try to invoke HelloWorldService.sayHello
:
2024-05-23T13:41:31.953+02:00 ERROR 56424 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed: org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively invoke method public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) without it being registered for runtime reflection. Add public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.] with root cause
org.graalvm.nativeimage.MissingReflectionRegistrationError: The program tried to reflectively invoke method public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) without it being registered for runtime reflection. Add public java.lang.String com.example.application.services.HelloWorldService.sayHello(java.lang.String) to the reflection metadata to solve this problem. See https://www.graalvm.org/latest/reference-manual/native-image/metadata/#reflection for help.
at org.graalvm.nativeimage.builder/com.oracle.svm.core.reflect.MissingReflectionRegistrationUtils.forQueriedOnlyExecutable(MissingReflectionRegistrationUtils.java:72) ~[na:na]
at [email protected]/java.lang.reflect.Method.acquireMethodAccessor(Method.java:77) ~[native-image-test:na]
at [email protected]/java.lang.reflect.Method.invoke(Method.java:577) ~[native-image-test:na]
at com.vaadin.hilla.EndpointInvoker.invokeVaadinEndpointMethod(EndpointInvoker.java:440) ~[native-image-test:na]
at com.vaadin.hilla.EndpointInvoker.invoke(EndpointInvoker.java:207) ~[native-image-test:na]
at com.vaadin.hilla.EndpointController.serveEndpoint(EndpointController.java:194) ~[native-image-test:na]
at [email protected]/java.lang.reflect.Method.invoke(Method.java:580) ~[native-image-test:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) ~[native-image-test:6.1.6]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[native-image-test:6.1.6]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[native-image-test:6.1.6]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) ~[native-image-test:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[native-image-test:6.1.6]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[native-image-test:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:206) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[native-image-test:10.1.20]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[native-image-test:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[native-image-test:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[native-image-test:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[native-image-test:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[native-image-test:6.1.6]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[native-image-test:6.1.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:175) ~[na:na]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:150) ~[na:na]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[na:na]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[na:na]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[native-image-test:10.1.20]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[na:na]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[native-image-test:10.1.20]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[na:na]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[na:na]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[na:na]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[native-image-test:10.1.20]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[na:na]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736) ~[na:na]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[native-image-test:10.1.20]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[na:na]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[na:na]
at [email protected]/java.lang.Thread.runWith(Thread.java:1596) ~[native-image-test:na]
at [email protected]/java.lang.Thread.run(Thread.java:1583) ~[native-image-test:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:833) ~[native-image-test:na]
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211) ~[na:na]
Ah. Good that you reminded of that. It's not fixed, but needs to be fixed https://github.com/vaadin/hilla/issues/2461
This ticket/PR has been released with Hilla 24.5.0.alpha1 and is also targeting the upcoming stable 24.5.0 version.