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

Ahead Of Time support #495

Closed
4 tasks done
bclozel opened this issue Sep 22, 2022 · 14 comments
Closed
4 tasks done

Ahead Of Time support #495

bclozel opened this issue Sep 22, 2022 · 14 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@bclozel
Copy link
Member

bclozel commented Sep 22, 2022

Since Spring Framework has been working on AOT and GraalVM Native Image support, we should consider improvements to make this work in time for 1.1.0.

Right now we're identifying several tasks:

@rafallezanko
Copy link

rafallezanko commented Oct 26, 2022

Hi @bclozel , I have meet another issue with opening GraphlQL websocket using webflux stack when I run native application. From my briftly analysis it looks like there is missing dependency or missing hint.

I don't know where should I report an issue? Just here is enough, or maybe create another one?

I have prepared simple repository where you can see full configuration of project and fell free to try yourself. Please find the link below: https://github.com/rafallezanko/spring_native_graphql_error_example/tree/master

When I start application I receive No JSON Encoder exception from CodecDelegate class:

> Task :nativeRun FAILED

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v3.0.0-SNAPSHOT)

2022-10-26T21:46:12.237+02:00  INFO 19650 --- [           main] com.example.demo.DemoApplicationKt       : Starting AOT-processed DemoApplicationKt using Java 17.0.4 on mbpro-rafallezanko.local with PID 19650 (/Users/rafallezanko/Downloads/demo/build/native/nativeCompile/demo started by rafallezanko in /Users/rafallezanko/Downloads/demo)
2022-10-26T21:46:12.237+02:00  INFO 19650 --- [           main] com.example.demo.DemoApplicationKt       : No active profile set, falling back to 1 default profile: "default"
2022-10-26T21:46:12.267+02:00  INFO 19650 --- [           main] .b.a.g.r.GraphQlWebFluxAutoConfiguration : GraphQL endpoint HTTP POST /graphql
2022-10-26T21:46:12.269+02:00  WARN 19650 --- [           main] .r.c.ReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webHandler': Error creating bean with name 'graphQlWebSocketEndpoint': Unsatisfied dependency expressed through method 'graphQlWebSocketEndpoint' parameter 0: Error creating bean with name 'graphQlWebSocketHandler': Instantiation of supplied bean failed
2022-10-26T21:46:12.269+02:00 ERROR 19650 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webHandler': Error creating bean with name 'graphQlWebSocketEndpoint': Unsatisfied dependency expressed through method 'graphQlWebSocketEndpoint' parameter 0: Error creating bean with name 'graphQlWebSocketHandler': Instantiation of supplied bean failed
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:606) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:931) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:916) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[demo:3.0.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[demo:3.0.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[demo:3.0.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[demo:3.0.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[demo:3.0.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[demo:3.0.0-SNAPSHOT]
	at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:13) ~[demo:na]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'graphQlWebSocketEndpoint': Unsatisfied dependency expressed through method 'graphQlWebSocketEndpoint' parameter 0: Error creating bean with name 'graphQlWebSocketHandler': Instantiation of supplied bean failed
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:365) ~[na:na]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:281) ~[na:na]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:209) ~[na:na]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:662) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1285) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:368) ~[na:na]
	at org.springframework.web.reactive.DispatcherHandler.initStrategies(DispatcherHandler.java:120) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.web.reactive.DispatcherHandler.setApplicationContext(DispatcherHandler.java:115) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:109) ~[na:na]
	at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:85) ~[na:na]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:420) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1745) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[demo:6.0.0-SNAPSHOT]
	... 15 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'graphQlWebSocketHandler': Instantiation of supplied bean failed
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1236) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1375) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1295) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:348) ~[na:na]
	... 36 common frames omitted
Caused by: java.lang.IllegalArgumentException: No JSON Encoder
	at org.springframework.graphql.server.webflux.CodecDelegate.lambda$findJsonEncoder$5(CodecDelegate.java:77) ~[na:na]
	at java.util.Optional.orElseThrow(Optional.java:403) ~[demo:na]
	at org.springframework.graphql.server.webflux.CodecDelegate.findJsonEncoder(CodecDelegate.java:77) ~[na:na]
	at org.springframework.graphql.server.webflux.CodecDelegate.<init>(CodecDelegate.java:61) ~[na:na]
	at org.springframework.graphql.server.webflux.GraphQlWebSocketHandler.<init>(GraphQlWebSocketHandler.java:92) ~[demo:1.1.0-RC1]
	at org.springframework.boot.autoconfigure.graphql.reactive.GraphQlWebFluxAutoConfiguration$WebSocketConfiguration.graphQlWebSocketHandler(GraphQlWebFluxAutoConfiguration.java:161) ~[demo:na]
	at org.springframework.boot.autoconfigure.graphql.reactive.GraphQlWebFluxAutoConfiguration__BeanDefinitions$WebSocketConfiguration__BeanDefinitions.lambda$getGraphQlWebSocketHandlerInstanceSupplier$0(GraphQlWebFluxAutoConfiguration__BeanDefinitions.java:109) ~[na:na]
	at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:212) ~[na:na]
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) ~[demo:6.0.0-SNAPSHOT]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:224) ~[na:na]
	at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:211) ~[na:na]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[demo:6.0.0-SNAPSHOT]
	... 48 common frames omitted

19 actionable tasks: 19 executed

FAILURE: Build failed with an exception.

