繁体   English   中英

如何在Kotlin通用代码中创建动态代理?

[英]How to create a dynamic proxy in Kotlin common code?

如果我使用的是JVM,则可以执行以下操作:

object Playground {

    class DynamicInvocationHandler : InvocationHandler {

        @Throws(Throwable::class)
        override operator fun invoke(proxy: Any, method: Method, args: Array<Any>): Any {
            LOGGER.info("Invoked method: {}", method.name)

            return 42
        }

        companion object {

            private val LOGGER = LoggerFactory.getLogger(
                    DynamicInvocationHandler::class.java)
        }
    }

    @JvmStatic
    fun main(args: Array<String>) {
        val proxy = Proxy.newProxyInstance(
                Playground::class.java.classLoader,
                arrayOf<Class<*>>(MutableMap::class.java),
                DynamicInvocationHandler()) as MutableMap<String, String>

        proxy["foo"] = "bar"
    }
}

并运行此命令将打印Invoked method: put 我如何在Kotlin 共同项目中做类似的事情?

编辑:我不试图在我的通用模块中使用Java中的任何东西。 我知道常见项目的运作方式。 相反,我感兴趣的是是否有基于Kotlin的解决方案。

编辑2:我不尝试代理Map类。 我正在寻找JDK中的Proxy之类的东西,可以用来代理任何接口 对困惑感到抱歉。

可能期望/实际工厂应解决该问题。

通用代码:

interface ProxyMethod {
    val name: String
    // other properties
}

interface ProxyHandler {
    fun invoke(proxy: Any, method: ProxyMethod, args: Array<Any>): Any
}

expect object Logger {
    fun info(message: String, vararg arguments: Any)
}

expect object ProxyFactory {
    fun mutableMapWithProxy(handler: ProxyHandler): MutableMap<String, String>
}

private class ProxyHandlerImpl: ProxyHandler {
    override fun invoke(proxy: Any, method: ProxyMethod, args: Array<Any>): Any {
        Logger.info("Invoked method: {}", method.name)
        return 0
    }
}

object Common {
    fun doSomething() {
        val myMap = ProxyFactory.mutableMapWithProxy(ProxyHandlerImpl())
        myMap["foo"] = "bar"
    }
}

Java代码:

actual object Logger {

    private val instance = LoggerFactory.getLogger(
            DynamicInvocationHandler::class.java)

    actual fun info(message: String, vararg arguments: Any) {
        instance.info(message, *arguments)
    }
}

actual object ProxyFactory  {
    actual fun mutableMapWithProxy(handler: ProxyHandler): MutableMap<String, String> {
        return Proxy.newProxyInstance(
                Playground::class.java.classLoader,
                arrayOf<Class<*>>(MutableMap::class.java),
                ProxyHandlerAdapter(handler)) as MutableMap<String, String>
    }
}

class ProxyHandlerAdapter(private val handler: ProxyHandler) : InvocationHandler {

    @Throws(Throwable::class)
    override operator fun invoke(proxy: Any, method: Method, args: Array<Any>): Any {
        return handler.invoke(proxy, methodToProxyMethod(method), args)
    }

    fun methodToProxyMethod(method: Method): ProxyMethod {
        // convert Method to ProxyMethod
    }
}

@JvmStatic
fun main(args: Array<String>) {
    Common.doSomething()
}

不幸的是,我不知道有哪个库可以简化这项工作,因此您应该手动为每个平台和界面执行此操作。

我认为简单的答案是Kotlin Multi Platform反射不支持代理。 您可以使用@ KamiSempai的expect - actual在Java应用程序中使用通用模块时的解决方案,但你将需要找到JS和本地目标的替代品。

当前的Kotlin本机版本中没有与此等效的功能。 查看其他答案,它们似乎在期望/事实中具有实际类型,但实时代理的目的是在运行时提供类型并生成可以委托给其的兼容实例。

这就是Retrofit之类的工作方式。 接口定义不是内部源,而是源代。

就目前而言,据我所知,您需要做source-gen。 那是本地人的。 不确定JS。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM