I have the following simple custom task with a custom property delegate:
import kotlin.reflect.KProperty
class MyDelegate<T : Any>(val default: T) {
var curVal = default
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return curVal
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
curVal = value
}
}
class MyTask : DefaultTask() {
@get:Internal
var x by MyDelegate("XXXXXX")
@TaskAction
fun run() {
println("hello")
}
}
val mytask by tasks.registering(MyTask::class) {
}
But when I try to run the task, it fails with the following error:
$ gradle mytask
[...]
Script compilation errors:
Line 17: var x by MyDelegate("XXXXXX")
^ Type 'TypeVariable(T)' has no method 'getValue(Build_gradle.MyTask, KProperty<*>)' and thus it cannot serve as a delegate
Line 17: var x by MyDelegate("XXXXXX")
^ Type 'TypeVariable(T)' has no method 'setValue(Build_gradle.MyTask, KProperty<*>, [ERROR : Type from delegate])' and thus it cannot serve as a delegate for var (read-write property)
On the other hand, the following Kotlin script file is executed by kotlinc without any issues:
$ cat test.kts
import kotlin.reflect.KProperty
class MyDelegate<T : Any>(val default: T) {
var curVal = default
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return curVal
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
curVal = value
}
}
class MyTask {
var x by MyDelegate("XXXXXX")
fun run() {
println("hello")
}
}
val t = MyTask()
println(t.x)
t.run()
$ kotlinc -script test.kts
XXXXXX
hello
If I make thisRef
be a generic type it works:
$ cat build.gradle.kts
import kotlin.reflect.KProperty
class MyDelegate<T : Any, S : Any>(val default: T) {
var curVal = default
operator fun getValue(thisRef: S?, property: KProperty<*>): T {
return curVal
}
operator fun setValue(thisRef: S?, property: KProperty<*>, value: T) {
curVal = value
}
}
open class MyTask : DefaultTask() {
@get:Internal
var x by MyDelegate<String, MyTask>("XXXXXX")
@TaskAction
fun run() {
println("hello")
}
}
val mytask by tasks.registering(MyTask::class) {
}
$ gradle mytask
> Task :mytask
hello
BUILD SUCCESSFUL in 346ms
1 actionable task: 1 executed
But it’s annoying to have to manually specify the types in MyDelegate<String, MyTask>
, since MyTask
can’t be inferred by Kotlin.
Is it possible make this work somehow?