sbrannen added a commit to spring-projects/spring-framework that referenced this issue Oct 28, 2022
As can be seen in a modified version of the following example project,
attempting to access a resource discovered via classpath scanning
within a GraalVM native image -- for example via the Files.exists(...)
invocation in FileSystemResource -- currently results in a
ClosedFileSystemException since PathMatchingResourcePatternResolver
explicitly closes the native image FileSystem that backs `resource:`
resources.

Sample project: https://github.com/joshlong/spring-boot-3-aot-graphql

To address this issue, this commit removes the explicit close()
invocation for custom FileSystems after classpath scanning in
PathMatchingResourcePatternResolver.

See spring-projects/spring-graphql#495
Closes gh-29397
@bclozel
Copy link
Member Author

bclozel commented Oct 31, 2022

@rafallezanko this issue is still opened, so GraalVM Native is not supported yet with Spring for GraphQL.

@bclozel
Copy link
Member Author

bclozel commented Nov 15, 2022

This is now resolved, but actual support in Spring Boot applications requires:

@rafallezanko
Copy link

Hi @bclozel, have you tried with enabled web socket in web flux project?

Application could not be able to start when I add the following property
spring.graphql.websocket.path=/graphql

I have attached error in my previous post in the issue. I have upgraded project to newest version of Spring and I have added metadata repository:
graalvmNative { metadataRepository { enabled.set(true) version.set("0.2.5") } }

@susimsek
Copy link

Hi @bclozel, Can you provide aot support for graphql-java-extended-scalars and graphql-java-extended-validation?
I'm using these libraries with spring graphql. when I run the native application, i am getting an error like this.

image

@bclozel
Copy link
Member Author

bclozel commented Nov 25, 2022

Thanks for reaching out @rafallezanko @susimsek I'll have a look and report back here.

@bclozel
Copy link
Member Author

bclozel commented Dec 2, 2022

@rafallezanko I've reproduced the WebSocket+Native issue and created #560 to solve it.

@rafallezanko
Copy link

Hi @bclozel , good to know. Thank you a lot!

@bclozel
Copy link
Member Author

bclozel commented Dec 16, 2022

Sorry for the late reply @susimsek

I've had a look at graphql-java-extended-scalars and it seems to work fine in a native image without any change.
As for graphql-java-extended-validation, I've submitted the following PR to the reachability metadata repository. In the meantime, you can add the json files listed here in the following folder in your application: src/main/resource/META-INF/native-image/com.graphql-java/graphql-java-extended-validation/.

@susimsek
Copy link

susimsek commented Dec 22, 2022

Hi @bclozel . I noticed that the reflection config for DataFetchingEnvironmentImpl is missing.Locale information is not handled correctly.I fixed this problem in this repo. it seems to be working fine now. Can you add missing reflection config to the reachability metadata repository.

@bclozel
Copy link
Member Author

bclozel commented Dec 22, 2022

@susimsek before I can add it to the repository, I need a failing test that shows the need for this entry. Any hint on how to reproduce this missing metadata? Do you have a stacktrace that shows what's doing the reflection?

@susimsek
Copy link

susimsek commented Dec 22, 2022

@bclozel line 71 of this class always returns null. Reflection is used in line 71. Since locale returns null, they always assigned the default locale on 35 lines.I noticed it while reviewing the github repo.i don't have a stacktrace.

@scmdmo
Copy link

scmdmo commented Sep 21, 2023

Hi @bclozel, is this issue with GraphQL fully fixed or is possible there is a regression?

I'm using Spring Boot 3.1.3 together with Graalvm 22.3.1. Use GraphQL from client side app compiled in native, as indicated in docs (https://docs.spring.io/spring-graphql/reference/graalvm-native.html#graalvm.client) I included @RegisterReflectionForBinding with my DTO type

However still get a No JSON Encoder error

Caused by: java.lang.IllegalArgumentException: No JSON Encoder
	at org.springframework.graphql.client.CodecDelegate.lambda$findJsonEncoder$5(CodecDelegate.java:85)
	at java.base@17.0.8/java.util.Optional.orElseThrow(Optional.java:403)
	at org.springframework.graphql.client.CodecDelegate.findJsonEncoder(CodecDelegate.java:85)
	at org.springframework.graphql.client.CodecDelegate.findJsonEncoder(CodecDelegate.java:62)
	at org.springframework.graphql.client.DefaultHttpGraphQlClientBuilder.lambda$build$0(DefaultHttpGraphQlClientBuilder.java:110)
	at org.springframework.web.reactive.function.client.DefaultExchangeStrategiesBuilder.codecs(DefaultExchangeStrategiesBuilder.java:63)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.lambda$codecs$0(DefaultWebClientBuilder.java:257)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.lambda$initExchangeStrategies$1(DefaultWebClientBuilder.java:361)
	at java.base@17.0.8/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.initExchangeStrategies(DefaultWebClientBuilder.java:361)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.build(DefaultWebClientBuilder.java:314)
	at org.springframework.graphql.client.DefaultHttpGraphQlClientBuilder.build(DefaultHttpGraphQlClientBuilder.java:113)

All my tries to fix it were unsuccessful, I'm running out of ideas and no clue why still fails.

@bclozel
Copy link
Member Author

bclozel commented Sep 21, 2023

Can you create a new issue and share a minimal sample? Maybe a reflection hint is missing, I can have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants