kotlin:试图通过反射调用其他类的功能时,违法
我尝试通过反射在Kotlin中调用方法,但行之有效。
我的代码(简单地列出,null-Checks and Catch-exceptions省略):
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)
}
}
}
}
}
因此,首先,我仅收集了Parammap中的所有参数,但这导致“ Java.lang.illang.illegalgumentException:没有提供必需参数的参数:fun of Fun的实例参数。 ..“。
幸运的是,我在这里找到了对我有帮助的问题:
因此我将零件添加了,如果(方法为callableReference)
。但是现在我得到了一个“ java.lang.illegalgumentException:对象不是声明类的实例”。
我还尝试使用method.call()
而不是method.callby()
:
...
var paramArray = arrayOf<Any>()
...
paramArray = paramArray.plus(paramValue)
...
method.call(*paramArray)
但这给出了相同的结果。如果没有实例参数,我会得到一个“ java.lang.illegalgumentException:Callable期望有2个参数,但提供了1个。”。使用实例参数,相同的“ java.lang.illegalgumentException:对象不是声明类的实例”,
然后我尝试在同一类中调用方法: 我在mycallerclass中创建了一个新方法:
fun myLocalMethod(strParam: String, intParam: Int): String {
return strParam
}
然后我在fun handlequest
中添加了一个方法:
val myLocalMethodFunc = ::myLocalMethod
val returnStr = myLocalMethodFunc.call("test", 3)
它奏效了! O_O
因此,谁能解释
- 为什么对本地函数的调用工作以及远程函数的呼叫行为不行?它们都是Kfunction的类型。
- 如何调用远程功能?如何以正确的方式提供实例参数?
- 为什么我不能调试
method.callby()
或method.call()
?那将对我有很大帮助,但是Intellij只是跳上它。
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:
- Error when use callBy on a function with default parameters in Kotlin
- Is there a way to get Kotlin function's owner via reflection
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()
ormethod.call()
? That would help me a lot, but IntelliJ just jumps over it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我找到了解决方案! wartoshika的答案使我了解到:我的功能不是静态的,它们位于单例内。
问题在于我收集功能的地方。正如我在对问题的评论中写的那样,提供要调用的函数的类,请执行所有操作
return listof(myimplementingclass :: mycallablemethod)
。那就是问题。应该是返回列表(:: myCallableMethod)
。然后行
PARAMMAP [Method.InstanceParameter !!] = Method.howner
导致NullPoInterException。通过删除该行,代码有效:)当没有错误时,我也可以调试到Callby()。我无法进行调试,因为代码无法找到要跳到的功能。
I found the solution! The answer of Wartoshika lead me to it: My functions aren't static and they are located within singletons.
The problem is in the place where I collect the functions. As I wrote in the comment to my question, the classes, that provide the functions to be called, do all something like
return listOf(MyImplementingClass::myCallableMethod)
. That is the problem. It should bereturn listOf(::myCallableMethod)
instead.Then the line
paramMap[method.instanceParameter!!] = method.owner
results in a NullPointerException. And by removing that line, the code works :)And when there's no error, I can also debug into the callBy(). I couldn't debug into it, because the code wasn't able to find the function to jump to.
生病尝试给出答案。
夹心三个重要状态:
每个状态都必须以不同的方式处理,因为它们需要一些额外的知识,需要参数。
1。非静态非对象Java或Kotlin类方法
呼叫
方法的第一个参数必须是该类别的不可用的实例或从反射类派生的实例。示例:
2。静态Java方法
访问静态Java方法时,您必须将
null
作为实例参数传递。这是可能的,因为您在没有具体实例的情况下调用静态方法。示例:
3。Kotlin对象类方法
我不知道为什么,但是对于Singleton对象,不需要实例参数。我认为这背后的原因是对此类方法的引用保留了有关其类别的信息。然后,Kotlin可以单独接收实例变量,因为整个JVM中只能存在一个实例。
示例:
当您尝试通过参考操作员访问本地函数时,此确切的行为将适用。考虑以下示例:
您的问题的想法:
当我创建一个非常简单的环境来测试它时,它可以很好地工作
也许这是您问题的启动。如果没有回答您的问题之一,请回复。
Ill try to give an answer.
concider three important states:
Every of there states has to be handled differently as they require some extra knowledge of wich parameters are required.
1. Non static non object Java or Kotlin classes method
The first parameter to the
call
method has to be a not nullable instance of that class or an instance that derived from the reflecting class.Example:
2. Static Java method
When accessing a static Java method you have to pass
null
as the instance parameter. This is possible since you call a static method without a concrete instance.Example:
3. Kotlin object classes method
I don't know why but for singleton objects no instance parameter is required. I think that the reason behind this is that a reference to such methods holds information about its class. Kotlin then can receive the instance variable on its own because only one instance can exists within the whole jvm.
Example:
This exact behaviour applies when you try to access a local function via reference operator. Consider the following example:
Ideas to your Question:
When i have created a very simple environment to test this it worked fine
. There are multiple possabilities. One i can think of:
Maybe this is a kickstart to your questions. Please reply if one of your question is not answered.