Support Java annotation constructors in reflection
#KT-13106 In Progress
This commit is contained in:
@@ -26,17 +26,31 @@ internal class AnnotationConstructorCaller(
|
||||
private val jClass: Class<*>,
|
||||
private val parameterNames: List<String>,
|
||||
private val callMode: CallMode,
|
||||
origin: Origin,
|
||||
methods: List<ReflectMethod> = parameterNames.map { name -> jClass.getDeclaredMethod(name) }
|
||||
) : FunctionCaller<Nothing?>(
|
||||
null, jClass, null, methods.map { it.genericReturnType }.toTypedArray()
|
||||
) {
|
||||
enum class CallMode { CALL_BY_NAME, POSITIONAL_CALL }
|
||||
|
||||
enum class Origin { JAVA, KOTLIN }
|
||||
|
||||
// Transform primitive int to java.lang.Integer because actual arguments passed here will be boxed and Class#isInstance should succeed
|
||||
private val erasedParameterTypes: List<Class<*>> = methods.map { method -> method.returnType.let { it.wrapperByPrimitive ?: it } }
|
||||
|
||||
private val defaultValues: List<Any?> = methods.map { method -> method.defaultValue }
|
||||
|
||||
init {
|
||||
// TODO: consider lifting this restriction once KT-8957 is implemented
|
||||
if (callMode == CallMode.POSITIONAL_CALL && origin == Origin.JAVA && (parameterNames - "value").isNotEmpty()) {
|
||||
throw UnsupportedOperationException(
|
||||
"Positional call of a Java annotation constructor is allowed only if there are no parameters " +
|
||||
"or one parameter named \"value\". This restriction exists because Java annotations (in contrast to Kotlin)" +
|
||||
"do not impose any order on their arguments. Use KCallable#callBy instead."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
import kotlin.reflect.jvm.internal.AnnotationConstructorCaller.CallMode.CALL_BY_NAME
|
||||
import kotlin.reflect.jvm.internal.AnnotationConstructorCaller.CallMode.POSITIONAL_CALL
|
||||
import kotlin.reflect.jvm.internal.AnnotationConstructorCaller.Origin.JAVA
|
||||
import kotlin.reflect.jvm.internal.AnnotationConstructorCaller.Origin.KOTLIN
|
||||
import kotlin.reflect.jvm.internal.JvmFunctionSignature.*
|
||||
|
||||
internal class KFunctionImpl private constructor(
|
||||
@@ -55,12 +57,16 @@ internal class KFunctionImpl private constructor(
|
||||
val member: Member? = when (jvmSignature) {
|
||||
is KotlinConstructor -> {
|
||||
if (isAnnotationConstructor)
|
||||
return@caller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, POSITIONAL_CALL)
|
||||
return@caller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, POSITIONAL_CALL, KOTLIN)
|
||||
container.findConstructorBySignature(jvmSignature.constructorDesc, isDeclared())
|
||||
}
|
||||
is KotlinFunction -> container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc, isDeclared())
|
||||
is JavaMethod -> jvmSignature.method
|
||||
is JavaConstructor -> jvmSignature.constructor
|
||||
is FakeJavaAnnotationConstructor -> {
|
||||
val methods = jvmSignature.methods
|
||||
return@caller AnnotationConstructorCaller(container.jClass, methods.map { it.name }, POSITIONAL_CALL, JAVA, methods)
|
||||
}
|
||||
is BuiltInFunction -> jvmSignature.getMember(container)
|
||||
}
|
||||
|
||||
@@ -86,9 +92,13 @@ internal class KFunctionImpl private constructor(
|
||||
}
|
||||
is KotlinConstructor -> {
|
||||
if (isAnnotationConstructor)
|
||||
return@defaultCaller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, CALL_BY_NAME)
|
||||
return@defaultCaller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, CALL_BY_NAME, KOTLIN)
|
||||
container.findDefaultConstructor(jvmSignature.constructorDesc, isDeclared())
|
||||
}
|
||||
is FakeJavaAnnotationConstructor -> {
|
||||
val methods = jvmSignature.methods
|
||||
return@defaultCaller AnnotationConstructorCaller(container.jClass, methods.map { it.name }, CALL_BY_NAME, JAVA, methods)
|
||||
}
|
||||
else -> {
|
||||
// Java methods, Java constructors and built-ins don't have $default methods
|
||||
null
|
||||
|
||||
@@ -71,9 +71,15 @@ internal sealed class JvmFunctionSignature {
|
||||
|
||||
class JavaConstructor(val constructor: Constructor<*>) : JvmFunctionSignature() {
|
||||
override fun asString(): String =
|
||||
"<init>" +
|
||||
constructor.parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { it.desc } +
|
||||
"V"
|
||||
constructor.parameterTypes.joinToString(separator = "", prefix = "<init>(", postfix = ")V") { it.desc }
|
||||
}
|
||||
|
||||
class FakeJavaAnnotationConstructor(val jClass: Class<*>) : JvmFunctionSignature() {
|
||||
// Java annotations do not impose any order of methods inside them, so we consider them lexicographic here for stability
|
||||
val methods = jClass.declaredMethods.sortedBy { it.name }
|
||||
|
||||
override fun asString(): String =
|
||||
methods.joinToString(separator = "", prefix = "<init>(", postfix = ")V") { it.returnType.desc }
|
||||
}
|
||||
|
||||
open class BuiltInFunction(private val signature: String) : JvmFunctionSignature() {
|
||||
@@ -189,10 +195,14 @@ internal object RuntimeTypeMapper {
|
||||
return JvmFunctionSignature.JavaMethod(method)
|
||||
}
|
||||
is JavaClassConstructorDescriptor -> {
|
||||
val constructor = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaConstructor)?.member ?:
|
||||
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function")
|
||||
|
||||
return JvmFunctionSignature.JavaConstructor(constructor)
|
||||
val element = (function.source as? JavaSourceElement)?.javaElement
|
||||
when {
|
||||
element is ReflectJavaConstructor ->
|
||||
return JvmFunctionSignature.JavaConstructor(element.member)
|
||||
element is ReflectJavaClass && element.isAnnotationType ->
|
||||
return JvmFunctionSignature.FakeJavaAnnotationConstructor(element.element)
|
||||
else -> throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function ($element)")
|
||||
}
|
||||
}
|
||||
else -> throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user