Problem:
Kotlin JDSL provides the interface KotlinJdslJpqlExecutor
. A Spring Data JPA repository interface, annotated with @Repository
and extending JpaRepository
can also extend KotlinJdslJpqlExecutor
.
@Entity
class MyEntity {
@Id
var id: UUID = UUID.randomUUID()
}
@Repository
interface MyEntityRepository: JpaRepository<MyEntity, UUID>, KotlinJdslJpqlExecutor
This in used in a Spring Boot 3.x application. It works just fine during development. We compile and run on OpenJDK 21.
But after compiling into a native image (GraalVM), it doesn't work any more. These are some exceptions:
Caused by: .springframework.data.mapping.PropertyReferenceException: No property 'update' found for type 'MyEntity'
and
Caused by: .springframework.data.mapping.PropertyReferenceException: No property 'findAll' found for type 'MyEntity'
Research:
The source code of Kotlin JDSL Spring Data JPA support:
There is a BeanPostProcessor
implementation in KotlinJdslJpaRepositoryFactoryBeanPostProcessor
. The KotlinJdslJpqlExecutor
is autowired and used to set a custom implementation.
@Component
@SinceJdsl("3.0.0")
open class KotlinJdslJpaRepositoryFactoryBeanPostProcessor : BeanPostProcessor {
@Lazy
@Autowired
lateinit var kotlinJdslJpqlExecutor: KotlinJdslJpqlExecutor
override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any? {
if (bean is JpaRepositoryFactoryBean<*, *, *> && bean.hasJdsl()) {
bean.setCustomImplementation(kotlinJdslJpqlExecutor)
}
return super.postProcessAfterInitialization(bean, beanName)
}
private fun JpaRepositoryFactoryBean<*, *, *>.hasJdsl(): Boolean {
return this.objectType.interfaces
.any { it == KotlinJdslJpqlExecutor::class.java }
}
}
According to the Spring AOT documentation, BeanPostProcessor
implementations are not invoked.
If the KotlinJdslJpaRepositoryFactoryBeanPostProcessor
is the issue, how to fix this?