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()方法,现在的问题是传递什么值,我将更新