Reflection: improve support of built-in classes in 'toJavaClass'
Also support mock class descriptor created for java.io.Serializable. This will be needed (and covered with tests) later for correct implementation of advanced reflection API
This commit is contained in:
@@ -20,13 +20,10 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.reflect.tryLoadClass
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
@@ -120,16 +117,9 @@ internal class KClassImpl<T : Any>(override val jClass: Class<T>) : KDeclaration
|
||||
override val nestedClasses: Collection<KClass<*>>
|
||||
get() = descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors().filterNot(DescriptorUtils::isEnumEntry).mapNotNull {
|
||||
nestedClass ->
|
||||
(nestedClass as ClassDescriptor).toJavaClass() ?: run {
|
||||
// If neither a Kotlin class nor a Java class, it must be a built-in
|
||||
val classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(nestedClass))
|
||||
?: throw KotlinReflectionInternalError("Class with no source must be a built-in: $nestedClass")
|
||||
val packageName = classId.packageFqName.asString()
|
||||
val className = classId.relativeClassName.asString().replace('.', '$')
|
||||
// All pseudo-classes like String.Companion must be accessible from the current class loader
|
||||
(this as Any).javaClass.safeClassLoader.tryLoadClass("$packageName.$className")
|
||||
}
|
||||
}.map { KClassImpl(it) }
|
||||
val jClass = (nestedClass as ClassDescriptor).toJavaClass()
|
||||
jClass?.let { KClassImpl(it) }
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private val objectInstance_ = ReflectProperties.lazy {
|
||||
|
||||
@@ -18,10 +18,15 @@ package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.components.RuntimeSourceElementFactory
|
||||
import org.jetbrains.kotlin.load.java.reflect.tryLoadClass
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import kotlin.jvm.internal.FunctionReference
|
||||
import kotlin.jvm.internal.PropertyReference
|
||||
import kotlin.reflect.IllegalCallableAccessException
|
||||
@@ -38,12 +43,36 @@ internal fun ClassDescriptor.toJavaClass(): Class<*>? {
|
||||
(source.javaElement as ReflectJavaClass).element
|
||||
}
|
||||
else -> {
|
||||
// This is a built-in class
|
||||
null
|
||||
// If this is neither a Kotlin class nor a Java class, it is either a built-in or some fake class descriptor like the one
|
||||
// that's created for java.io.Serializable in JvmBuiltInsSettings
|
||||
val classId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(this)) ?: classId
|
||||
val packageName = classId.packageFqName.asString()
|
||||
val className = classId.relativeClassName.asString()
|
||||
// All pseudo-classes like kotlin.String.Companion must be accessible from the current class loader
|
||||
loadClass(javaClass.safeClassLoader, packageName, className)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun loadClass(classLoader: ClassLoader, packageName: String, className: String): Class<*>? {
|
||||
if (packageName == "kotlin") {
|
||||
// See mapBuiltInType() in typeSignatureMapping.kt
|
||||
when (className) {
|
||||
"Array" -> return Array<Any>::class.java
|
||||
"BooleanArray" -> return BooleanArray::class.java
|
||||
"ByteArray" -> return ByteArray::class.java
|
||||
"CharArray" -> return CharArray::class.java
|
||||
"DoubleArray" -> return DoubleArray::class.java
|
||||
"FloatArray" -> return FloatArray::class.java
|
||||
"IntArray" -> return IntArray::class.java
|
||||
"LongArray" -> return LongArray::class.java
|
||||
"ShortArray" -> return ShortArray::class.java
|
||||
}
|
||||
}
|
||||
|
||||
return classLoader.tryLoadClass("$packageName.${className.replace('.', '$')}")
|
||||
}
|
||||
|
||||
// TODO: wrap other exceptions
|
||||
internal inline fun <R> reflectionCall(block: () -> R): R =
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user