I ran into a surprising bug. I am trying to make an application that would access mongodb using the repository pattern. In order to reduce code duplication I wanted to make a common base class for all repositories. The repository of each root aggregate (such as Person
in code bellow), would inherit from this RepositoryBase
and inherit all the common functionality.
data class Person(val name: String)
open class RepositoryBase<T: Any> (val template: ReactiveMongoTemplate, private val klass: KClass<T>)
{
fun count(): Mono<Long> = template.count(Query(), klass.java)
}
@Repository
class PersonRepository(template: ReactiveMongoTemplate): RepositoryBase<Person>(template, Person::class)
@RunWith(SpringRunner::class)
@SpringBootTest
class DemoApplicationTests
{
@Autowired var personRepository: PersonRepository? = null
@Test
fun contextLoads()
{
println(personRepository?.count()?.block()!!)
}
}
However, this does not seem to work:
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.JvmClassMappingKt.getJavaClass, parameter $receiver
at kotlin.jvm.JvmClassMappingKt.getJavaClass(JvmClassMapping.kt) at com.example.demo.RepositoryBase.count(DemoApplicationTests.kt:18) ...
It seems that at the time Person::class
is being called, the introspection capabilities are not fully initialized and the subsequent call to KClass.java
, which is defined as:
/**
* Returns a Java [Class] instance corresponding to the given [KClass] instance.
*/
@Suppress("UPPER_BOUND_VIOLATED")
public val <T> KClass<T>.java: Class<T>
@JvmName("getJavaClass")
get() = (this as ClassBasedDeclarationContainer).jClass as Class<T>
results in the null-exception.
I would like to know if there are some rules on using introspection in Spring applications or whether this is a bug either in Kotlin or in Spring.