Si estoy en la JVM, puedo hacer esto:
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" } } y ejecutar esto imprimirá el Invoked method: put . ¿Cómo puedo hacer algo como esto en un proyecto común de Kotlin?
Editar: no estoy tratando de usar nada de Java en mi módulo común. Sé cómo funcionan los proyectos comunes. En cambio, lo que me interesa es si existe una solución basada en Kotlin para esto o no.
Edición 2: no estoy tratando de representar la clase Map . Estoy buscando algo como Proxy en el JDK que pueda usar para representar cualquier interfaz . Perdón por la confusion.
Probablemente Expect/Actual Factory debería resolver el problema.
Código común:
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" } }Código 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() }Lamentablemente, no conozco ninguna biblioteca que simplifique este trabajo, por lo que debe hacerlo a mano para cada plataforma e interfaz.
Creo que la respuesta simple es que la reflexión de Kotlin Multi Platform no admite proxies. Puede usar la expect de @KamiSempai: la solución actual cuando usa el módulo común en una aplicación Java, pero deberá encontrar alternativas para JS y objetivos nativos.
No hay equivalente para esto en las versiones nativas de Kotlin actuales. Al observar las otras respuestas, parecen tener tipos reales en las expectativas/reales, pero el propósito de un proxy en vivo es proporcionar un tipo en tiempo de ejecución y generar una instancia compatible que se pueda delegar.
Así es como funcionan cosas como Retrofit. En lugar de generación de origen, las definiciones de interfaz se envían internamente.
Por ahora, necesitarás hacer source-gen, hasta donde yo sé. Eso es para nativos. No estoy seguro acerca de JS.