Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scalar backed by value class inside input type fail to deserialize #1879

Open
stengvac opened this issue Apr 9, 2024 · 3 comments
Open

Scalar backed by value class inside input type fail to deserialize #1879

stengvac opened this issue Apr 9, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@stengvac
Copy link

stengvac commented Apr 9, 2024

Hello,

lets say we have value class

@JvmInline
value class ValueClass(val value: String)

we use DGS codegen to generate input and outputs for our server side and we used few value classes for Scalars. In version 8.2.0 it was possible to use scalar in generated input type as one of its fields. Top level value class did not work.

Expected behavior

Allow to register converters for conversionService in DefaultInputObjectMapper. It is possible to register custom input object mapper, but as value class is nested in input type, it is not possible to simply register converter only for some types, it require to implement whole DefaultInputObjectMapper or I did miss some configuration.

I have tried with DGS 8.5.5

Actual behavior

With registered Coercing<ValueClass, String>

Code like this worked:

// generated by DGS codegen
data class MyInput(
 val value: ValueClass,
)

@DgsQuery
fun myQuery(@InputArgument input: MyInput): String

This changed with higher versions of DGS as DefaultInputObjectMapper got reworked. Now registered coercing is still called, but converter for value class is not found in DefaultInputObjectMapper.

Stack

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [ValueClass] to type [java.lang.String]
	at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:294)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:185)
	at com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.maybeConvert(DefaultInputObjectMapper.kt:118)
	at com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.mapToKotlinObject(DefaultInputObjectMapper.kt:94)
	at com.netflix.graphql.dgs.internal.DefaultInputObjectMapper$Converter.convert(DefaultInputObjectMapper.kt:68)
	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182)
	at com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.maybeConvert(DefaultInputObjectMapper.kt:118)
	at com.netflix.graphql.dgs.internal.DefaultInputObjectMapper.mapToKotlinObject(DefaultInputObjectMapper.kt:94)
	at com.netflix.graphql.dgs.internal.method.InputObjectMapperConverter.convert(InputObjectMapperConverter.kt:41)
	at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182)
	at com.netflix.graphql.dgs.internal.method.AbstractInputArgumentResolver.convertValue(AbstractInputArgumentResolver.kt:79)
	at com.netflix.graphql.dgs.internal.method.AbstractInputArgumentResolver.resolveArgument(AbstractInputArgumentResolver.kt:48)
	at com.netflix.graphql.dgs.internal.method.ArgumentResolverComposite.resolveArgument(ArgumentResolverComposite.kt:39)
	at com.netflix.graphql.dgs.internal.DataFetcherInvoker.invokeKotlinMethod(DataFetcherInvoker.kt:114)
	at com.netflix.graphql.dgs.internal.DataFetcherInvoker.get(DataFetcherInvoker.kt:76)
	at graphql.schema.DataFetcherFactories.lambda$wrapDataFetcher$2(DataFetcherFactories.java:37)
	at com.netflix.graphql.dgs.metrics.micrometer.DgsGraphQLMetricsInstrumentation.instrumentDataFetcher$lambda$6(DgsGraphQLMetricsInstrumentation.kt:149)
	at graphql.execution.instrumentation.dataloader.DataLoaderDispatcherInstrumentation.lambda$instrumentDataFetcher$0(DataLoaderDispatcherInstrumentation.java:90)
	at graphql.execution.ExecutionStrategy.invokeDataFetcher(ExecutionStrategy.java:329)
	at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:305)
	at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:243)
	at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:214)
	at graphql.execution.ExecutionStrategy.resolveField(ExecutionStrategy.java:186)
	at graphql.execution.AsyncSerialExecutionStrategy.lambda$execute$1(AsyncSerialExecutionStrategy.java:56)
	at graphql.execution.Async.eachSequentiallyImpl(Async.java:162)
	at graphql.execution.Async.eachSequentially(Async.java:151)
	at graphql.execution.AsyncSerialExecutionStrategy.execute(AsyncSerialExecutionStrategy.java:51)
	at graphql.execution.Execution.executeOperation(Execution.java:162)
	at graphql.execution.Execution.execute(Execution.java:104)
	at graphql.GraphQL.execute(GraphQL.java:568)
	at graphql.GraphQL.lambda$parseValidateAndExecute$13(GraphQL.java:487)
	at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2309)
	at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:482)
	at graphql.GraphQL.lambda$executeAsync$9(GraphQL.java:440)
	at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1187)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2309)
	at graphql.GraphQL.executeAsync(GraphQL.java:428)
	at com.netflix.graphql.dgs.internal.BaseDgsQueryExecutor.baseExecute(BaseDgsQueryExecutor.kt:123)
	at com.netflix.graphql.dgs.internal.DefaultDgsQueryExecutor.execute(DefaultDgsQueryExecutor.kt:84)
	at com.netflix.graphql.dgs.mvc.DgsRestController$executeQuery$executionResult$1.invoke(DgsRestController.kt:215)
	at com.netflix.graphql.dgs.mvc.DgsRestController$executeQuery$executionResult$1.invoke(DgsRestController.kt:213)
	at com.netflix.graphql.dgs.internal.utils.TimeTracer.logTime(TimeTracer.kt:24)
	at com.netflix.graphql.dgs.mvc.DgsRestController.executeQuery(DgsRestController.kt:213)
	at com.netflix.graphql.dgs.mvc.DgsRestController.graphql(DgsRestController.kt:135)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:577)

Steps to reproduce

Create value class. Use it as field in input type. Call query/mutation with such input.

@stengvac stengvac added the bug Something isn't working label Apr 9, 2024
@stengvac stengvac changed the title Scalar backed by value class on input fail to deserialize Scalar backed by value class inside input type fail to deserialize Apr 9, 2024
@stengvac
Copy link
Author

Or maybe it could be considered feature.

@kilink
Copy link
Member

kilink commented Apr 11, 2024

I think this was already reported in #355, although I suppose you consider it a different problem since it's reporting usage at the top level. It worked before we switched to using the ConversionService? I'd have to look into why that is the case, it likely just worked by chance.

@stengvac
Copy link
Author

stengvac commented Apr 15, 2024

Yep I am aware, that top level does not work so we went for input object, which worked.

Will value classes be supported or do we have to swap to non value class? I just want to know what to expect and make adjustments in our code base. Thx.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants