如何从 Groovy 代码中调用 Kotlin 扩展函数?

问题描述 投票:0回答:1

我正在使用

kotlin-dsl
插件用 Kotlin 语言编写一个 Gradle 插件:

plugins {
    `kotlin-dsl`
}

我创建了一个插件类和一个扩展:

class MyPlugin : Plugin<Project> {

    private lateinit var extension: MyPluginExtension

    override fun apply(project: Project) {
        extension = project.extensions.create("myPluginExtension")
        ...
    }

}

我的扩展类中有一个中缀函数

foo

open class MyPluginExtension {

    infix fun String.foo(other: String) {
        ...
    }

}

插件用户应该如何使用我的插件(使用 Kotlin DSL):

plugins {
    id("my-plugin")
}

myPluginExtension {
    "first" foo "second"
}

我想为使用 Groovy 语言的插件用户提供相同的语法:

myPluginExtension {
    'first' foo 'second'   // cannot call Kotlin infix function using Groovy
    'first'.foo('second')  // this is not working too
    foo('first', 'second') // ok, but not desired syntax for me
}

我不太了解 Groovy,但我听说它有 扩展方法。如何让我的插件对 Groovy 爱好者来说看起来很酷?

如果不能直接进行函数调用,我相信有一种方法可以用 Groovy 语言创建一个包装器扩展方法来调用 Kotlin 扩展函数。

我发现了一个类似的问题Kotlin function parameter with receiver, called from Groovy,但这并不是我所需要的。

kotlin groovy gradle-plugin gradle-kotlin-dsl extension-function
1个回答
0
投票

我不熟悉 kotlin,所以,我将参考 java 作为基准

这是 groovy 世界中

String
类的扩展方法:

String.metaClass.foo = { x-> " foo( first:${delegate}, second:${x} ) "}


"aaa".foo "bbb"    //returns: foo( first:aaa, second:bbb )

在 java 中,您可以使用大约这段代码来为某些类注册扩展方法:

class MethodFoo extends groovy.lang.Closure{
    public MethodFoo(Object owner){
        super(owner);
    }
    Object doCall(String second){
        return "foo( first:" + getDelegate() + ", second:" + second + " )";
    }
}

//-------------------------------
var mc = GroovySystem.getMetaClassRegistry().getMetaClass(String.class);
Class []argTypes = { String.class };
String methodName = "foo"
if( !mc.hasMetaMethod(methodName, argTypes) ){
    //instead of null it could be a reference to a gradle project if you want to access it inside a method with getOwner()
    mc.registerInstanceMethod(methodName, new MethodFoo(null));
}

//---- after this point in groovy you can make this call:
"aaa".foo "bbb"    //should return: foo( first:aaa, second:bbb )


PS:语法实现还是可以的

"aaa" foo "bbb"

groovy 会将这一行翻译成大致如下代码:

plugin."aaa"( plugin.getProperty("foo") ).getProperty("bbb")

// where plugin."aaa" -> invoke method with name `"aaa"`

只要“aaa”是动态的——您可以在您的插件中实现GroovyObect invokeMethod,它将在任何未知方法调用时被调用

这种方法很棘手但可行。 我懒得用java实现它。这是一个可以在 groovy 控制台中运行的 groovy 代码:

class MethodFoo{
    String first
    Object getProperty(String name){
        println( "foo( first: $first, second: $name )" )
    }
}

class Plugin{
    MethodFoo getFoo(){
        return new MethodFoo()
    }
    
    Object invokeMethod(String name, Object args){
        if(args.length==1 && args[0] instanceof MethodFoo){
            args[0].first = name
            return args[0]
        }
        throw new Exception("method not found: $name")
    }
}


new Plugin().with{
    "aaa" foo "bbb"    //prints: foo( first: aaa, second: bbb )
}
© www.soinside.com 2019 - 2024. All rights reserved.