Kotlin2 equals + hashcode + toString - #951
Open
bugy wants to merge 3 commits into
Open
Conversation
added 3 commits
August 3, 2026 10:12
kotlin2 response/data types (generateKotlinNullableClasses = true) had no equals/hashCode and compared by identity, since their fields are backed by lazy supplier lambdas that throw when a field wasn't requested. Add generated equals/hashCode where two instances are equal iff they requested the same set of fields and every requested field's value is equal; an unrequested field's supplier is never invoked. This mirrors the semantics and CodeBlock style of the existing Java DataTypeGenerator.addEquals/ addHashcode. Regenerates all kotlin2 integration-test golden expected files.
Renders only the fields the projection actually requested, so an unrequested field's supplier is never invoked. Addresses Netflix#638.
Same semantics as before (same-class check, identical requested-field set required, never invoke an unrequested supplier, absent != requested-null, never throws) - purely a shape change, requested by review because the previous joinToCode-based bodies wrapped badly. - equals/hashCode now delegate to a private `__$fieldValues(): List<Any?>` helper that snapshots every field (using the field's own default lambda as the "unrequested" placeholder instead of invoking it). Two instances are equal iff `this === other || (other is T && fieldValues() == other.fieldValues())`; hashCode is `fieldValues().hashCode()`. A mismatched requested-field set already forces a mismatched list entry at that field's index, so no separate "same requested set" check is needed on top - verified by the existing runtime test, left unmodified. - toString gets its own `__$fieldStrings(): List<String>` helper (it needs field names, so it can't reuse fieldValues()), then joins them. - Both helper names are backtick-escaped and contain "$", which GraphQL Names can never contain, so they can't collide with a member derived from any field (e.g. a field literally named `fieldValues`). - The list literals are built from plain "\n"-containing string literals, not KotlinPoet's indent()/unindent(), which - confirmed by reproducing it in isolation - leaves the CodeWriter's indent level unbalanced after a single-expression function body collapses to `= ...`. Regenerates 97 golden expected-output files (the one zero-field case's toString was already just "ClassName()" and is unchanged).
bugy
requested review from
asibross,
iparadiso,
iuliiasobolevska,
jjacobs44,
kilink,
kzwang,
paulbakker and
srinivasankavitha
as code owners
August 3, 2026 10:28
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.
Hi all, I noticed that new kotlin generator with projections and nullable field types do not support lazy equals + hashcode + toString.
The latter (toString) I would like to bring here for sure (it would be more or less safe and doesn't affect how people use DTOs). There is an open issue for it: #638
equals+hashCode I would like to have too, to have it consistent with other DGS generated files.
Proposed implementation of equals+hashCode compares only initialized fields. The fields which are not initialized are considered equal.
cc @mbossenbroek what do you think?