BindingReflectionHintsRegistrar
currently does not add reflection entries for Kotlin data class components.
With this kind of repository and data class:
data class Customer(@Id val id: Int?, val name: String)
interface CustomerRepository : CoroutineCrudRepository<Customer, Int>
The following error is visible at startup:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': Could not compute caller for function: public final operator fun component1(): kotlin.Int? defined in com.example.demo.Customer[DeserializedSimpleFunctionDescriptor@32208e3c] (member = null)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1753) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1375) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1295) ~[demo:6.0.0-RC1]
at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:348) ~[na:na]
... 21 common frames omitted
Caused by: kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Could not compute caller for function: public final operator fun component1(): kotlin.Int? defined in com.example.demo.Customer[DeserializedSimpleFunctionDescriptor@32208e3c] (member = null)
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:88) ~[na:na]
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:61) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:63) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[demo:1.7.20-release-201(1.7.20)]
at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(KFunctionImpl.kt:61) ~[na:na]
at kotlin.reflect.jvm.ReflectJvmMapping.getJavaMethod(ReflectJvmMapping.kt:63) ~[na:na]
at kotlin.reflect.jvm.ReflectJvmMapping.getKotlinFunction(ReflectJvmMapping.kt:136) ~[na:na]
at org.springframework.core.MethodParameter$KotlinDelegate.getGenericReturnType(MethodParameter.java:914) ~[na:na]
at org.springframework.core.MethodParameter.getGenericParameterType(MethodParameter.java:510) ~[demo:6.0.0-RC1]
at org.springframework.core.SerializableTypeWrapper$MethodParameterTypeProvider.getType(SerializableTypeWrapper.java:291) ~[na:na]
at org.springframework.core.SerializableTypeWrapper.forTypeProvider(SerializableTypeWrapper.java:107) ~[na:na]
at org.springframework.core.ResolvableType.forType(ResolvableType.java:1413) ~[demo:6.0.0-RC1]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1334) ~[demo:6.0.0-RC1]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1316) ~[demo:6.0.0-RC1]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1283) ~[demo:6.0.0-RC1]
at org.springframework.core.ResolvableType.forMethodReturnType(ResolvableType.java:1243) ~[demo:6.0.0-RC1]
at org.springframework.core.GenericTypeResolver.resolveReturnType(GenericTypeResolver.java:80) ~[na:na]
at org.springframework.beans.GenericTypeAwarePropertyDescriptor.<init>(GenericTypeAwarePropertyDescriptor.java:110) ~[na:na]
at org.springframework.beans.CachedIntrospectionResults.buildGenericTypeAwarePropertyDescriptor(CachedIntrospectionResults.java:431) ~[na:na]
at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:310) ~[na:na]
at org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:183) ~[na:na]
at org.springframework.beans.BeanUtils.getPropertyDescriptors(BeanUtils.java:489) ~[na:na]
at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:414) ~[demo:3.0.0-SNAPSHOT]
It should be tested in https://github.com/spring-projects/spring-aot-smoke-tests and work out of the box.
Comment From: cmdjulian
I also did encounter the problem for a for two other situations:
Mind the following controller:
@RestController
@RequestMapping(NOTE_ENDPOINT)
class NoteController(private val service: NoteService) {
@PostMapping
fun createNote(@PathVariable notebookId: UUID, @Valid @RequestBody command: NoteCommand): NoteDto {
return service.createNote(command.toNote(notebookId), command.tags).toDto()
}
@GetMapping
fun findNotes(@PathVariable notebookId: UUID, filters: NoteFilters): List<NoteDto> {
return service.findNotes(notebookId, filters.tagNames, filters.content).map(Note::toDto)
}
}
data class NoteCommand(
@get:Size(min = 3, max = 128)
val title: String,
@get:Size(max = 65536)
val content: String?,
val tags: List<String> = emptyList()
)
data class NoteFilters(val tagNames: List<String>?, val content: String?)
Sending a valid NoteCommand
works as expected. But if some of the constraints are violated, an error is raised resulting in a 500 server error, as the previously described problem is triggered as well.
Secondly, requesting the collection endpoint, having a container object for a bunch of request parameters, in my case NoteFilters
, also causes the application to respond with a 500 server error because of missing reflection config.
Bot can be prevented by registering the aforementioned types in the reflect config, something like that works:
class AotConfig : RuntimeHintsRegistrar {
override fun registerHints(hints: RuntimeHints, classLoader: ClassLoader?) {
hints.reflection().registerType(NoteCommand::class.java, *MemberCategory.values())
hints.reflection().registerType(NoteFilters::class.java, *MemberCategory.values())
}
}
with src/main/resources/META-INF/spring
:
org.springframework.aot.hint.RuntimeHintsRegistrar=com.example.app.config.AotConfig
Comment From: sdeleuze
@cmdjulian Could be a different issue. I have created https://github.com/spring-projects/spring-framework/issues/29331 for something I have been able to reproduce. Please create another issue if you see other problems and please add a repro prject + the exception you see.
Comment From: cmdjulian
Okay, will do, thanks!