I am trying to instantiate instances generically for a (de)serialization library I am building. This sometimes requires object stubs to be generated automatically (they are later replaced by real instances).
When trying to do so, I call the constructor as a KFunction, which works for classes that only take preexisting values or plain values like Int, Long ...
for which I have predefined stubs. When I as the library provider don't know a type I need a stub for, I want to proxy that type and later inject the actual value (the latter works perfectly). However whenever I try to call the constructor with the proxy provided, the constructor call throws an IllegalArgumentException
.
I debugged to DelegatingConstructorAccessorImpl.newInstance
where I cannot go any further as things start to get native. I am pretty certain, that the arguments are in the right order and all, because if I replace the value with a real instance it works, however the proxy is not identified as the expected type.
My proxies are generated like this:
Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
type.jvmErasure.java.interfaces,
InvocationHandler { proxy, method, args ->
if (method.name == "getClass") {
println("PROXY: #getClass was called on proxy of type $type.")
return@InvocationHandler type.jvmErasure.java
} else if (method.name == "toString" && method.parameters.isEmpty()
&& method.returnType == String::class.java
) {
return@InvocationHandler "Proxy<$type>"
} else if (method.name == "equals" && method.returnType == Boolean::class.java) {
println("PROXY: #equals was called on proxy of type $type.")
return@InvocationHandler proxy === args[0]
} else {
throw UnsupportedOperationException("This method should not have been called: $method")
}
}
)
In the beginning I thought my method calls failed, and I am still unsure, if this is not the case. However the debugging of the JVM does not stop on any invokation, which suggests to me, that I am doing something else wrong with the proxy.
How can I make the proxy fit the expected constructor argument?
My constructor call is made like this:
private fun <T> newInstanceCatching(
className: String,
calledConstructor: KFunction<T>,
params: Map<KParameter, Any?>
): T = try {
calledConstructor.callBy(params)
} catch (e: Exception) {
val readableParams = params.map { "\n${it.key.name}: ${it.key.type} = ${it.value}" }
println("Failed to instantiate: $className by $calledConstructor with parameters: $readableParams")
throw e
}
As mentioned, this works for actual instances as constructor parameters, just not when at least one parameter is a proxy.
Aucun commentaire:
Enregistrer un commentaire