Inherit KType from KAnnotatedElement, implement KType.annotations
#KT-16795 Fixed
This commit is contained in:
committed by
Ilya Gorbunov
parent
e4bbe2d5e2
commit
ceb909d261
@@ -61,7 +61,7 @@ internal class AnnotationConstructorCaller(
|
||||
value ?: throwIllegalArgumentType(index, parameterNames[index], erasedParameterTypes[index])
|
||||
}
|
||||
|
||||
return createAnnotationInstance(jClass, methods, parameterNames.zip(values).toMap())
|
||||
return createAnnotationInstance(jClass, parameterNames.zip(values).toMap(), methods)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,11 @@ private fun throwIllegalArgumentType(index: Int, name: String, expectedJvmType:
|
||||
throw IllegalArgumentException("Argument #$index $name is not of the required type $typeString")
|
||||
}
|
||||
|
||||
private fun createAnnotationInstance(annotationClass: Class<*>, methods: List<ReflectMethod>, values: Map<String, Any>): Any {
|
||||
internal fun <T : Any> createAnnotationInstance(
|
||||
annotationClass: Class<T>,
|
||||
values: Map<String, Any>,
|
||||
methods: List<ReflectMethod> = values.keys.map { name -> annotationClass.getDeclaredMethod(name) }
|
||||
): T {
|
||||
fun equals(other: Any?): Boolean =
|
||||
(other as? Annotation)?.annotationClass?.java == annotationClass &&
|
||||
methods.all { method ->
|
||||
@@ -163,7 +167,7 @@ private fun createAnnotationInstance(annotationClass: Class<*>, methods: List<Re
|
||||
}
|
||||
}
|
||||
|
||||
return Proxy.newProxyInstance(annotationClass.classLoader, arrayOf(annotationClass)) { _, method, args ->
|
||||
val result = Proxy.newProxyInstance(annotationClass.classLoader, arrayOf(annotationClass)) { _, method, args ->
|
||||
val name = method.name
|
||||
when (name) {
|
||||
"annotationType" -> annotationClass
|
||||
@@ -176,4 +180,7 @@ private fun createAnnotationInstance(annotationClass: Class<*>, methods: List<Re
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return result as T
|
||||
}
|
||||
|
||||
@@ -112,6 +112,9 @@ internal class KTypeImpl(
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = type.isMarkedNullable
|
||||
|
||||
override val annotations: List<Annotation>
|
||||
get() = type.computeAnnotations()
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is KTypeImpl && type == other.type
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.reflect.jvm.internal;
|
||||
|
||||
/* package */ class Util {
|
||||
public static Object getEnumConstantByName(Class<? extends Enum<?>> enumClass, String name) {
|
||||
// This is a workaround for KT-5191. Enum#valueOf cannot be called in Kotlin
|
||||
return Enum.valueOf((Class) enumClass, name);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package kotlin.reflect.jvm.internal
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.isEffectivelyInlineOnly
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
@@ -30,6 +31,8 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.constants.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
@@ -102,10 +105,38 @@ internal fun Annotated.computeAnnotations(): List<Annotation> =
|
||||
when (source) {
|
||||
is ReflectAnnotationSource -> source.annotation
|
||||
is RuntimeSourceElementFactory.RuntimeSourceElement -> (source.javaElement as? ReflectJavaAnnotation)?.annotation
|
||||
else -> null
|
||||
else -> it.toAnnotationInstance()
|
||||
}
|
||||
}
|
||||
|
||||
private fun AnnotationDescriptor.toAnnotationInstance(): Annotation? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val annotationClass = annotationClass?.toJavaClass() as? Class<out Annotation> ?: return null
|
||||
|
||||
return createAnnotationInstance(
|
||||
annotationClass,
|
||||
allValueArguments.entries
|
||||
.mapNotNull { (name, value) -> value.toRuntimeValue(annotationClass.classLoader)?.let(name.asString()::to) }
|
||||
.toMap()
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: consider throwing exceptions such as AnnotationFormatError/AnnotationTypeMismatchException if a value of unexpected type is found
|
||||
private fun ConstantValue<*>.toRuntimeValue(classLoader: ClassLoader): Any? = when (this) {
|
||||
is AnnotationValue -> value.toAnnotationInstance()
|
||||
is ArrayValue -> value.map { it.toRuntimeValue(classLoader) }.toTypedArray()
|
||||
is EnumValue -> {
|
||||
val (enumClassId, entryName) = value
|
||||
loadClass(classLoader, enumClassId.packageFqName.asString(), enumClassId.relativeClassName.asString())?.let { enumClass ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
Util.getEnumConstantByName(enumClass as Class<out Enum<*>>, entryName.asString())
|
||||
}
|
||||
}
|
||||
is KClassValue -> (value.constructor.declarationDescriptor as? ClassDescriptor)?.toJavaClass()
|
||||
is ErrorValue, is NullValue -> null
|
||||
else -> value // Primitives and strings
|
||||
}
|
||||
|
||||
// TODO: wrap other exceptions
|
||||
internal inline fun <R> reflectionCall(block: () -> R): R =
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user