How to get KClass of @file:JvmName


#1

@file:JvmName(“EncryptionModule”)
@file:Module

package com.dfdfdfd.di.module

@Provides
@Singleton
fun getEncryptionService(context: Context): EncryptionService {
    return EncryptionServiceDefault(context)
}

I wrote in this way to retrieve class with static functions.

@Singleton
@Component(modules = [
ApplicationModule::class,
EncryptionModule::class, //error Unresolved reference EncryptionModule
DataModule::class])

Please, help me. How to retrieve const instance of KClass in this case?


#2

Did you figure this out?


#3

At Kotlin language level top level functions are independent of the file they are declared in. They belong directly to their package. @JvmName annotations do not change this, they merely change details of the compilation result not the validity of your Kotlin (unless you use it to avoid platform issues on uncompilable Kotlin). On the JVM a class is needed that contains these static members. It still isn’t possible to create instances of them. Instead you may be thinking about an object rather than a toplevel.


#4

No


#5

Yeah, that’s what the OP asked about — how to get hold of the j.l.Class reference to the container class?


#6

The easiest way would be through one of the properties or methods in the file. They (at least on Java level) have an owner class that you can get through there (and you can create a KClass of a j.l.Class). However, the class file is (on the Kotlin side) merely an implementation detail. It does not exist in the language model, as such there is no way to directly reference it (or indirectly without going into JVM implementation details).


#7

I can’t do it right now, can I?
Suppose I need something like val log = LoggerFactory.getLogger(clazz). If log is top-level, how do I take the clazz? I can’t use log itself (other than wrapping it into lazy, which is an abomination), so I need to declare a dummy some top-level val… but its ::class only gives us its KClass, not the one of its owner.

Looks like for the time being, I need to wrap such things in an object.


#8

You’ll have to use the reflection library in combination with delegation. Using that you can use: KProperty.javaGetter in the getValue or provideDelegate operators. javaGetter will give you a Java method. A method has an owner and you know the Java class. At the same time you are now tightly bound to implementation details of Kotlin toplevel properties.


#9

Thanks! I ended up doing this:

// Usage: `val log by TopLevelLoggerCreator`
object TopLevelLoggerCreator {
  operator fun getValue(thisRef: Any?, property: KProperty<*>): Logger {
    val loggerClass = property.javaGetter!!.declaringClass
    return LoggerFactory.getLogger(loggerClass)
  }
}

… but I ran into an issue when trying to use the code that calls this delegate in the tests: property.javaGetter was failing with internal reflection error. I tried to reproduce it in a separate project, but couldn’t. Anyway, in general this should work, so thanks again!