graphql-kotlin icon indicating copy to clipboard operation
graphql-kotlin copied to clipboard

Generated GQL client causes `kotlinx.serialization` compiler recursion error

Open holzerch opened this issue 3 years ago • 10 comments

Library Version Kotlin Version: 1.8.0 (also tested 1.7.20)

id("com.expediagroup.graphql") version "6.3.3"

...

implementation("com.expediagroup:graphql-kotlin-spring-client:6.3.3") {
        exclude("com.expediagroup", "graphql-kotlin-client-jackson")
    }
implementation("com.expediagroup:graphql-kotlin-client-serialization:6.3.3")

Describe the bug After switching from Jackson to kotlinx.serialization the generated code no longer compiles. It fails in the step kotlinCompile with the exception.

org.jetbrains.kotlin.util.KotlinFrontEndException: Front-end Internal error: Failed to analyze declaration Variables
File being compiled: (30,3) in /Users/christian/dev/doms-ecom-integration/build/generated/source/graphql/main/test/CreateFulfilmentOption.kt
The root cause java.lang.AssertionError was thrown at: org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor.getModality(LazyClassDescriptor.java:584)
	at org.jetbrains.kotlin.resolve.ExceptionWrappingKtVisitorVoid.visitDeclaration(ExceptionWrappingKtVisitorVoid.kt:43)
	at org.jetbrains.kotlin.psi.KtVisitorVoid.visitDeclaration(KtVisitorVoid.java:461)
	at org.jetbrains.kotlin.psi.KtVisitorVoid.visitDeclaration(KtVisitorVoid.java:21)
	at org.jetbrains.kotlin.psi.KtVisitor.visitNamedDeclaration(KtVisitor.java:406)

...

Caused by: java.lang.AssertionError: Recursion detected in a lazy value under LockBasedStorageManager@756f0f2d (TopDownAnalyzer for JVM)
	at org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor.getModality(LazyClassDescriptor.java:584)
	at org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializationUtilKt.getShouldHaveGeneratedSerializer(KSerializationUtil.kt:138)
	at org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationResolveExtension.generateSyntheticClasses(SerializationResolveExtension.kt:78)

The generated code looks like this

@Generated
@Serializable
public class CreateFulfilmentOption(
  public override val variables: CreateFulfilmentOption.Variables,
) : GraphQLClientRequest<CreateFulfilmentOption.Result> {
  @Required
  public override val query: String = CREATE_FULFILMENT_OPTION

  @Required
  public override val operationName: String = "CreateFulfilmentOption"

  public override fun responseType(): KClass<CreateFulfilmentOption.Result> =
      CreateFulfilmentOption.Result::class

  @Generated
  @Serializable
  public data class Variables(
    public val input: CreateFulfilmentOptionInput,
    public val executionMode: ExecutionMode? = null,
  )

  @Generated
  @Serializable
  public data class Result(
    public val createFulfilmentOption: FulfilmentOption? = null,
  )
}

The problem seems to be related to the nested class Result. After moving it outside of CreateFulfilmentOption the error is gone

To Reproduce Generate client code with kotlinx serialiser and try to compile with the described version.

Expected behavior The generated code compiles

holzerch avatar Jan 02 '23 14:01 holzerch

@holzerch have you found a workaround for this? I've tried playing with a lot of versions but have not come up with a winning combination yet

la289 avatar Jan 06 '23 15:01 la289

@holzerch have you found a workaround for this? I've tried playing with a lot of versions but have not come up with a winning combination yet

sadly no. I went back to Jackson and really wondering how this can work for anyone else

holzerch avatar Jan 07 '23 11:01 holzerch

Hello 👋 graphql-kotlin v6 is using Kotlin v1.6.21 and kotlinx.serialization v1.3.2 (link).

Next major (v7 alpha is out) is targeting Kotlin v1.7.21 and kotlinx.serialization v1.4.1 (link).

Thanks, Derek

dariuszkuc avatar Jan 09 '23 18:01 dariuszkuc

Hey Derek, thanks for the explanation. I wasn't aware of that. Since I don't want to downgrade my Kotlin version to 1.6, I tried the v7 alpha version sadly without success. The problem is still the same, which is no surprise since the generated code looks the same.

holzerch avatar Jan 10 '23 09:01 holzerch

Can you provide a link to a repository that reproduces this issue?

Tests within the repo seems to be fine

dariuszkuc avatar Jan 10 '23 17:01 dariuszkuc

@holzerch v7 alpha version does not contain the changes @dariuszkuc mentioned

Kotlin v1.7.21 and kotlinx.serialization v1.4.1 (link)

we can probably release another alpha or you can publish to your local repository and try it.

samuelAndalon avatar Jan 10 '23 17:01 samuelAndalon

@samuelAndalon could you please release the current state of the v7 as another alpha?

holzerch avatar Jan 11 '23 08:01 holzerch

Can you provide a link to a repository that reproduces this issue?

@dariuszkuc Here is a repo to reproduce the error. Just run ./gradlew build https://github.com/holzerch/gql-client-kotlin-serialization-bug It is just a plain Spring Initializr project with added dummy schema, query and client generation

holzerch avatar Jan 11 '23 08:01 holzerch

Hello 👋 It appears that this is actually a compiler plugin issue (https://youtrack.jetbrains.com/issue/KT-39491). Per spring docs it should be possible to use kotlinx-serialization but if I apply Kotlin Spring plugin it blows up for me.

Removing Kotlin Spring plugin (but keeping serialization and Spring Boot plugins) seems to work.

Thanks, Derek

dariuszkuc avatar Jan 26 '23 15:01 dariuszkuc

Thanks for digging up the root cause @dariuszkuc I just want to point out that you can workaround the problem by changing the structure of the generated code a little bit as I mentioned in the initial issue statement.

The problem seems to be related to the nested class Result. After moving it outside of the parent the error is gone

Since this is breaking change maybe it would be something for version 7?

holzerch avatar Jan 26 '23 15:01 holzerch