Prefer getters over fluent setters for input field types - #833
Merged
Merged
Conversation
To find the Java type of an input object field, the scanner took any public method named `x` or `getX`, picked the one with the shortest name and used its return type. A fluent setter such as `RepairApply repairMan(RepairMan)`, as generated by JHipster or Lombok @accessors(fluent = true), has the shortest name, so the input type of the field was mapped to the enclosing class. That fails with "Two different classes used for type" as soon as the same input type is also used as a resolver parameter. Look for a getter without parameters first, then for a public field. Methods with parameters, such as `getX(DataFetchingEnvironment)`, are only used when neither exists, so nested input types that can only be found through them are still discovered. Fixes #446 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
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 #446
Checklist
Description
A schema with
input RepairApplyInput { repairMan: RepairManInput }and a mutation that takesRepairManInputdirectly fails to build withTwo different classes used for type RepairManInput, where one of the two classes isRepairApplyitself. The only workaround in the thread is duplicating the input type under another name. The reporter didn't post their entity classes, but you get the exact same error when the entity has a fluent setter, like thepublic RepairApply repairMan(RepairMan repairMan) { ...; return this; }JHipster generates, or therepairMan()+repairMan(RepairMan)pair from Lombok's@Accessors(fluent = true). Without the fluent setter the same schema builds fine on master.SchemaClassScanner#findInputValueTypeInTypefinds the Java type of an input field by taking the public methods namedxorgetX, sorting them by name length and using the return type of the first non-synthetic one. It never looked at parameters.repairMan(RepairMan)has a shorter name thangetRepairMan(), so it wins andRepairManInputgets mapped to its return type,RepairApply. That clashes with theRepairManparameter ofcreateRepairMan.Now getters without parameters come first (non-synthetic first, same as before), then the public field, and only then methods with parameters, picked the same way as before. My first version dropped methods with parameters completely, but that broke schemas that build on master. For example a class used for both
type Foo { bar: Bar }andinput FooInput { bar: BarInput }withgetBar(DataFetchingEnvironment),setBar(Bar)and a private field. IfBarInputis only reachable throughFooInput.bar, it never got discovered andmakeExecutableSchema()threwExpected type 'BarInput' to be a GraphQLInputType, but it wasn't!. Same for an input class that only has a fluent setter. Keeping them as the last resort means those resolve exactly as on master.scanner finds input field types through getters with argumentscovers that case.scanner ignores fluent setters when finding input field typescovers the issue with a JHipster-style property, a Lombok-style pair and a@JvmFieldfield, each with a fluent setter, and fails on master with the same error as the issue.I didn't try to use a fluent setter's parameter type when there's no getter or public field. Telling a fluent setter apart from a getter with arguments would need a heuristic (one parameter, returns the declaring type) that gets things like
Foo getParent(env)onFooorMap.remove(Object)wrong. So a class with only a fluent setterx(X), or withx(X)andgetX(env)but no getter without parameters, still resolves to the setter's return type, same as on master. Neither is needed for #446.Behaviour change: when an input class has a getter without parameters (or a public field) and a method with parameters for the same field, the field's Java type now comes from the getter or field. So schemas that failed with "Two different classes used for type X" because of a fluent setter now build. Classes that only have methods with parameters for a field resolve as before.
🤖 Generated with Claude Code