Skip to content

Kotlin coroutines handler don't work with "org.springframework.boot:spring-boot-starter-validation" #344

Closed
@nenros

Description

@nenros

Hi!
I have problems with Webflux + Kotlin + Coroutines. When I have something like that:

@Controller
class PersonController(val service: PersonService) {

    @MutationMapping( "createPerson")
    suspend fun createPerson(@Argument("input") personInput: PersonInput) : Person {
            return service.createPerson()
    }
}

and I try to make request

mutation {
    createPerson(input: {firstName: "Test", lastName: "Test"}) {
        id, firstName, lastName
    }
}

I get

{
  "errors": [
    {
      "message": "Index 1 out of bounds for length 1",
      "locations": [
        {
          "line": 33,
          "column": 5
        }
      ],
      "path": [
        "createPerson"
      ],
      "extensions": {
        "classification": "INTERNAL_ERROR"
      }
    }
  ],
  "data": {
    "createPerson": null
  }
}

But when I change to response type mono

@Controller
class PersonController(val service: PersonService) {

    @MutationMapping( "createPerson")
    fun createPerson(@Argument("input") personInput: PersonInput) : Mono<Person> {
            return mono {service.createPerson()}
    }
}

request works


After some investigation I found that problem was in validation starter:

java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
	at java.base/java.util.Arrays$ArrayList.get(Arrays.java:4165) ~[na:na]
	at org.hibernate.validator.internal.properties.javabean.JavaBeanExecutable.getParameterName(JavaBeanExecutable.java:86) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ParameterMetaData$Builder.build(ParameterMetaData.java:165) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.findParameterMetaData(ExecutableMetaData.java:436) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.aggregated.ExecutableMetaData$Builder.build(ExecutableMetaData.java:391) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder$BuilderDelegate.build(BeanMetaDataBuilder.java:260) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.aggregated.BeanMetaDataBuilder.build(BeanMetaDataBuilder.java:133) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.createBeanMetaData(BeanMetaDataManagerImpl.java:206) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.getBeanMetaData(BeanMetaDataManagerImpl.java:165) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:267) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:235) ~[hibernate-validator-6.2.3.Final.jar:6.2.3.Final]
	at org.springframework.graphql.data.method.annotation.support.HandlerMethodInputValidator.validate(HandlerMethodInputValidator.java:78) ~[spring-graphql-1.0.0-M6.jar:na]
	at org.springframework.graphql.data.method.annotation.support.DataFetcherHandlerMethod.validateAndInvoke(DataFetcherHandlerMethod.java:188) ~[spring-graphql-1.0.0-M6.jar:na]
	at org.springframework.graphql.data.method.annotation.support.DataFetcherHandlerMethod.invoke(DataFetcherHandlerMethod.java:121) ~[spring-graphql-1.0.0-M6.jar:na]
	at org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer$SchemaMappingDataFetcher.get(AnnotatedControllerConfigurer.java:449) ~[spring-graphql-1.0.0-M6.jar:na]
	at org.springframework.graphql.execution.ContextDataFetcherDecorator.get(ContextDataFetcherDecorator.java:67) ~[spring-graphql-1.0.0-M6.jar:na]
	at graphql.execution.instrumentation.dataloader.DataLoaderDispatcherInstrumentation.lambda$instrumentDataFetcher$0(DataLoaderDispatcherInstrumentation.java:87) ~[graphql-java-17.3.jar:na]
	at graphql.execution.ExecutionStrategy.fetchField(ExecutionStrategy.java:279) ~[graphql-java-17.3.jar:na]
	at graphql.execution.ExecutionStrategy.resolveFieldWithInfo(ExecutionStrategy.java:210) ~[graphql-java-17.3.jar:na]
	at graphql.execution.ExecutionStrategy.resolveField(ExecutionStrategy.java:182) ~[graphql-java-17.3.jar:na]
	at graphql.execution.AsyncSerialExecutionStrategy.lambda$execute$1(AsyncSerialExecutionStrategy.java:43) ~[graphql-java-17.3.jar:na]
	at graphql.execution.Async.eachSequentiallyImpl(Async.java:80) ~[graphql-java-17.3.jar:na]
	at graphql.execution.Async.eachSequentially(Async.java:69) ~[graphql-java-17.3.jar:na]
	at graphql.execution.AsyncSerialExecutionStrategy.execute(AsyncSerialExecutionStrategy.java:38) ~[graphql-java-17.3.jar:na]
	at graphql.execution.Execution.executeOperation(Execution.java:159) ~[graphql-java-17.3.jar:na]
	at graphql.execution.Execution.execute(Execution.java:105) ~[graphql-java-17.3.jar:na]
	at graphql.GraphQL.execute(GraphQL.java:613) ~[graphql-java-17.3.jar:na]
	at graphql.GraphQL.parseValidateAndExecute(GraphQL.java:538) ~[graphql-java-17.3.jar:na]
	at graphql.GraphQL.executeAsync(GraphQL.java:502) ~[graphql-java-17.3.jar:na]
	at org.springframework.graphql.execution.DefaultExecutionGraphQlService.lambda$execute$2(DefaultExecutionGraphQlService.java:81) ~[spring-graphql-1.0.0-M6.jar:na]
	at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:47) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:295) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:159) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142) ~[reactor-core-3.4.16.jar:3.4.16]
	at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:400) ~[reactor-netty-core-1.0.17.jar:1.0.17]
	at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:419) ~[reactor-netty-core-1.0.17.jar:1.0.17]
	at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:600) ~[reactor-netty-http-1.0.17.jar:1.0.17]
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:93) ~[reactor-netty-core-1.0.17.jar:1.0.17]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:266) ~[reactor-netty-http-1.0.17.jar:1.0.17]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:327) ~[netty-codec-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:299) ~[netty-codec-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:722) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:658) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:584) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:496) ~[netty-transport-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[netty-common-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.75.Final.jar:4.1.75.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.75.Final.jar:4.1.75.Final]
	at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]

and this is wrong line

.validateParameters(handlerMethod.getBean(), handlerMethod.getMethod(), arguments, validationGroups);

question if it isn't related to https://hibernate.atlassian.net/browse/HV-1796

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions