Affects: \<6.1.2> Reproducer: https://github.com/juliuskrah/graphql-demo/tree/spf-32472
Missing class in AOT processed Bean
Given the following bean definition:
class MongockBeanDefinitionRegistrar(
private val environment: Environment
): ImportBeanDefinitionRegistrar {
// ...
override fun registerBeanDefinitions(
metadata: AnnotationMetadata,
registry: BeanDefinitionRegistry,
importBeanNameGenerator: BeanNameGenerator,
) {
// ...
val mongockSupportBeanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(MongockRunnerSupport::class.java)
.addPropertyValue("migrationClasses", changeUnitSets)
.addPropertyReference("driver", "connectionDriver")
.addPropertyReference("config", "mongock-io.mongock.runner.springboot.base.config.MongockSpringConfiguration")
val mongockRunnerBeanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(MongockRunner::class.java)
.setFactoryMethodOnBean("create", "mongockRunnerSupport")
.setInitMethodName("execute")
registry.registerBeanDefinition(getName(MongockRunner::class.java), mongockRunnerBeanDefinitionBuilder.beanDefinition)
registry.registerBeanDefinition("mongockRunnerSupport", mongockSupportBeanDefinitionBuilder.beanDefinition)
}
class MongockRunnerSupport: ApplicationContextAware, ApplicationEventPublisherAware {
var driver: ConnectionDriver? = null
var config: MongockConfiguration? = null
var migrationClasses: List<Class<*>>? = emptyList()
private lateinit var applicationContext: ApplicationContext
private lateinit var eventPublisher: ApplicationEventPublisher
fun create(): MongockRunner {
val builder: RunnerSpringbootBuilder = MongockSpringboot.builder()
if (this.driver != null) builder.setDriver(driver)
if (this.config != null) builder.setConfig(config)
builder.setSpringContext(applicationContext)
builder.setEventPublisher(eventPublisher)
migrationClasses?.forEach(builder::addMigrationClass)
return builder.buildRunner()
}
override fun setApplicationContext(applicationContext: ApplicationContext) {
this.applicationContext = applicationContext
}
override fun setApplicationEventPublisher(applicationEventPublisher: ApplicationEventPublisher) {
this.eventPublisher = applicationEventPublisher
}
}
}
The aot process generates the following class:
@Generated
public class MongockBeanDefinitionRegistrar__BeanDefinitions {
@Generated
public static class MongockRunnerSupport {
private static BeanInstanceSupplier<MongockRunner> getMongockRunnerInstanceSupplier() {
return BeanInstanceSupplier.<MongockRunner>forFactoryMethod(MongockBeanDefinitionRegistrar.MongockRunnerSupport.class, "create")
.withGenerator((registeredBean) -> registeredBean.getBeanFactory().getBean(MongockBeanDefinitionRegistrar.MongockRunnerSupport.class).create());
}
public static BeanDefinition getMongockRunnerBeanDefinition() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(MongockRunner.class);
beanDefinition.setTargetType(MongockRunner.class);
beanDefinition.setInitMethodNames("execute");
beanDefinition.setInstanceSupplier(getMongockRunnerInstanceSupplier());
return beanDefinition;
}
public static BeanDefinition getMongockRunnerSupportBeanDefinition() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(MongockBeanDefinitionRegistrar.MongockRunnerSupport.class);
beanDefinition.getPropertyValues().addPropertyValue("migrationClasses", List.of(CreateProductCollectionChangeUnit202401151530.class));
beanDefinition.getPropertyValues().addPropertyValue("driver", new RuntimeBeanReference("connectionDriver"));
beanDefinition.getPropertyValues().addPropertyValue("config", new RuntimeBeanReference("mongock-io.mongock.runner.springboot.base.config.MongockSpringConfiguration"));
beanDefinition.setInstanceSupplier(MongockBeanDefinitionRegistrar.MongockRunnerSupport::new);
return beanDefinition;
}
}
}
I encounter the following exception when running the native executable:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongockRunnerSupport': Unresolved class: class com.example.graph.spring.MongockBeanDefinitionRegistrar$MongockRunnerSupport (kind = CLASS)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:606) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1323) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1284) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:486) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:341) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:334) ~[graphql-demo:6.1.2]
at com.example.graph.spring.MongockBeanDefinitionRegistrar__BeanDefinitions$MongockRunnerSupport.lambda$getRunnerSpringbootBuilderInstanceSupplier$0(MongockBeanDefinitionRegistrar__BeanDefinitions.java:28) ~[na:na]
at org.springframework.util.function.ThrowingFunction.apply(ThrowingFunction.java:63) ~[graphql-demo:6.1.2]
at org.springframework.util.function.ThrowingFunction.apply(ThrowingFunction.java:51) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$withGenerator$0(BeanInstanceSupplier.java:171) ~[na:na]
at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[graphql-demo:6.1.2]
at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:206) ~[na:na]
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) ~[graphql-demo:6.1.2]
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:218) ~[na:na]
at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.obtainInstanceFromSupplier(DefaultListableBeanFactory.java:949) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1216) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1160) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[graphql-demo:6.1.2]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:960) ~[graphql-demo:6.1.2]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[graphql-demo:6.1.2]
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[graphql-demo:3.2.1]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762) ~[graphql-demo:3.2.1]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:464) ~[graphql-demo:3.2.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) ~[graphql-demo:3.2.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1358) ~[graphql-demo:3.2.1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1347) ~[graphql-demo:3.2.1]
at com.example.graph.ApplicationKt.main(Application.kt:16) ~[graphql-demo:na]
at java.base@21/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH) ~[na:na]
Caused by: kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Unresolved class: class com.example.graph.spring.MongockBeanDefinitionRegistrar$MongockRunnerSupport (kind = CLASS)
at kotlin.reflect.jvm.internal.KClassImpl.createSyntheticClassOrFail(KClassImpl.kt:340) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl.access$createSyntheticClassOrFail(KClassImpl.kt:49) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:67) ~[na:na]
at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:53) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:70) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data.getDescriptor(KClassImpl.kt:53) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl.getDescriptor(KClassImpl.kt:193) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl.getMemberScope$kotlin_reflection(KClassImpl.kt:202) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data$declaredNonStaticMembers$2.invoke(KClassImpl.kt:173) ~[na:na]
at kotlin.reflect.jvm.internal.KClassImpl$Data$declaredNonStaticMembers$2.invoke(KClassImpl.kt:173) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:70) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data.getDeclaredNonStaticMembers(KClassImpl.kt:173) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data$allNonStaticMembers$2.invoke(KClassImpl.kt:182) ~[na:na]
at kotlin.reflect.jvm.internal.KClassImpl$Data$allNonStaticMembers$2.invoke(KClassImpl.kt:182) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:70) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data.getAllNonStaticMembers(KClassImpl.kt:182) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data$allMembers$2.invoke(KClassImpl.kt:188) ~[na:na]
at kotlin.reflect.jvm.internal.KClassImpl$Data$allMembers$2.invoke(KClassImpl.kt:188) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:70) ~[na:na]
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:32) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl$Data.getAllMembers(KClassImpl.kt:188) ~[graphql-demo:1.9.21-release-633]
at kotlin.reflect.jvm.internal.KClassImpl.getMembers(KClassImpl.kt:206) ~[graphql-demo:1.9.21-release-633]
at org.springframework.data.util.KotlinBeanInfoFactory.getBeanInfo(KotlinBeanInfoFactory.java:64) ~[graphql-demo:3.2.1]
at org.springframework.beans.CachedIntrospectionResults.getBeanInfo(CachedIntrospectionResults.java:222) ~[na:na]
at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:248) ~[na:na]
at org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:157) ~[na:na]
at org.springframework.beans.BeanWrapperImpl.getCachedIntrospectionResults(BeanWrapperImpl.java:162) ~[graphql-demo:6.1.2]
at org.springframework.beans.BeanWrapperImpl.getLocalPropertyHandler(BeanWrapperImpl.java:193) ~[graphql-demo:6.1.2]
at org.springframework.beans.BeanWrapperImpl.getLocalPropertyHandler(BeanWrapperImpl.java:58) ~[graphql-demo:6.1.2]
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyHandler(AbstractNestablePropertyAccessor.java:739) ~[graphql-demo:6.1.2]
at org.springframework.beans.AbstractNestablePropertyAccessor.isWritableProperty(AbstractNestablePropertyAccessor.java:565) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1686) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1433) ~[graphql-demo:6.1.2]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[graphql-demo:6.1.2]
... 41 common frames omitted
Comment From: sdeleuze
When running docker compose -f src/main/resources/compose.yml -f src/main/resources/compose.dev.yml up
, I get a permissions on /docker-entrypoint-initdb.d/keyfile are too open
error with Docker 24.0.5, could you please fix it to allow me to run the sample properly?
Comment From: juliuskrah
When running
docker compose -f src/main/resources/compose.yml -f src/main/resources/compose.dev.yml up
, I get apermissions on /docker-entrypoint-initdb.d/keyfile are too open
error with Docker 24.0.5, could you please fix it to allow me to run the sample properly?
Set the permissions on the file
chmod 400 src/main/resources/docker/keyfile
Comment From: sdeleuze
I am able to reproduce, that said, I am not sure something has to be fixed in Spring Framework since org.springframework.data.util.KotlinBeanInfoFactory
is triggering this error. But we can try to qualify more precisely this issue.
I am not sure yet why we see this error because com.example.graph.spring.MongockBeanDefinitionRegistrar$MongockRunnerSupport
seems to have various metadata provided, and even if I add allDeclaredMethods: true
and "allPublicMethods": true
I still see the same error (see related kotlin-reflect
source code).
Comment From: sdeleuze
After more tests, I found that the applications works as expected if you add a reflection hint for the outer class com.example.graph.spring.MongockBeanDefinitionRegistrar
(currently missing).
@snicoll The code path involves Spring Data which invokes kotlinClass.getMembers()
which requires the outer class hint, but maybe we could handle that defensively at Framework level. Any thoughts?
Unrelated, notice that an additional hint for io.mongock.runner.core.executor.MongockRunnerImpl
is also needed to be able to detect the execute
function and can't be, by design, guessed by the inference mechanism if I am not mistaken.
Comment From: snicoll
After chatting with Sébastien, we think that we should detect this case whenever we infer a reflection hint on a type. We also wonder if the same issue would happen if a non-static inner class was exposed that way in Java.