Fix deserialization of enum annotation arguments at runtime

This commit is contained in:
Alexander Udalov
2015-02-27 17:22:02 +03:00
parent f36ef6f546
commit 4fb420f3f1
12 changed files with 177 additions and 13 deletions
@@ -22,10 +22,10 @@ import org.jetbrains.kotlin.name.Name
abstract class ReflectJavaAnnotationArgument(
override val name: Name?
) : JavaAnnotationArgument {
class object {
default object Factory {
fun create(value: Any, name: Name?): ReflectJavaAnnotationArgument {
return when {
value.javaClass.isEnum() -> ReflectJavaEnumValueAnnotationArgument(name, value)
value.javaClass.isEnumClassOrSpecializedEnumEntryClass() -> ReflectJavaEnumValueAnnotationArgument(name, value as Enum<*>)
value is Annotation -> ReflectJavaAnnotationAsAnnotationArgument(name, value)
value is Array<Any> -> ReflectJavaArrayAnnotationArgument(name, value)
value is Class<*> -> ReflectJavaClassObjectAnnotationArgument(name, value)
@@ -49,9 +49,13 @@ class ReflectJavaArrayAnnotationArgument(
class ReflectJavaEnumValueAnnotationArgument(
name: Name?,
private val value: Any
private val value: Enum<*>
) : ReflectJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument {
override fun resolve() = ReflectJavaField(value.javaClass.getDeclaredField(value.toString()))
override fun resolve(): ReflectJavaField {
val clazz = value.javaClass
val enumClass = if (clazz.isEnum()) clazz else clazz.getEnclosingClass()
return ReflectJavaField(enumClass.getDeclaredField(value.name()))
}
}
class ReflectJavaClassObjectAnnotationArgument(
@@ -80,7 +80,11 @@ public class ReflectJavaClass(private val klass: Class<*>) : ReflectJavaElement(
.map(::ReflectJavaField)
.toList()
override fun getConstructors() = klass.getDeclaredConstructors().map(::ReflectJavaConstructor)
override fun getConstructors() = klass.getDeclaredConstructors()
.stream()
.filter { constructor -> !constructor.isSynthetic() }
.map(::ReflectJavaConstructor)
.toList()
override fun getDefaultType(): ReflectJavaClassifierType = throw UnsupportedOperationException()
@@ -34,6 +34,9 @@ private fun calculateVisibility(modifiers: Int): Visibility {
}
}
public fun Class<*>.isEnumClassOrSpecializedEnumEntryClass(): Boolean =
javaClass<Enum<*>>().isAssignableFrom(this)
public val Class<*>.fqName: FqName
get() = classId.asSingleFqName().toSafe()
@@ -159,19 +159,21 @@ private object ReflectClassStructure {
visitor.visit(name, value)
}
javaClass<Enum<*>>().isAssignableFrom(clazz) -> {
visitor.visitEnum(name, clazz.classId, Name.identifier(value.toString()))
// isEnum returns false for specialized enum constants (enum entries which are subclasses)
val classId = (if (clazz.isEnum()) clazz else clazz.getEnclosingClass()).classId
visitor.visitEnum(name, classId, Name.identifier((value as Enum<*>).name()))
}
javaClass<Annotation>().isAssignableFrom(clazz) -> {
clazz.isAnnotation() -> {
// TODO: support values of annotation types
throw UnsupportedOperationException("Values of annotation types are not yet supported in Kotlin reflection: $value")
}
clazz.isArray() -> {
val elementVisitor = visitor.visitArray(name) ?: return
val componentType = clazz.getComponentType()
if (javaClass<Enum<*>>().isAssignableFrom(componentType)) {
val componentClassName = componentType.classId
if (componentType.isEnum()) {
val enumClassId = componentType.classId
for (element in value as Array<*>) {
elementVisitor.visitEnum(componentClassName, Name.identifier(element.toString()))
elementVisitor.visitEnum(enumClassId, Name.identifier((element as Enum<*>).name()))
}
}
else {