Repository navigation
Allow resolver methods that leave out the source object - #904
Merged
Merged
Conversation
|
Collaborator
Author
|
Verifier: PASS+NOTES on e0dc4f4 (vs master 84dcb8e), through the installed jar in a consumer project, graphql-java 26.1 and 25.1 at runtime.
Note: with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes #304
Checklist
Description
A
GraphQLResolver<T>method has to take the source as its first parameter, even when it doesn't need it. The case from the issue is a child field that only reads what its parent put inlocalContext:Now a resolver method can leave out the source if it ends in at least one
DataFetchingEnvironment,GraphQLContextor context class parameter, after the field's arguments (thumbnail(size: Int, env)). Without one (imageBlob()), it's still not a match, so helpers and Kotlin property getters on resolvers don't suddenly become resolvers.These methods are only looked at where the build fails today with "No method found", so nothing that builds today binds differently:
Image.getName()beatsImageResolver.name(env)) and a method that takes the source (title(image)beatstitle(env)). So it doesn't follow "resolver before data class", which I'd have liked, but that would rebind fields that work todayallowUnimplementedResolvers,missingResolverDataFetcherormissingResolverDataFetcherProviderset, a missing field still gets the missing resolver fetcher. Otherwise a helper likepreview(env)would take over a field that builds today. So the feature doesn't work with those options, which is the main limitation hereA method is also rejected (so it keeps failing at build time instead of failing every query) when an argument would land on an environment or context parameter (
thumbnail(context: GraphQLContext, env)forthumbnail(size: Int), the #890 warning), or when its first parameter could be the source (title(source: Any, env)ortitle(item: Item, env)onGraphQLResolver<Book>), since that's most likely a mistyped source. Because of the first rule, valid methods never trigger the #890 warning, and it still fires where it did. The "No method found" error now also lists the forms without the source, e.g.ImageResolver.thumbnail(~size, <environment or context>).The first commit makes "does parameter 0 take the source?" a single decision. The scanner decided it from the search and
MethodFieldResolver.getIndexOffsetdecided it again from the method's declaring class. They only disagreed when the method is declared by the data class itself (or a class both extend), e.g.class Badge : GraphQLResolver<Badge>. Those schemas build but every query of the field fails withCannot construct instance of Badge, and now they work.Release note: a resolver method can leave out the source object when it ends in a
DataFetchingEnvironment,GraphQLContextor context class parameter, e.g.fun imageBlob(env: DataFetchingEnvironment)in aGraphQLResolver<Image>. It's only used when nothing else matches the field, and not whenallowUnimplementedResolversor a missing resolver data fetcher is set.SourcelessResolverTesthas 14 cases, 6 of them fail without this change and the rest pin what must not change (getter and overload precedence, root ambiguity, the missing resolver options, rejected methods). TheBadgecase is inMethodFieldResolverTestand fails without it too.mvn clean verifypasses on JDK 25 against graphql-java 26.1 and 25.1 (398 tests), and on JDK 11 (397).Also checked through the installed jar in a separate consumer project, on graphql-java 26.1 and 25.1 at runtime: env with
localContext, an argument plus env,GraphQLContext, the context class, both together and a suspend method all resolve (the build fails without this change). A data class getter and an overload with the source, a helper withallowUnimplementedResolvers, the #890 warnings and a root resolver taking only the environment give the same results and log lines as before. A method with an argument on its context parameter still fails, with the extra signature lines.javaponly shows internal classes changing (DataClassTypeResolverInforemoved,FieldResolverScannerandSearchmembers).Schema build JMH on graphql-java 25.1, 3 alternating runs each: no measurable difference. The edealer schema takes 60.3 ms on master (a4736c9), 61.9 ms on #903 and 61.5 ms here (medians, about 2 ms between runs of the same jar), and allocates about 163 MB per build on all three. Expected, since fields that match today don't run any new code.