Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reflection 如何使用callBy()调用Kotlin companion factory方法?_Reflection_Kotlin_Kotlin Companion - Fatal编程技术网

Reflection 如何使用callBy()调用Kotlin companion factory方法?

Reflection 如何使用callBy()调用Kotlin companion factory方法?,reflection,kotlin,kotlin-companion,Reflection,Kotlin,Kotlin Companion,我让代码接受一个类作为参数,并准备好数据,以便在存在工厂方法的情况下,调用该类的构造函数或伴随对象工厂方法 调用构造函数时,所有这些都可以正常工作,但我得到了错误 java.lang.IllegalArgumentException: No argument provided for a required parameter: instance of fun nz.salect.objjson.JVMTest.StudentWithFactory.Companion.fromJson(kotli

我让代码接受一个类作为参数,并准备好数据,以便在存在工厂方法的情况下,调用该类的构造函数或伴随对象工厂方法

调用构造函数时,所有这些都可以正常工作,但我得到了错误

java.lang.IllegalArgumentException: No argument provided for a required parameter: instance of fun nz.salect.objjson.JVMTest.StudentWithFactory.Companion.fromJson(kotlin.String, kotlin.Int): nz.salect.objjson.JVMTest.StudentWithFactory
调用工厂方法时。有关的工厂方法:

data class StudentWithFactory(val name: String, val years: Int=0) {

    companion object {

        fun fromJson(name: String="", age: Int = 0):StudentWithFactory {
            return StudentWithFactory(name, age)
        }
    }
}
没有必需的参数,除非存在某些隐藏参数。有什么想法吗

事实上,我恢复了从
fromJson
中完全删除参数,并使用
直接调用伴随方法:fromJson.callby(emptyMap())
。同样的错误

显然,伴随方法至少需要一个附加参数。也许是上课?还是伴星? 如何指定所需的参数

为构建callBy()的函数提供了一个类(或从提供的类中查找该类)以及json名称和值

var funk:KFunction<*>?=null
val companionFuncs=cls.companionObject?.declaredMemberFunctions
if(companionFuncs?.size ?:0 >0){
    companionFuncs?.forEach {
        if(it.name == "fromJson") funk=it
    }

}
val cons:KFunction<T> = if(funk != null)
       funk as KFunction<T>
    else
       cls.primaryConstructor ?: throw IllegalArgumentException("no primary constructor ${cls.simpleName}")
val valuesMap = cons.parameters.filter{it.name in vals}
    .associateBy(
    {it},
    {generateValue(it)}
)
val data = cons.callBy(valuesMap) //as T
return data
var funk:KFunction?=null
val companionFuncs=cls.companionObject?.declaredMemberFunctions
if(companionFuncs?.size?:0>0){
公司职能?.forEach{
如果(it.name==“fromJson”)funk=it
}
}
val cons:KFunction=if(funk!=null)
funk as KFunction
其他的
cls.primaryConstructor?:抛出IllegalArgumentException(“没有主构造函数${cls.simpleName}”)
val valuesMap=cons.parameters.filter{val中的it.name}
.协会(
{it},
{生成价值(it)}
)
val data=cons.callBy(valuesMap)//作为T
返回数据

您可以使用
parameters
属性来确定必须向函数/构造函数传递多少参数

如果你打电话

val paramsConstr = StudentWithFactory::class.primaryConstructor?.parameters
val paramsFunc = ::fromJson.parameters
paramsConstr
的大小将如预期的一样为2,但如果您调用

val paramsConstr = StudentWithFactory::class.primaryConstructor?.parameters
val paramsFunc = ::fromJson.parameters
paramsFunc
的大小为3。第一个元素对应于同伴对象的实例。因此,这是您需要提供的参数列表

您可以像这样从JSON调用
fromJson

// not using any default parameters
::fromJson.callBy(mapOf(
        paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
        paramsFunc[1] to "Hello",
        paramsFunc[2] to 30
))

// using only the default parameter for "name"
::fromJson.callBy(mapOf(
        paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
        paramsFunc[2] to 30
))

您可以使用
parameters
属性来确定必须向函数/构造函数传递多少参数

如果你打电话

val paramsConstr = StudentWithFactory::class.primaryConstructor?.parameters
val paramsFunc = ::fromJson.parameters
paramsConstr
的大小将如预期的一样为2,但如果您调用

val paramsConstr = StudentWithFactory::class.primaryConstructor?.parameters
val paramsFunc = ::fromJson.parameters
paramsFunc
的大小为3。第一个元素对应于同伴对象的实例。因此,这是您需要提供的参数列表

您可以像这样从JSON调用
fromJson

// not using any default parameters
::fromJson.callBy(mapOf(
        paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
        paramsFunc[1] to "Hello",
        paramsFunc[2] to 30
))

// using only the default parameter for "name"
::fromJson.callBy(mapOf(
        paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
        paramsFunc[2] to 30
))
除了我的,还有一个更技术性的解释:

是的,实际上有一个隐藏参数,如果您查看反编译(到Java)字节码,您可以看到它(例如):

public final class StudentWithFactory {

   // ...
   public static final class Companion {
      // ...
      @NotNull
      public static StudentWithFactory fromJson$default(StudentWithFactory.Companion var0, String var1, int var2, int var3, Object var4) {
         // ...

         return var0.fromJson(var1, var2);
      }
      // ...
   }
}
第一个参数(
var0
)实际上是伴生对象的实例
var1
(名称)和
var2
(年龄)是您声明的参数
var3
是一个位掩码,用于确定是否已传递显式值或是否应使用默认值*。我真的不知道var4是干什么用的。它在Java代码中未使用。但导入的部分是,如果要调用函数,只需担心
var0
var1
var2

因此,最终fromJson*的非静态版本实际上是在伴生对象的实例上调用的:

var0.fromJson(var1, var2)
*为了简单起见,省略了代码

除了我的,还有一个更技术性的解释:

是的,实际上有一个隐藏参数,如果您查看反编译(到Java)字节码,您可以看到它(例如):

public final class StudentWithFactory {

   // ...
   public static final class Companion {
      // ...
      @NotNull
      public static StudentWithFactory fromJson$default(StudentWithFactory.Companion var0, String var1, int var2, int var3, Object var4) {
         // ...

         return var0.fromJson(var1, var2);
      }
      // ...
   }
}
第一个参数(
var0
)实际上是伴生对象的实例
var1
(名称)和
var2
(年龄)是您声明的参数
var3
是一个位掩码,用于确定是否已传递显式值或是否应使用默认值*。我真的不知道var4是干什么用的。它在Java代码中未使用。但导入的部分是,如果要调用函数,只需担心
var0
var1
var2

因此,最终fromJson*的非静态版本实际上是在伴生对象的实例上调用的:

var0.fromJson(var1, var2)
*为了简单起见,省略了代码

请提供调用factory方法的代码。我假设您使用反射,那么默认参数将不会被使用。我不是kotlin反射专家,但可能您需要在您的同伴工厂方法上使用
@JVMLowloads
,以便无参数方法实际存在于字节码中。您能提供在中调用工厂方法的代码吗?我试着直接调用工厂方法,没有问题,但也许我“误解了您的问题……我认为这是一个类似的问题:@Rene我添加了调用工厂方法的代码。在提供的json数据中使用默认参数。请提供调用工厂方法的代码。我假设您使用反射,那么默认参数将不会被使用。我不是kotlin反射专家,但可能您需要在您的同伴工厂方法上使用
@JVMLowloads
,以便无参数方法实际存在于字节码中。您能提供在中调用工厂方法的代码吗?我试着直接调用工厂方法,没有问题,但也许我“误解了您的问题……我认为这是一个类似的问题:@Rene我添加了调用工厂方法的代码。默认参数在提供的json数据中出现的地方使用。感谢@Willi,我在周五晚些时候为我发布了我的问题,并且正在考虑类似的实验,并在调试器中使用反射数据来验证伴生对象是否是隐藏参数。由于传递给进行调用的方法的数据是类,通过反射从中找到伴生对象,然后从伴生对象中找到fromJson()方法,现在的问题是传递什么值,我将更新