spring-projects / spring-graphql

Spring Integration for GraphQL
https://spring.io/projects/spring-graphql
Apache License 2.0
1.52k stars 298 forks source link

Spring Devtools Restart feature causes cast exceptions #629

Closed koenpunt closed 1 year ago

koenpunt commented 1 year ago

I haven't been seeing these consistently until recently. Is it not expected to work the RestartClassLoader, or is there something in the class casting that has changed that caused this now to fail?

java.lang.ClassCastException: class oopen.timemachine.graphql.model.MerchantConnection cannot be cast to class oopen.timemachine.graphql.model.MerchantConnection (oopen.timemachine.graphql.model.MerchantConnection is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @3af7cbcf; oopen.timemachine.graphql.model.MerchantConnection is in unnamed module of loader 'app')
bclozel commented 1 year ago

I haven't seen those while using devtools lately, but I suspected that this could happen. Which spring-graphql and graphql-java versions are you using? I think that graphql-java loads and reflects on application classes and doing so from different classloaders can cause issues like this. I think this is even more likely to happen with graphql-java 20.0, like in graphql-java/graphql-java#3086.

For this case, I think you should bring the app classes and graphql-java on the same classloader. As explained in the Spring Boot ref docs on the restart classloader, adding a META-INF/spring-devtools.properties with the following content should help:

restart.include.graphqljava=/graphql-java-[\\w\\d-\\.]+\\.jar

I'm assuming that those oopen.timemachine.graphql.model classes are in the main application. If not, you should bring that dependency in the restart classloader as well.

Can you try that and report back?

koenpunt commented 1 year ago

Thanks for that info.

We're using spring-graphql 1.1.1 and graphql-java 20.0.

Unfortunately adding the spring-devtools.properties file causes errors at startup;

Caused by: java.lang.IllegalStateException: Failed to introspect Class [org.springframework.graphql.execution.DataFetcherExceptionResolverAdapter] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@7b1d7fff]
 ....
Caused by: java.lang.LinkageError: loader constraint violation: loader 'app' wants to load interface graphql.schema.DataFetchingEnvironment. A different interface with the same name was previously loaded by org.springframework.boot.devtools.restart.classloader.RestartClassLoader @7e046dbe. (graphql.schema.DataFetchingEnvironment is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @7e046dbe, parent loader 'app')
bclozel commented 1 year ago

This issue is superseded by graphql-java/graphql-java#3086 and graphql-java/graphql-java#3095. I've tested the same scenario with graphql-java 20.1 and devtools works fine without any spring-devtools.properties file.