Si je suis sur la JVM, je peux faire ceci:
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" } }
et l'exécuter affichera Méthode invoquée: put
. Comment puis-je faire quelque chose comme ça dans un projet Kotlin commun ?
Modifier: je n'essaye pas d'utiliser quoi que ce soit de Java dans mon module commun . Je sais comment fonctionnent les projets communs. Ce qui m'intéresse à la place, c'est de savoir s'il existe ou non une solution basée sur Kotlin.
Édition 2: Je n'essaye pas de créer un proxy pour la carte
classe. Je recherche quelque chose comme Proxy
dans le JDK que je peux utiliser pour proxy n'importe quelle interface . Désolé pour la confusion.
3 Réponses :
Probablement Expect / Actual Factory devrait résoudre le problème.
Code commun:
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() }
Code Java:
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" } }
Malheureusement, je ne connais aucune bibliothèque qui simplifie ce travail, vous devriez donc le faire à la main pour chaque plate-forme et interface.
Je n'essaye pas de créer un proxy pour une carte
. Je recherche une solution proxy avec laquelle je peux proxy n'importe quelle interface .
Je comprends ce que tu veux. Mais maintenant, cela n'est pas possible sans des efforts excessifs. Peut-être pas, mais ça y ressemble. Je mets à jour ma réponse pour montrer comment créer un proxy pour n'importe quelle interface.
La génération de code simplifiera le travail. Mais quelqu'un devrait écrire une bibliothèque qui génère le code.
Attention avec java.lang.reflect.Proxy
, il ne vous permet pas de lancer une exception de quelque type que ce soit (il les encapsulera pour suivre JLS) jonnyzzz.com/blog/2018/11/22/proxy
Je pense que la réponse simple est que la réflexion Kotlin Multi Platform ne prend pas en charge les proxies. Vous pouvez utiliser la solution expect
- réelle
de @ KamiSempai lorsque vous utilisez le module commun dans une application java, mais vous devrez trouver des alternatives pour JS et les cibles natives.
Il n'y a pas d'équivalent pour cela dans les versions actuelles de Kotlin Native. En regardant les autres réponses, ils semblent avoir des types réels dans les expect / actuals, mais le but d'un proxy en direct est de fournir un type au moment de l'exécution et de générer une instance compatible qui peut être déléguée.
C'est ainsi que fonctionnent des choses comme la modernisation. Plutôt que la génération source, les définitions d'interface sont mandatées en interne.
Pour l'instant, vous devrez faire source-gen, pour autant que je sache. C'est pour natif. Je ne suis pas sûr de JS.
Se mettre d'accord. Dans ce cas, la génération de code est le seul moyen de faire les astuces similaires aux astuces avec réflexion en Java.
Je ne prévois pas de prendre en charge le natif mais j'ai vu que JS a également une implémentation de Proxy
!
Vous ne pouvez pas utiliser Java Reflection dans le module commun. Parce qu'il s'agit d'une fonctionnalité Java et disponible uniquement dans le module Java.
J'ai édité ma réponse. Je sais que c'est une fonctionnalité Java, je comprends ce qu'est un projet commun. Je n'ai pas été en mesure de trouver une solution basée sur Kotlin, c'est pourquoi je pose la question.