1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
package moe.nea.firmament.util.asm
import com.google.common.base.Defaults
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import org.objectweb.asm.Type
import org.objectweb.asm.tree.AnnotationNode
object AsmAnnotationUtil {
class AnnotationProxy(
val originalType: Class<out Annotation>,
val annotationNode: AnnotationNode,
) : InvocationHandler {
val offsets = annotationNode.values.withIndex()
.chunked(2)
.map { it.first() }
.associate { (idx, value) -> value as String to idx + 1 }
fun nestArrayType(depth: Int, comp: Class<*>): Class<*> =
if (depth == 0) comp
else java.lang.reflect.Array.newInstance(nestArrayType(depth - 1, comp), 0).javaClass
fun unmap(
value: Any?,
comp: Class<*>,
depth: Int,
): Any? {
value ?: return null
if (depth > 0)
return ((value as List<Any>)
.map { unmap(it, comp, depth - 1) } as java.util.List<Any>)
.toArray(java.lang.reflect.Array.newInstance(nestArrayType(depth - 1, comp), 0) as Array<*>)
if (comp.isEnum) {
comp as Class<out Enum<*>>
when (value) {
is String -> return java.lang.Enum.valueOf(comp, value)
is List<*> -> return java.lang.Enum.valueOf(comp, value[1] as String)
else -> error("Unknown enum variant $value for $comp")
}
}
when (value) {
is Type -> return Class.forName(value.className)
is AnnotationNode -> return createProxy(comp as Class<out Annotation>, value)
is String, is Boolean, is Byte, is Double, is Int, is Float, is Long, is Short, is Char -> return value
}
error("Unknown enum variant $value for $comp")
}
fun defaultFor(fullType: Class<*>): Any? {
if (fullType.isArray) return java.lang.reflect.Array.newInstance(fullType.componentType, 0)
if (fullType.isPrimitive) {
return Defaults.defaultValue(fullType)
}
if (fullType == String::class.java)
return ""
return null
}
override fun invoke(
proxy: Any,
method: Method,
args: Array<out Any?>?
): Any? {
val name = method.name
val ret = method.returnType
val retU = generateSequence(ret) { if (it.isArray) it.componentType else null }
.toList()
val arrayDepth = retU.size - 1
val componentType = retU.last()
val off = offsets[name]
if (off == null) {
return defaultFor(ret)
}
return unmap(annotationNode.values[off], componentType, arrayDepth)
}
}
fun <T : Annotation> createProxy(
annotationClass: Class<T>,
annotationNode: AnnotationNode
): T {
require(Type.getType(annotationClass) == Type.getType(annotationNode.desc))
return Proxy.newProxyInstance(javaClass.classLoader,
arrayOf(annotationClass),
AnnotationProxy(annotationClass, annotationNode)) as T
}
}
|