4

如果我在 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课程。我正在寻找类似ProxyJDK 中的东西,我可以用它来代理任何接口。对困惑感到抱歉。

4

3 回答 3

1

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

通用代码:

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()
}

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

于 2019-01-23T13:10:32.917 回答
1

我认为简单的答案是 Kotlin 多平台反射不支持代理。在 java 应用程序中使用公共模块时,您可以使用@KamiSempai 的expect解决actual方案,但您需要找到 JS 和本机目标的替代方案。

于 2019-01-23T14:14:06.480 回答
0

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

这就是改造之类的工作方式。接口定义不是源生成,而是在内部代理。

目前,据我所知,您需要执行 source-gen。那是给本地人的。不知道 JS。

于 2019-01-23T14:47:38.043 回答