# 便捷的反射工具

# 介绍

TabooLib 内置了专属的反射依赖库 https://github.com/TabooLib/reflex (opens new window) Reflex 为基于 Kotlin 语言开发的反射工具,其与 Java 原生反射 API 及 kotlin-reflect 间最大区别在于其可无视软兼容反射目标类中的字段或方法。 你无需了解这么多 只需要看看有没有遇到这种情况:

  1. 想获取一个private的变量
  2. 想执行一个private的方法

# 用法

class TestNoEdit(){
    private var a = 0
    private fun say(){
        println("say")
    }
}

fun test(){
    val test = TestNoEdit()
    test.a = 1 // 并不可以这样

    //
    val property = test.getProperty<Int>("a") ?: 0

    test.invokeMethod<Any>("say")

    TestNoEdit::class.java.invokeConstructor()
}

至此 成为反射的神!

# 获取字段参数

test.getProperty<字段类型>("字段的名称")
// T:
val property = test.getProperty<Int>("a") ?: 0

那,老师 如果我不知道用什么字段类型应该怎么办?
可以使用 Any

test.getProperty<Any>("a")

# 设置字段内容

test.setProperty("字段的名称","要设置的值")
test.setProperty("a",10)

# 运行方法

invokeConstructor(构造函数的类型)
// 例如 构造函数需要两个字符串 
invokeConstructor(String::class.java,String::class.java)

# 获取构造函数

invokeConstructor(构造函数的类型)
// 例如 构造函数需要两个字符串 
invokeConstructor(String::class.java,String::class.java)

# 案例 - 扫包读取某class的注解进行注册 6.1

@Awake
object GermUIHook : ClassVisitor(5) {

    // 在什么时机进行扫描
    override fun getLifeCycle(): LifeCycle {
        return LifeCycle.ENABLE
    }

    // 扫描类,同级的还有扫描方法 和 扫描常量的
    override fun visitStart(clazz: Class<*>, instance: Supplier<*>?) {
        // 判断是否实现了 IGermUI 接口
        if (clazz.interfaces.contains(IGermUI::class.java)) {
            // 判断是否这个类被  @HookGerm("value") 修饰
            if (clazz.isAnnotationPresent(HookGerm::class.java)) {
                // 获取注解 @HookGerm
                val hook = clazz.getAnnotation(HookGerm::class.java)
                // 取出内容并添加到 Map中
                hookMap[hook.value] = clazz as Class<IGermUI>
            } else {
                val name = clazz.simpleName
                hookMap[name] = clazz as Class<IGermUI>
            }
        }
    }
 }
/**
 * 当类开始加载时
 *
 * @param clazz    类
 * @param instance 实例
 */
public void visitStart(@NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
}

/**
 * 当类结束加载时
 *
 * @param clazz    类
 * @param instance 实例
 */
public void visitEnd(@NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
}

/**
 * 当字段加载时
 *
 * @param field    字段
 * @param clazz    类
 * @param instance 实例
 */
public void visit(@NotNull ClassField field, @NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
}

/**
 * 当方法加载时
 *
 * @param method   方法
 * @param clazz    类
 * @param instance 实例
 */
public void visit(@NotNull ClassMethod method, @NotNull Class<?> clazz, @Nullable Supplier<?> instance) {
}

# 案例 - 扫包注册papi变量 6.2

    @Awake
    @Inject
    class PlaceholderRegister : ClassVisitor(0) {

        val hooked by unsafeLazy {
            runCatching { Class.forName("me.clip.placeholderapi.expansion.PlaceholderExpansion") }.isSuccess
        }

        override fun visitStart(clazz: ReflexClass) {
            if (hooked && clazz.structure.interfaces.any { it.name == PlaceholderExpansion::class.java.name }) {
                val expansion = findInstance(clazz) as? PlaceholderExpansion ?: error("PlaceholderExpansion must have an instance")
                if (!expansion.enabled) {
                    return
                }
                object : me.clip.placeholderapi.expansion.PlaceholderExpansion() {

                    override fun persist(): Boolean {
                        return true
                    }

                    override fun getIdentifier(): String {
                        return expansion.identifier
                    }

                    override fun getAuthor(): String {
                        return BukkitPlugin.getInstance().description.authors.toString()
                    }

                    override fun getVersion(): String {
                        return BukkitPlugin.getInstance().description.version
                    }

                    override fun onPlaceholderRequest(player: Player?, params: String): String {
                        return expansion.onPlaceholderRequest(player, params)
                    }

                    override fun onRequest(player: OfflinePlayer?, params: String): String {
                        return expansion.onPlaceholderRequest(player, params)
                    }
                }.also { papiExpansion ->
                    // 自动重载
                    if (expansion.autoReload) {
                        registerBukkitListener(ExpansionUnregisterEvent::class.java) {
                            if (it.expansion == papiExpansion) {
                                submit { papiExpansion.register() }
                            }
                        }
                    }
                }.register()
            }
        }

        override fun getLifeCycle(): LifeCycle {
            return LifeCycle.ENABLE
        }
    }

进阶

8分钟

介绍

用法

获取字段参数

设置字段内容

运行方法

获取构造函数

案例 - 扫包读取某class的注解进行注册 6.1

案例 - 扫包注册papi变量 6.2