[Reflection] Support java records in kotlin reflection
^KT-47760
This commit is contained in:
committed by
teamcityserver
parent
8dad8fa813
commit
17fc1da719
+22
-6
@@ -97,9 +97,6 @@ class ReflectJavaClass(
|
||||
.map(::ReflectJavaConstructor)
|
||||
.toList()
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent>
|
||||
get() = emptyList()
|
||||
|
||||
override fun hasDefaultConstructor() = false // any default constructor is returned by constructors
|
||||
|
||||
override val lightClassOriginKind: LightClassOriginKind?
|
||||
@@ -118,9 +115,11 @@ class ReflectJavaClass(
|
||||
override val isEnum: Boolean
|
||||
get() = klass.isEnum
|
||||
|
||||
// TODO: Support reflect
|
||||
override val isRecord: Boolean
|
||||
get() = false
|
||||
get() = Java16SealedRecordLoader.loadIsRecord(klass) ?: false
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent>
|
||||
get() = (Java16SealedRecordLoader.loadGetRecordComponents(klass) ?: emptyArray()).map(::ReflectJavaRecordComponent)
|
||||
|
||||
override val isSealed: Boolean
|
||||
get() = Java16SealedRecordLoader.loadIsSealed(klass) ?: false
|
||||
@@ -141,6 +140,8 @@ private object Java16SealedRecordLoader {
|
||||
class Cache(
|
||||
val isSealed: Method?,
|
||||
val getPermittedSubclasses: Method?,
|
||||
val isRecord: Method?,
|
||||
val getRecordComponents: Method?
|
||||
)
|
||||
|
||||
private var _cache: Cache? = null
|
||||
@@ -152,9 +153,11 @@ private object Java16SealedRecordLoader {
|
||||
Cache(
|
||||
clazz.getMethod("isSealed"),
|
||||
clazz.getMethod("getPermittedSubclasses"),
|
||||
clazz.getMethod("isRecord"),
|
||||
clazz.getMethod("getRecordComponents")
|
||||
)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
Cache(null, null)
|
||||
Cache(null, null, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,4 +182,17 @@ private object Java16SealedRecordLoader {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return getPermittedSubclasses.invoke(clazz) as Array<Class<*>>
|
||||
}
|
||||
|
||||
fun loadIsRecord(clazz: Class<*>): Boolean? {
|
||||
val cache = initCache()
|
||||
val isRecord = cache.isRecord ?: return null
|
||||
return isRecord.invoke(clazz) as Boolean
|
||||
}
|
||||
|
||||
fun loadGetRecordComponents(clazz: Class<*>): Array<Any>? {
|
||||
val cache = initCache()
|
||||
val getRecordComponents = cache.getRecordComponents ?: return null
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return getRecordComponents.invoke(clazz) as Array<Any>?
|
||||
}
|
||||
}
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.descriptors.runtime.structure
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaRecordComponent
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType
|
||||
import java.lang.reflect.Member
|
||||
import java.lang.reflect.Method
|
||||
|
||||
class ReflectJavaRecordComponent(val recordComponent: Any) : ReflectJavaMember(), JavaRecordComponent {
|
||||
override val type: JavaType
|
||||
get() = Java16RecordComponentsLoader.loadGetType(recordComponent)?.let { ReflectJavaClassifierType(it) }
|
||||
?: throw NoSuchMethodError("Can't find `getType` method")
|
||||
override val isVararg: Boolean
|
||||
get() = false
|
||||
override val member: Member
|
||||
get() = Java16RecordComponentsLoader.loadGetAccessor(recordComponent)
|
||||
?: throw NoSuchMethodError("Can't find `getAccessor` method")
|
||||
}
|
||||
|
||||
private object Java16RecordComponentsLoader {
|
||||
class Cache(
|
||||
val getType: Method?,
|
||||
val getAccessor: Method?,
|
||||
)
|
||||
|
||||
private var _cache: Cache? = null
|
||||
|
||||
private fun buildCache(recordComponent: Any): Cache {
|
||||
// Should be Class<RecordComponent>
|
||||
val classOfComponent = recordComponent::class.java
|
||||
|
||||
return try {
|
||||
Cache(
|
||||
classOfComponent.getMethod("getType"),
|
||||
classOfComponent.getMethod("getAccessor"),
|
||||
)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
Cache(null, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCache(recordComponent: Any): Cache {
|
||||
var cache = this._cache
|
||||
if (cache == null) {
|
||||
cache = buildCache(recordComponent)
|
||||
this._cache = cache
|
||||
}
|
||||
return cache
|
||||
|
||||
}
|
||||
|
||||
fun loadGetType(recordComponent: Any): Class<*>? {
|
||||
val cache = initCache(recordComponent)
|
||||
val getType = cache.getType ?: return null
|
||||
return getType.invoke(recordComponent) as Class<*>
|
||||
}
|
||||
|
||||
fun loadGetAccessor(recordComponent: Any): Method? {
|
||||
val cache = initCache(recordComponent)
|
||||
val getType = cache.getAccessor ?: return null
|
||||
return getType.invoke(recordComponent) as Method
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user