I've come across an issue where some Java code is ...
# getting-started
p
I've come across an issue where some Java code is using org.apache.commons.beanutils.PropertyUtils.setProperty to try and set a property on a Kotlin class. I've annotated the field with @JvmField to get past the first issue I had, and now I'm getting
Unknown property 'someField' on class 'class rubbish.SomeKotlinClass'
Is there a way of making Kotlin POJO type classes 100% compatible with code like PropertyUtils that relies on Java reflection ?
Copy code
// <https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils>
implementation("commons-beanutils:commons-beanutils:1.9.3")
Copy code
package rubbish

import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import org.apache.commons.beanutils.PropertyUtils
import org.junit.jupiter.api.Test

data class SomeKotlinClass(
    @JvmField
    var someField: String? = null,
)

class SetTest {

    @Test
    fun kotlinTestData() {

        val x = SomeKotlinClass::class.java.getDeclaredConstructor().newInstance()

        x.shouldNotBeNull()

        val fields = SomeKotlinClass::class.java.declaredFields
        fields.forEach {
            println("Field is $it")
            println("trying to get field")
            SomeKotlinClass::class.java.getField(it.name)
            println("got field")
        }

        PropertyUtils.setProperty(x,"someField","hello")

        x.someField shouldBe "hello"
    }
}
e
non-
@JvmField
properties should be compatible with Java Bean conventions. why did you need it?
p
because if you don't have it the same code fails with a NoSuchFieldException. Maybe that's the issue I should focus on. The test case posted is basically what the Java code that I have in production is doing (it gets a field and later on tries to set it; I can't change the Java code (it's in a company jar that I can't change). If I convert SomeKotlinClass back to java it works fine.
e
Copy code
data class SomeKotlinClass(
    var someField: String? = null,
)

fun main(vararg args: String) {
    val x = SomeKotlinClass::class.java.getDeclaredConstructor().newInstance()
    PropertyUtils.setProperty(x,"someField","hello")
    println(x)
}
this works fine for me, prints
SomeKotlinClass(someField=hello)
p
Yes that works, but the code I'm using does a getField before the set property. So :
Copy code
SomeKotlinClass::class.java.getField("someField")
fails, but works if SomeKotlinClass is in Java
e
that code assumes that the backing field is
public
, which is a pretty terrible idea
you could express the same as what I assume you were doing in Java,
Copy code
class SomeKotlinClass {
    @JvmField
    var someField: String? = null
    fun getSomeField(): String? = someField
    fun setSomeField(someField: String?) {
        this.someField = someField
    }
}
but Kotlin's not going to assist you with that
👍 1
p
Thanks,I'm going to do some more digging, with a better example.
It turns out that the only reason the Java porous work in our production code is indeed because they have been defined as being public, so I could manually add getters and a JVM field, but I might has well leave them in Java. Thanks again.