Skip to content

Instantly share code, notes, and snippets.

@pschichtel
Created August 17, 2021 14:53
Show Gist options
  • Save pschichtel/830b7943ea43b7cb58cadd984b54b903 to your computer and use it in GitHub Desktop.
Save pschichtel/830b7943ea43b7cb58cadd984b54b903 to your computer and use it in GitHub Desktop.
SuspendAwareKotlinParameterNameDiscoverer
import org.hibernate.validator.internal.engine.DefaultClockProvider
import org.springframework.core.LocalVariableTableParameterNameDiscoverer
import org.springframework.core.PrioritizedParameterNameDiscoverer
import org.springframework.core.StandardReflectionParameterNameDiscoverer
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import javax.validation.ClockProvider
import javax.validation.Configuration
import javax.validation.ParameterNameProvider
/**
* This class is part of the workaround for a bug in hibernate-validation.
*
* It post-processes the Hibernate configuration to use our customized parameter name discoverer.
*
* See:
* * Spring issue: https://github.com/spring-projects/spring-framework/issues/23499
* * Hibernate issue: https://hibernate.atlassian.net/browse/HV-1638
*/
class CustomLocalValidatorFactoryBean : LocalValidatorFactoryBean() {
override fun getClockProvider(): ClockProvider = DefaultClockProvider.INSTANCE
override fun postProcessConfiguration(configuration: 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)
}
})
}
}
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import org.springframework.context.annotation.Role
import org.springframework.context.annotation.Bean
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.boot.validation.MessageInterpolatorFactory
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
@Configuration(proxyBeanMethods = false)
class SomeConfiguration {
/**
* This bean definition is part of the workaround for a bug in hibernate-validation.
*
* It replaces the default validator factory bean with ours that uses the customized parameter name discoverer.
*
* See:
* * Spring issue: https://github.com/spring-projects/spring-framework/issues/23499
* * Hibernate issue: https://hibernate.atlassian.net/browse/HV-1638
*/
@Primary
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
fun defaultValidator(): LocalValidatorFactoryBean {
val factoryBean = CustomLocalValidatorFactoryBean()
factoryBean.messageInterpolator = MessageInterpolatorFactory().getObject()
return factoryBean
}
}
import org.springframework.core.KotlinReflectionParameterNameDiscoverer
import org.springframework.core.ParameterNameDiscoverer
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import kotlin.reflect.jvm.kotlinFunction
/**
* This class is part of the workaround for a bug in hibernate-validation.
*
* It appends an additional (empty) parameter name in case of suspend functions
*
* See:
* * Spring issue: https://github.com/spring-projects/spring-framework/issues/23499
* * Hibernate issue: https://hibernate.atlassian.net/browse/HV-1638
*/
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
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment