dimanche 26 septembre 2021

InvocationHandler in Kotlin

I'm reading Head First: Design Patterns (2nd ed) and I followed the code sample but instead of using Java, I used Kotlin. Currently, I'm in a chapter tackling about proxy protection pattern and having difficulty to run it with Kotlin. Please see the code and exceptions below.

Sample code

interface Person {
    fun getName(): String
    fun setName(name: String)
}

class PersonImpl : Person {
    private var _name: String = ""
    override fun getName(): String = _name
    override fun setName(name: String) {
        _name = name
    }
}
class OwnerInvocationHandler(private val person: Person) : InvocationHandler {
    override fun invoke(proxy: Any?, method: Method, args: Array<Any>?): Any? {
        try {
            val methodName = method.name
            if (methodName.isNullOrEmpty())
                return null

            if (methodName.startsWith("get")) {
//              return method.invoke(proxy, *(args ?: arrayOfNulls<Any>(0))) // << Encountered "EXCEPTION B" below
//              return method.invoke(proxy, *(args ?: emptyArray()))         // << Encountered "EXCEPTION B" below
//              return method.invoke(proxy, *args.orEmpty())                 // << Encountered "EXCEPTION B" below
                return method.invoke(proxy, args)                            // << From the code sample, encountered "EXCEPTION A" below
            } else if (methodName.startsWith("set")) {
                return method.invoke(person, args)
            }
        } catch (e: InvocationTargetException) {
            e.printStackTrace()
        }
        return null
    }
}
// main.kt
val listOfPeople = arrayListOf<Person>()

fun main(array: Array<String>) {
    initializeDatabase()

    val joe = getPersonFromDatabase("Joe Javabean") ?: return
    val ownerProxy = getOwnerProxy(joe)
    println("Name is ${ownerProxy.getName()}")

}

fun initializeDatabase() {
    val p1 = PersonImpl()
    p1.setName("Joe Javabean")
    listOfPeople.add(p1)
}

fun getOwnerProxy(person: Person): Person {
    return Proxy.newProxyInstance(
            person.javaClass.classLoader,
            person.javaClass.interfaces,
            OwnerInvocationHandler(person)
    ) as Person
}

fun getPersonFromDatabase(name: String): Person? {
    return listOfPeople.firstOrNull { p -> name.contentEquals(p.getName()) }
}

Exception

Exception A

/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10a5ef4e0). One of the two will be used. Which one is undefined.
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.helloworld.app.OwnerInvocationHandler.invoke(OwnerInvocationHandler.kt:17)
    at com.sun.proxy.$Proxy0.getName(Unknown Source)
    at com.helloworld.app.MainKt.main(main.kt:12)

Exception B

objc[64094]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java (0x109e744c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x109eee4e0). One of the two will be used. Which one is undefined.
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
java.lang.reflect.InvocationTargetExceptionjava.lang.reflect.InvocationTargetException
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.helloworld.app.OwnerInvocationHandler.invoke(OwnerInvocationHandler.kt:17)
    at com.sun.proxy.$Proxy0.getName(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.helloworld.app.OwnerInvocationHandler.invoke(OwnerInvocationHandler.kt:17)
    at com.sun.proxy.$Proxy0.getName(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.helloworld.app.OwnerInvocationHandler.invoke(OwnerInvocationHandler.kt:17)
    at com.sun.proxy.$Proxy0.getName(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.helloworld.app.OwnerInvocationHandler.invoke(OwnerInvocationHandler.kt:17)
    at com.sun.proxy.$Proxy0.getName(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    ...

I found the link below but didn't solve my issue.

Kotlin: Argument Type Mismatch when passing Array as vararg parameter

Aucun commentaire:

Enregistrer un commentaire