quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.64k stars 2.64k forks source link

Unable to use Panache Sort.Direction enum as method parameter for GraphQL query #36688

Open mzuber opened 11 months ago

mzuber commented 11 months ago

Describe the bug

Using the Sort.Direction enum from the quarkus-hibernate-orm-panache extension as a method parameter for a GraphQL query defined with the quarkus-smallrye-graphql extension results in a startup failure when Quarkus tries to generate the schema of the exposed GraphQL API at application startup:

2023-10-25 14:30:49,999 WARN  [io.sma.gra.sch.cre.ReferenceCreator] (build-27) Class [io.quarkus.panache.common.Sort$Direction] is not indexed in Jandex. Can not scan Object Type, might not be mapped correctly. Kind = [CLASS]
2023-10-25 14:30:52,088 ERROR [io.qua.run.boo.StartupActionImpl] (Quarkus Main Thread) Error running Quarkus: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:113)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ExceptionInInitializerError
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)
        ... 6 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
        at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)
        ... 15 more
Caused by: graphql.AssertException: type Direction not found in schema
        at graphql.Assert.assertNotNull(Assert.java:17)
        at graphql.schema.GraphQLTypeResolvingVisitor.handleTypeReference(GraphQLTypeResolvingVisitor.java:49)
        at graphql.schema.GraphQLTypeResolvingVisitor.visitGraphQLTypeReference(GraphQLTypeResolvingVisitor.java:44)
        at graphql.schema.GraphQLTypeReference.accept(GraphQLTypeReference.java:62)
        at graphql.schema.SchemaTraverser$TraverserDelegateVisitor.enter(SchemaTraverser.java:109)
        at graphql.util.Traverser.traverse(Traverser.java:144)
        at graphql.schema.SchemaTraverser.doTraverse(SchemaTraverser.java:96)
        at graphql.schema.SchemaTraverser.depthFirst(SchemaTraverser.java:86)
        at graphql.schema.SchemaTraverser.depthFirst(SchemaTraverser.java:79)
        at graphql.schema.impl.SchemaUtil.replaceTypeReferences(SchemaUtil.java:105)
        at graphql.schema.GraphQLSchema$Builder.buildImpl(GraphQLSchema.java:938)
        at graphql.schema.GraphQLSchema$Builder.build(GraphQLSchema.java:904)
        at io.smallrye.graphql.bootstrap.Bootstrap.generateGraphQLSchema(Bootstrap.java:205)
        at io.smallrye.graphql.bootstrap.Bootstrap.bootstrap(Bootstrap.java:120)
        at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:52)
        at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:42)
        at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:32)
        at io.smallrye.graphql.cdi.producer.GraphQLProducer.initialize(GraphQLProducer.java:27)
        at io.smallrye.graphql.cdi.producer.GraphQLProducer_ClientProxy.initialize(Unknown Source)
        at io.quarkus.smallrye.graphql.runtime.SmallRyeGraphQLRecorder.createExecutionService(SmallRyeGraphQLRecorder.java:30)
        at io.quarkus.deployment.steps.SmallRyeGraphQLProcessor$buildExecutionService1691419614.deploy_7(Unknown Source)
        at io.quarkus.deployment.steps.SmallRyeGraphQLProcessor$buildExecutionService1691419614.deploy(Unknown Source)
        ... 16 more

Expected behavior

It is possible to use the Sort.Direction enum from the quarkus-hibernate-orm-panache as a method parameter for a GraphQL query.

Actual behavior

The quarkus-smallrye-graphql extension is unable to generate the schema of the exposed GraphQL API at application startup. Before the startup failure the warning Class [io.quarkus.panache.common.Sort$Direction] is not indexed in Jandex. Can not scan Object Type, might not be mapped correctly. Kind = [CLASS] is logged.

How to Reproduce?

In a Quarkus application using both the quarkus-hibernate-orm-panache and the quarkus-smallrye-graphql extension, define a GraphQL API using the Sort.Direction enum in a query definition:

@GraphQLApi
public class DemoResource {

    @Query("sortDirection")
    public String testPanacheSortDirectionEnum(Sort.Direction sortDirection) {
        return sortDirection.name();
    }
}

Output of uname -a or ver

No response

Output of java -version

openjdk version "17.0.7" 2023-04-18 OpenJDK Runtime Environment GraalVM CE 17.0.7+7.1 (build 17.0.7+7-jvmci-23.0-b12) OpenJDK 64-Bit Server VM GraalVM CE 17.0.7+7.1 (build 17.0.7+7-jvmci-23.0-b12, mixed mode, sharing)

Quarkus version or git rev

3.4.3

Build tool (ie. output of mvnw --version or gradlew --version)

Gradle 8.3

Additional information

No response

quarkus-bot[bot] commented 11 months ago

/cc @FroMage (panache), @jmartisk (graphql), @loicmathieu (panache), @phillip-kruger (graphql)

jmartisk commented 11 months ago

When using classes from a dependency inside your graphql api, that dependency must be explicitly added to the index (with few exceptions) Try adding this to your configuration

quarkus.index-dependency.panache.group-id=io.quarkus
quarkus.index-dependency.panache.artifact-id=quarkus-panache-common
gsmet commented 11 months ago

It looks like an usage that could be common, I'm thinking we could add this enum to the index automatically.

jmartisk commented 11 months ago

Yeah that makes sense I guess. @mskacelik will create a PR with that

gsmet commented 11 months ago

@mskacelik the idea would be to use AdditionalIndexedClassesBuildItem in the Panache module.

jmartisk commented 11 months ago

Why in Panache? Don't we want this in GraphQL, because it's most likely needed because of using it inside a GraphQL api?

gsmet commented 11 months ago

I'm not sure if we have a capability for Panache but if we have one (or if you feel like adding one) then yes we can do it in Panache GraphQL. But I think the class needs to be in the classpath to be added to the index so you need to check (and let's not check with a class loader call if we can avoid it).

mzuber commented 11 months ago

When using classes from a dependency inside your graphql api, that dependency must be explicitly added to the index (with few exceptions) Try adding this to your configuration

quarkus.index-dependency.panache.group-id=io.quarkus
quarkus.index-dependency.panache.artifact-id=quarkus-panache-common

@jmartisk Thanks, this did the trick. Do you think there is value in adding a note to the SmallRye GraphQL guide on this? Happy to provide a PR.

jmartisk commented 11 months ago

@gsmet There are capabilities for MONGODB_PANACHE and MONGODB_PANACHE_KOTLIN. I assume we could add separate capabilities for HIBERNATE_ORM_PANACHE, HIBERNATE_REACTIVE_PANACHE, HIBERNATE_ORM_PANACHE_KOTLIN, HIBERNATE_REACTIVE_PANACHE_KOTLIN and assume that if one of these six is present, then the class is present? We wanted to simply use QuarkusClassLoader.isClassPresentAtRuntime, is that bad?

@mzuber we could add something to additional notes (https://quarkus.io/guides/smallrye-graphql#additional-notes), probably not specifically about Panache, but more generally about using stuff from dependencies. This specific case might go away if we really start adding that enum into the index automatically.

phillip-kruger commented 3 weeks ago

I don't think GraphQL needs this info ? Maybe the fix is the GraphQL just ignore the error ? If possible ?

FroMage commented 2 weeks ago

Well, can it work with this error? What does the graphql look like if the error is ignored? If that causes the method to be ignored, that's probably not what we want, no?