Netflix / dgs-framework

GraphQL for Java with Spring Boot made easy.
https://netflix.github.io/dgs
Apache License 2.0
3.06k stars 295 forks source link

bug: Extended JSON scalar serialization not working for mutation input #1817

Closed Sandip888831 closed 2 months ago

Sandip888831 commented 7 months ago

I am using JSON scalar from DGS extended scalar library but it is failing to serialize it to input JsonObject.

Expected behavior

JSON scalar should be serialized to JsonObject

Actual behavior

JSON Scalar serialization to input JsonObject is failing

Steps to reproduce

I am using JSON from DGS extended scalar library, This the version I am using:

<dependency>
    <groupId>com.netflix.graphql.dgs</groupId>
    <artifactId>graphql-dgs-platform-dependencies</artifactId>
    <version>8.1.1</version>
</dependency>
<dependency>
    <groupId>com.netflix.graphql.dgs</groupId>
    <artifactId>graphql-dgs-extended-scalars</artifactId>
    <version>8.1.1</version>
</dependency>

This is my mutation schema:

saveSession(session: SaveUserSessionInput!): String
data class SaveUserSessionInput(
val pageToLoad: String?,
var entries: MutableList<JsonObject>? #(com.google.gson.JsonObject)
)

This is how I am calling it:

mutation {
    saveSession(
      session: {pageToLoad: "Symptom", entries: [{key: "Symptom", value: "dummy_symptom_value"}]}
    ) {
      message
    }
  }

While running the mutation I am getting this error: com.netflix.graphql.dgs.exceptions.DgsInvalidInputArgumentException: Input argument type 'class com.google.gson.JsonObject' doesn't match input {key=Symptom, value=dummy_symptom_value}

Stacktrace:

0 = {StackTraceElement@20372} "com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.mapToJavaObject(DefaultInputObjectMapper.kt:160)"
1 = {StackTraceElement@20373} "com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.convertList(DefaultInputObjectMapper.kt:230)"
2 = {StackTraceElement@20374} "com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.mapToKotlinObject(DefaultInputObjectMapper.kt:78)"
3 = {StackTraceElement@20375} "com.netflix.graphql.dgs.internal.method.InputObjectMapperConverter.convert(InputObjectMapperConverter.kt:41)"
4 = {StackTraceElement@20376} "org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)"
5 = {StackTraceElement@20377} "org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:192)"
6 = {StackTraceElement@20378} "com.netflix.graphql.dgs.internal.method.AbstractInputArgumentResolver.convertValue(AbstractInputArgumentResolver.kt:79)"
7 = {StackTraceElement@20379} "com.netflix.graphql.dgs.internal.method.AbstractInputArgumentResolver.resolveArgument(AbstractInputArgumentResolver.kt:48)"
8 = {StackTraceElement@20380} "com.netflix.graphql.dgs.internal.method.ArgumentResolverComposite.resolveArgument(ArgumentResolverComposite.kt:39)"
9 = {StackTraceElement@20381} "com.netflix.graphql.dgs.internal.DataFetcherInvoker.invokeKotlinMethod(DataFetcherInvoker.kt:104)"
10 = {StackTraceElement@20382} "com.netflix.graphql.dgs.internal.DataFetcherInvoker.get(DataFetcherInvoker.kt:70)"
11 = {StackTraceElement@20383} "graphql.schema.DataFetcherFactories.lambda$wrapDataFetcher$2(DataFetcherFactories.java:37)"
12 = {StackTraceElement@20384} "com.netflix.graphql.dgs.metrics.micrometer.DgsGraphQLMetricsInstrumentation.instrumentDataFetcher$lambda$3(DgsGraphQLMetricsInstrumentation.kt:142)"
13 = {StackTraceElement@20385} "graphql.execution.instrumentation.dataloader.DataLoaderDispatcherInstrumentation.lambda$instrumentDataFetcher$0(DataLoaderDispatcherInstrumentation.java:90)"
14 = {StackTraceElement@20386} "graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:309)"
15 = {StackTraceElement@20387} "graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:286)"
16 = {StackTraceElement@20388} "graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:212)"
kilink commented 7 months ago

The parameter mapping doesn't support this sort of thing at the moment. If anything, I would classify it as a gap in our documentation. If you just wanted the raw map, you can use Map<String, Object>. But to get something like a Gson JsonObject, you'd need to implement your own Coercing implementation and use your own custom Scalar I think.

I think we could support registering of custom converters that would serve this purpose as well, but support for that hasn't been fleshed out.