Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

629
Visualizações
failed to validate request params in a Spring Boot/Kotlin Coroutines controller

In a SpringBoot/Kotlin Coroutines project, I have a controller class like this.


@RestContollser
@Validated
class PostController(private val posts: PostRepository) {

    suspend fun search(@RequestParam q:String, @RequestParam  @Min(0) offset:Int, @RequestParam  @Min(1) limit:Int): ResponseEntity<Any> {}

}

The validation on the @ResquestBody works as the general Spring WebFlux, but when testing

validating request params , it failed and throws an exception like:

java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
    at java.base/java.util.Arrays$ArrayList.get(Arrays.java:4165)
    Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:

It is not a ConstraintViolationException.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

I think this is a bug in the framework when you are using coroutines (update , it is, I saw Happy Songs comment). In summary:

"@Validated is indeed not yet Coroutines compliant, we need to fix that by using Coroutines aware methods to discover method parameters."

The trouble is that the signature of the method on your controller is actually enhanced by Spring to have an extra parameter, like this, adding a continuation:

public java.lang.Object com.example.react.PostController.search(java.lang.String,int,int,kotlin.coroutines.Continuation)

so when the hibernate validator calls getParameter names to get the list of parameters on your method, it thinks there are 4 in total on the request, and then gets an index out of bounds exception trying to get the 4th (index 3).

If you put a breakpoint on the return of this:

   @Override
        public E get(int index) {
            return a[index];
        }

and put a breakpoint condition of index ==3 && a.length <4 you can see what is going on.

I'd report it as a bug on the Spring issue tracker.

You might be better off taking an alternative approach, as described here, using a RequestBody as a DTO and using the @Valid annotation

https://www.vinsguru.com/spring-webflux-validation/

over 4 years ago · Santiago Trujillo Relatório

0

Thanks for the happy songs' comments, I found the best solution by now to overcome this barrier from the Spring Github issues#23499.

As explained in comments of this issue and PaulNuk's answer, there is a Continuation will be appended to the method arguments at runtime, which will fail the index computation of the method parameter names in the Hibernate Validator.

The solution is changing the ParameterNameDiscoverer.getParameterNames(Method) method and adding a empty string as the additional parameter name when it is a suspend function.

class KotlinCoroutinesLocalValidatorFactoryBean : LocalValidatorFactoryBean() {
    override fun getClockProvider(): ClockProvider = DefaultClockProvider.INSTANCE

    override fun postProcessConfiguration(configuration: javax.validation.Configuration<*>) {
        super.postProcessConfiguration(configuration)

        val discoverer = PrioritizedParameterNameDiscoverer()
        discoverer.addDiscoverer(SuspendAwareKotlinParameterNameDiscoverer())
        discoverer.addDiscoverer(StandardReflectionParameterNameDiscoverer())
        discoverer.addDiscoverer(LocalVariableTableParameterNameDiscoverer())

        val defaultProvider = configuration.defaultParameterNameProvider
        configuration.parameterNameProvider(object : ParameterNameProvider {
            override fun getParameterNames(constructor: Constructor<*>): List<String> {
                val paramNames: Array<String>? = discoverer.getParameterNames(constructor)
                return paramNames?.toList() ?: defaultProvider.getParameterNames(constructor)
            }

            override fun getParameterNames(method: Method): List<String> {
                val paramNames: Array<String>? = discoverer.getParameterNames(method)
                return paramNames?.toList() ?: defaultProvider.getParameterNames(method)
            }
        })
    }
}

class SuspendAwareKotlinParameterNameDiscoverer : ParameterNameDiscoverer {

    private val defaultProvider = KotlinReflectionParameterNameDiscoverer()

    override fun getParameterNames(constructor: Constructor<*>): Array<String>? =
        defaultProvider.getParameterNames(constructor)

    override fun getParameterNames(method: Method): Array<String>? {
        val defaultNames = defaultProvider.getParameterNames(method) ?: return null
        val function = method.kotlinFunction
        return if (function != null && function.isSuspend) {
            defaultNames + ""
        } else defaultNames
    }
}

Then declare a new validator factory bean.

    @Primary
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    fun defaultValidator(): LocalValidatorFactoryBean {
        val factoryBean = KotlinCoroutinesLocalValidatorFactoryBean()
        factoryBean.messageInterpolator = MessageInterpolatorFactory().getObject()
        return factoryBean
    }

Get the complete sample codes from my Github.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda