I have something like this
fun validate(obj1: Any) {
// Here I am getting the KClass of the object
val objKClass = obj1::class
// Here I am casting the object using KClass
val obj1Cast = objKClass.safeCast(obj1)
// Then I want to iterate over its properties
for (prop in objKClass.memberProperties) {
//And get one BigDecimal? value
val bigDecimal: BigDecimal? = prop.get(obj1Cast) as BigDecimal?
}
}
This doesn't work, I get in relation to prop.get(obj1Cast)
:
Type mismatch.
Required:
Nothing
Found:
Any?
Is there another way to access the values of the memberProperties and cast them to BigDecimal? (for example) given an object with type Any as the input for my function?
CodePudding user response:
Use generic type capture to solve this problem.
In your current code, prop
is of type KProperty1<out Any, *>
. This is because the type of obj1
is Any
, so the type of objKClass
is KClass<out Any>
. There are no values that satisfy the type out Any
when it's used as an input parameter, so you get a compile error.
The first step is to capture the type of obj1
. We can do that by adding a generic type parameter for it, instead of using Any
. Let's call the captured type T
.
fun <T: Any> validate(obj1: T) {
val objKClass: KClass<out T> = obj1::class
val obj1Cast = objKClass.safeCast(obj1) ?: return
for (prop in objKClass.memberProperties) {
val bigDecimal: BigDecimal? = prop.get(obj1Cast) as BigDecimal?
}
}
Now the type of prop
is KProperty1<out T, *>
. This gets us one step closer, but we still have a compile error. That's because out T
can only be used for an output value, but we want to pass a T
into a method parameter.
Luckily, the safeCast
can help us, because it will narrow the type of the value so it exactly matches the type of the class. We just need to give it some help by using a second method to capture the exact type of the class. Let's call the narrower exact type T2
.
// Here we capture the type of the object as T,
// and get its class as KClass<out T>
fun <T: Any> validate(obj1: T) {
validate(obj1, obj1::class)
}
// Here we narrow the type of the object from T to T2
fun <T: Any, T2: T> validate(obj1: T, type: KClass<T2>) {
val obj1Cast = type.safeCast(obj1) ?: return
for (prop in type.memberProperties) {
val bigDecimal: BigDecimal? = prop.get(obj1Cast) as BigDecimal?
}
}
Now it works with no compilation errors. For more information on how this works, you can read about "generic type capturing".