1

I'm trying to play around with Java reflection in Kotlin, and I have the following field in my Kotlin class:

val tree: Tree by lazy { 
    getTree(hashGroup, service) 
}

I'd like to set this field through Java reflection, and so far I got to this point:

val tField = transaction::class.java.getDeclaredField("tree\$delegate")
tField.isAccessible = true
tField.set(transaction, newTree)

Obviously this is not going to work, because the tree field has a delegate (tree$delegate) and it wants me to set it to a Lazy class type and not Tree type.

I know the easiest would be to actually add a setter for this field in the main class but I can't really modify the API and I need this for a resilience test case. Is this even possible to do?

h331z
  • 53
  • 5

1 Answers1

3

Just create a Lazy<T> instance like you normally would!

If you want to set it to the constant value newTree:

tField.set(transaction, lazyOf(newTree))

You can also set a new block of code for it to be evaluated lazily:

tField.set(transaction, lazy {
    Tree().apply {
        // do something lazily to this tree...
    }
})
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Getting this error: `Can not set static final kotlin.Lazy field fieldName$delegate to kotlin.InitializedLazyImpl `when using `lazyOf`, and getting : `Can not set static final fieldName$delegate to kotlin.SynchronizedLazyImpl` when using `lazy{}`, any solution? – Suraj Vaishnav Jan 03 '23 at 08:10
  • @SurajVaishnav It seems like whatever you have became a *static* field on the JVM side? Those are known to be tricky to set with reflection. See [this discussion](https://stackoverflow.com/q/3301635/5133585). Alternatively, find a way to make a non-static. – Sweeper Jan 03 '23 at 08:15