Skip to content

Kotlin 2.0.20, JVM21, SpringBoot 3.3.3, value classes, reflection error with CoroutineCrudRepository #3143

@dbs24

Description

@dbs24

Kotlin 2.0.20, JVM21 (graalvm-jdk-21.0.3+7.1), SpringBoot 3.3.3. The following code is available:

package org.somepkg.repo.invite

import org.springframework.data.annotation.Id
import org.springframework.data.annotation.Transient
import org.springframework.data.relational.core.mapping.Table
import org.springframework.data.repository.kotlin.CoroutineCrudRepository
import org.springframework.stereotype.Service
import java.io.Serializable

//=========================================================
@JvmInline
value class TestValueClass<T>(private val someValue: BoxImpl<T>) : Box<T> by someValue {
    fun someFun(): Box<T> = someValue
    constructor(initValue: T) : this(BoxImpl(initValue))
}

//=========================================================
sealed interface Box<T>
class BoxImpl<T>(val t: T) : Box<T>

//=========================================================
abstract class AbstractEntity(
    @Transient
    override val entityId: Long
) : Entity {
    @delegate:Transient
    @get:Transient
    val valueClassInstance: TestValueClass<String> by lazy {
        TestValueClass("someValue")
    }
}

//=========================================================
sealed interface Entity : Serializable {
    val entityId: Long
}

//=========================================================
@Table("table_entity")
data class FinalEntity(
    @Id
    val inviteId: Long,
    val inviteCode: String,
) : AbstractEntity(inviteId)

//=========================================================
interface FailedRepo : CoroutineCrudRepository<FinalEntity, Long> {
    suspend fun findByInviteCode(inviteCode: String): FinalEntity?
}

//=========================================================
@Service
class InviteService4Test(val failedRepo: FailedRepo) {

    suspend fun doSomething() {
        failedRepo.findByInviteCode("someCode")?.valueClassInstance?.someFun()
    }
}

The following error occurs when starting the spring boot application (see stacktrace applied below)
The error occurs from using value class (TestValueClass).
When this class is implemented as a regular class (without the @JvmInline annotation and “value” marker), the application starts normally, without any error

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failedRepo' defined in org.dbs.sandbox.repo.invite.FailedRepo defined in @EnableR2dbcRepositories declared on SandBoxApplication: Cannot invoke "java.lang.reflect.Type.getClass()" because "formal" is null
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1806)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:969)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
	at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
	at org.dbs.spring.boot.api.AbstractSpringBootApplication$SpringBootSubscriber.onNext(AbstractSpringBootApplication.kt:100)
	at org.dbs.spring.boot.api.AbstractSpringBootApplication$SpringBootSubscriber.onNext(AbstractSpringBootApplication.kt:76)
	at reactor.core.publisher.StrictSubscriber.onNext(StrictSubscriber.java:89)
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2571)
	at reactor.core.publisher.StrictSubscriber.onSubscribe(StrictSubscriber.java:77)
	at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4576)
	at org.dbs.spring.boot.api.AbstractSpringBootApplication$Companion.runSpringBootApplication(AbstractSpringBootApplication.kt:268)
	at org.dbs.spring.boot.api.AbstractSpringBootApplication$Companion.runSpringBootApplication(AbstractSpringBootApplication.kt:245)
	at org.dbs.sandbox.SandBoxApplication$Companion.main(SandBoxApplication.kt:20)
	at org.dbs.sandbox.SandBoxApplication.main(SandBoxApplication.kt)
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Type.getClass()" because "formal" is null
	at java.desktop/com.sun.beans.TypeResolver.resolve(TypeResolver.java:203)
	at java.desktop/com.sun.beans.TypeResolver.resolve(TypeResolver.java:218)
	at java.desktop/com.sun.beans.TypeResolver.resolve(TypeResolver.java:169)
	at java.desktop/com.sun.beans.TypeResolver.resolveInClass(TypeResolver.java:81)
	at java.desktop/java.beans.FeatureDescriptor.getReturnType(FeatureDescriptor.java:374)
	at java.desktop/java.beans.PropertyDescriptor.findPropertyType(PropertyDescriptor.java:686)
	at java.desktop/java.beans.PropertyDescriptor.setReadMethod(PropertyDescriptor.java:281)
	at java.desktop/java.beans.PropertyDescriptor.<init>(PropertyDescriptor.java:141)
	at org.springframework.data.util.KotlinBeanInfoFactory.getBeanInfo(KotlinBeanInfoFactory.java:83)
	at org.springframework.beans.CachedIntrospectionResults.getBeanInfo(CachedIntrospectionResults.java:222)
	at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:248)
	at org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:157)
	at org.springframework.beans.BeanUtils.getPropertyDescriptors(BeanUtils.java:488)
	at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:463)
	at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:424)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:320)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:246)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:97)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$6(RepositoryFactoryBeanSupport.java:289)
	at java.base/java.util.Optional.ifPresent(Optional.java:178)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:289)
	at org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean.afterPropertiesSet(R2dbcRepositoryFactoryBean.java:159)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1853)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1802)
	... 24 more

Metadata

Metadata

Assignees

Labels

for: external-projectFor an external project and not something we can fix

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions