mardi 7 juin 2022

Kotlin: IllegalArgumentException while trying to call function of other classes by reflection

I try to call methods by reflection in kotlin and it doesn't work.

My code (simplyfied, null-checks and catch-exceptions omitted):

class MyCallerClass() {

  val allCallableMethods: List<KFunction<Unit>> = ... 

  // request: we're within a web-page. The user can see the callable methods and click which one to call 
  fun handleRequest(request: HttpServletRequest) {

    val callableMethodName = request.getParameter(callableMethodNameParam)
    if (callableMethodName != null) {
      for (method in allCallableMethods) {
        if (method.name == callableMethodName) {
          // we found the method the user wants to call!

          val paramMap: MutableMap<KParameter, Any> = mutableMapOf()
            
          // this part I added after I got an IllegalArgumentException. See below
          if (method is CallableReference) {
            paramMap[method.instanceParameter!!] = method.owner
          }

          for (param in method.valueParameters) {
            val paramName = if (param.name != null) {
              param.name!!
            }

            val paramValue: String? = request.getParameter(paramName)
            if(paramValue != null) {
              paramMap[param] = paramValue
            }
          }

          method.callBy(paramMap)
        }
      }
    }
  }
}

So first I only collected all params in the paramMap, but that resulted in "java.lang.IllegalArgumentException: No argument provided for a required parameter: instance parameter of fun...".

Luckily I found questions here that helped me on:

So I added the part with if (method is CallableReference). But now I get a "java.lang.IllegalArgumentException: object is not an instance of declaring class".


I also tried to use method.call() instead of method.callBy():

...
var paramArray = arrayOf<Any>()
...
paramArray = paramArray.plus(paramValue)
...
method.call(*paramArray)

But that gave the same results. Without the instance-parameter I get a "java.lang.IllegalArgumentException: Callable expects 2 arguments, but 1 were provided.". With the instance-parameter the same "java.lang.IllegalArgumentException: object is not an instance of declaring class"


Then I tried to call a method within the same class: I created a new method in MyCallerClass:

fun myLocalMethod(strParam: String, intParam: Int): String {
  return strParam
}

and then I added this in fun handleRequest:

val myLocalMethodFunc = ::myLocalMethod
val returnStr = myLocalMethodFunc.call("test", 3)

And it worked! o_O


So can anyone explain

  • why the call to the local function works and to the remote function doesn't? They're both of the type KFunction.
  • how I can call the remote functions? How do I provide the instanceParameter in the correct way?
  • why I can't debug into method.callBy() or method.call()? That would help me a lot, but IntelliJ just jumps over it.




Aucun commentaire:

Enregistrer un commentaire