This happens only in a native image. I have this configuration:
@Configuration(proxyBeanMethods = false)
class MyConfiguration {
@Bean
fun a(): A {
return A()
}
private fun b(): B {
return B()
}
}
class A
class B
Running the application works. Now rename the a()
method to z_a()
and it breaks:
java.lang.ClassNotFoundException: com.example.demo.B
at java.base@17.0.5/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:52) ~[demo:na]
at java.base@17.0.5/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na]
at java.base@17.0.5/java.lang.ClassLoader.loadClass(ClassLoader.java:132) ~[demo:na]
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.parseType(KDeclarationContainerImpl.kt:273) ~[demo:1.7.21-release-272(1.7.21)]
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.loadReturnType(KDeclarationContainerImpl.kt:288) ~[demo:1.7.21-release-272(1.7.21)]
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findMethodBySignature(KDeclarationContainerImpl.kt:198) ~[demo:1.7.21-release-272(1.7.21)]
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:68) ~[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.21-release-272(1.7.21)]
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) ~[na:na]
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.2]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1334) ~[demo:6.0.2]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1316) ~[demo:6.0.2]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1283) ~[demo:6.0.2]
at org.springframework.core.ResolvableType.forMethodReturnType(ResolvableType.java:1228) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:814) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681) ~[demo:6.0.2]
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:652) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1632) ~[demo:6.0.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:559) ~[demo:6.0.2]
at org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:147)
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:794)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:13)
Caused by: java.lang.ClassNotFoundException: com.example.demo.B
at java.base@17.0.5/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:52)
at java.base@17.0.5/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base@17.0.5/java.lang.ClassLoader.loadClass(ClassLoader.java:132)
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.parseType(KDeclarationContainerImpl.kt:273)
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.loadReturnType(KDeclarationContainerImpl.kt:288)
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findMethodBySignature(KDeclarationContainerImpl.kt:198)
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:68)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:531) ~[demo:6.0.2]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:106) ~[na:na]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:745) ~[demo:6.0.2]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:565) ~[demo:6.0.2]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[demo:3.0.0]
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:61)
at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:63)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32)
at kotlin.reflect.jvm.internal.KFunctionImpl.getCaller(KFunctionImpl.kt:61)
at kotlin.reflect.jvm.ReflectJvmMapping.getJavaMethod(ReflectJvmMapping.kt:63)
at kotlin.reflect.jvm.ReflectJvmMapping.getKotlinFunction(ReflectJvmMapping.kt:136)
at org.springframework.core.MethodParameter$KotlinDelegate.getGenericReturnType(MethodParameter.java:914)
at org.springframework.core.MethodParameter.getGenericParameterType(MethodParameter.java:510)
at org.springframework.core.SerializableTypeWrapper$MethodParameterTypeProvider.getType(SerializableTypeWrapper.java:291)
at org.springframework.core.SerializableTypeWrapper.forTypeProvider(SerializableTypeWrapper.java:107)
at org.springframework.core.ResolvableType.forType(ResolvableType.java:1413)
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1334)
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1316)
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1283)
at org.springframework.core.ResolvableType.forMethodReturnType(ResolvableType.java:1228)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:814)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:652)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1632)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:559)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:531)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:106)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:745)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:565)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
... 3 more
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[demo:3.0.0]
at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:13) ~[demo:na]
2022-12-08T17:30:40.001+01:00 WARN 179946 --- [ main] o.s.boot.SpringApplication : Unable to close ApplicationContext
java.lang.ClassNotFoundException: com.example.demo.B
at java.base@17.0.5/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:52) ~[demo:na]
at java.base@17.0.5/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[na:na]
at java.base@17.0.5/java.lang.ClassLoader.loadClass(ClassLoader.java:132) ~[demo:na]
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.parseType(KDeclarationContainerImpl.kt:273) ~[demo:1.7.21-release-272(1.7.21)]
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.loadReturnType(KDeclarationContainerImpl.kt:288) ~[demo:1.7.21-release-272(1.7.21)]
at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.findMethodBySignature(KDeclarationContainerImpl.kt:198) ~[demo:1.7.21-release-272(1.7.21)]
at kotlin.reflect.jvm.internal.KFunctionImpl$caller$2.invoke(KFunctionImpl.kt:68) ~[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.21-release-272(1.7.21)]
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) ~[na:na]
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.2]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1334) ~[demo:6.0.2]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1316) ~[demo:6.0.2]
at org.springframework.core.ResolvableType.forMethodParameter(ResolvableType.java:1283) ~[demo:6.0.2]
at org.springframework.core.ResolvableType.forMethodReturnType(ResolvableType.java:1228) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:814) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:652) ~[demo:6.0.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1632) ~[demo:6.0.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:559) ~[demo:6.0.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:531) ~[demo:6.0.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:658) ~[demo:6.0.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:650) ~[demo:6.0.2]
at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1276) ~[demo:6.0.2]
at org.springframework.boot.SpringApplication.getExitCodeFromMappedException(SpringApplication.java:863) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.getExitCodeFromException(SpringApplication.java:851) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.handleExitCode(SpringApplication.java:838) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:778) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[demo:3.0.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[demo:3.0.0]
at com.example.demo.DemoApplicationKt.main(DemoApplication.kt:13) ~[demo:na]
Demo project here: demo.zip
I debugged that to a behaviour in Kotlin reflection. Essentially you need reflection metadata for ALL methods (not only for the @Bean
methods like it's at the moment) if you use ResolvableType.forMethodReturnType(method)
. It depends on the iteration order of the methods. You can read more here: https://github.com/mhalbritter/kotlin-graalvm-reflection
Comment From: sdeleuze
Confirmed, I have bring this behavior to the attention of the Kotlin team and will share their feedback here. Worst case scenario, I guess we could configure introspect medadata for all functions of Kotlin classes.
Comment From: sdeleuze
Feedback from Kotlin team:
The implementation can be optimized somewhat, but in the worst case we still have to iterate over all methods in a class, because the rules of correspondence between KFunction <-> java.lang.reflect.Method are not trivial and even their names don't match sometimes (e.g. because of @JvmName, default parameters, inline classes, etc).
So let's configure introspection on all functions for Kotlin classes.