graphql-java-kickstart / graphql-java-tools

A schema-first tool for graphql-java inspired by graphql-tools for JS
https://www.graphql-java-kickstart.com/tools/
MIT License
810 stars 174 forks source link

graphql.AssertException is being thrown where previously it wasn't #780

Open TsvetomirValchev opened 7 months ago

TsvetomirValchev commented 7 months ago

Description

With a schema like this

Previously we could execute a query like:

query quests {
  quests(
    filter: {
      states: ["ONGOING"]
    }
  ) {
    questId
  }
}

Now whenever there is an existing entry that is child of Questline in the database in the specific state that you query for, an error is thrown ( so let's say there is an entry in the database for EpicQuestline that has status ONGOING, if you query for status: ONGOING ) , it would throw an error:

graphql.AssertException: You have asked for named object type 'Questline' but it's not an object type but rather a 'graphql.schema.GraphQLInterfaceType'
    at graphql.Assert.assertTrue(Assert.java:78)
    at graphql.schema.GraphQLSchema.getObjectType(GraphQLSchema.java:295)
    at graphql.kickstart.tools.DictionaryTypeResolver.getType(DictionaryTypeResolver.kt:27)
    at graphql.execution.ResolveType.resolveAbstractType(ResolveType.java:62)
    at graphql.execution.ResolveType.resolveTypeForInterface(ResolveType.java:53)
    at graphql.execution.ResolveType.resolveType(ResolveType.java:39)
    at graphql.execution.ExecutionStrategy.resolveType(ExecutionStrategy.java:720)
    at graphql.execution.ExecutionStrategy.completeValue(ExecutionStrategy.java:483)
    at graphql.execution.ExecutionStrategy.completeValueForList(ExecutionStrategy.java:586)
    at graphql.execution.ExecutionStrategy.completeValueForList(ExecutionStrategy.java:543)
    at graphql.execution.ExecutionStrategy.completeValue(ExecutionStrategy.java:469)
    at graphql.execution.ExecutionStrategy.completeField(ExecutionStrategy.java:435)
    at graphql.execution.ExecutionStrategy.lambda$resolveFieldWithInfo$1(ExecutionStrategy.java:215)
    at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:684)
    at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:662)
    at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2168)
    at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:214)
    at graphql.execution.AsyncExecutionStrategy.execute(AsyncExecutionStrategy.java:55)
    at graphql.execution.Execution.executeOperation(Execution.java:161)
    ... 126 common frames omitted

Additional information:

A colleague of mine mentioned that this issue seems familiar to him and last time something like this was encountered the solution was somewhere in the dependency versions of hibernate-orm plugin and graphql-enhance plugin ( they were incompatible and once the versions were matched the issue was fixed.) This is currently not the case since i checked the versions of the aforementioned dependencies and it seems the issue is coming from somewhere else.

A list of all concrete Quest/Questline objects that inherit the Quest interface ( i.e. a list that has EpicQuestline and SpecificQuest from the example schema ).

A graphql.AssertException saying You have asked for named object type 'Questline' but it's not an object type but rather a 'graphql.schema.GraphQLInterfaceType' is thrown instead .

Steps to reproduce the bug

  1. Have a similar schema

  2. Have a query like:

query quests {
  quests(
    filter: {
      states: ["ONGOING"]
    }
  ) {
    questId
  }
}
  1. A resolver function like : this

Note: The repository provided above might not have enough information. If you need more information please let me know and I will provide it to the best of my ability and ASAP.

Since this is one of the first ever github issues in my career please excuse my negligence!

TsvetomirValchev commented 6 months ago

Hello!

is there any updates on this?

drewhk commented 5 months ago

Hi @TsvetomirValchev, I am not sure it helps you, but I had a similar problem when using Hibernate. The issue was that the returned object was actually a Hibernate proxy object, that is a type subclassing the original interface, but not belonging to the set of subtypes GraphQL kickstart knows (since the proxy class is generated at runtime). If you use Hibernate lazy loading, or any other library that may proxy your original objects you might experience this strange issue. I am not sure if this is the case for you, but maybe a future reader is unblocked by my comment :)

TsvetomirValchev commented 5 months ago

Hi @drewhk! Do you mind sharing how you fixed it ? I think you might have hit the spot for why this issue is happening but I could not work out a way to fix it. A colleague of mine previously told me there was a similar issue and it was something related to some libraries' interaction with Hibernate.

drewhk commented 5 months ago

So, in my case there was a GraphQL type Outer which had a field inner of interface type Inner. Since this field was lazy loaded, I had to create a FieldResolver<Outer> with a getInner method that just took the inner field of the object and called Hibernate.unproxy on it. That is I did not expose the inner field directly (as it could contain a proxy), but wrapped the access in a dedicated field resolver that just unproxied the object in that field. Sorry if it is a bit terse, I am in a hurry right now :)

TsvetomirValchev commented 5 months ago

Thank you for the fast response i will try this fix and will post an update if it fixed my issue as well! Thanks again!