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:
Alexander Udalov
2016-07-13 18:34:32 +03:00
parent 0c98231f53
commit 5e3efe0e58
2 changed files with 34 additions and 15 deletions
@@ -20,13 +20,10 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.JvmAbi 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.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies 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<*>> override val nestedClasses: Collection<KClass<*>>
get() = descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors().filterNot(DescriptorUtils::isEnumEntry).mapNotNull { get() = descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors().filterNot(DescriptorUtils::isEnumEntry).mapNotNull {
nestedClass -> nestedClass ->
(nestedClass as ClassDescriptor).toJavaClass() ?: run { val jClass = (nestedClass as ClassDescriptor).toJavaClass()
// If neither a Kotlin class nor a Java class, it must be a built-in jClass?.let { KClassImpl(it) }
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) }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private val objectInstance_ = ReflectProperties.lazy { private val objectInstance_ = ReflectProperties.lazy {
@@ -18,10 +18,15 @@ package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.load.java.components.RuntimeSourceElementFactory 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.ReflectJavaClass
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
import org.jetbrains.kotlin.name.FqName 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.FunctionReference
import kotlin.jvm.internal.PropertyReference import kotlin.jvm.internal.PropertyReference
import kotlin.reflect.IllegalCallableAccessException import kotlin.reflect.IllegalCallableAccessException
@@ -38,12 +43,36 @@ internal fun ClassDescriptor.toJavaClass(): Class<*>? {
(source.javaElement as ReflectJavaClass).element (source.javaElement as ReflectJavaClass).element
} }
else -> { else -> {
// This is a built-in class // 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
null // 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 // TODO: wrap other exceptions
internal inline fun <R> reflectionCall(block: () -> R): R = internal inline fun <R> reflectionCall(block: () -> R): R =
try { try {