Get property of a Kotlin reflected object with type Any - kotlin

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?

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".

Related

Why do i need to specify constructor argument as nullable generic type?

I'm trying to make OK() to call ApiResponse constructor. When I give null to ApiResponse constructor argument, it shows error that type mismatches.
If I change data type to T? it works. Why is it happening? Default upper bound of T is Any? so i thought it won't be any problem to assign null.
class ApiResponse<T> private constructor(
val data: T, // If I change data type to T?, no error
val message: String?
) {
companion object {
fun <T> OK(): ApiResponse<T> {
return ApiResponse(null, null)
}
fun <T> OK(data: T): ApiResponse<T> {
return ApiResponse(data, null)
}
}
}
I've searched with keywords kotlin, generic, constructor, nullable, T but i could not find answer.
In
fun <T> OK(): ApiResponse<T> {
return ApiResponse(null, null)
}
if someone calls ApiResponse.OK<String>(), then it tries to construct an ApiResponse where data is null and also of type String, which is incompatible. None of your types prevent that call -- when you have a generic type argument to the function like that, the caller can specify any T they please, including a nonnull type.
You must either return an ApiResponse<T?>, or not have an argumentless OK factory method.

Kotlin: store any type of function reference in a variable

Is it possible to have a variable that can holds any type function.
Like :
fun method1(par: Boolean){}
fun method2(par: Boolean) : Int{return 1}
fun method3(par: Boolean, par2: Boolean) : Int{return 1}
var funtionHolder : ((Any)->Any) ?= null //What should I write here?? so to hold any type of function
fun method4(){
.........
funtionHolder = ::method1 //getting compile time error
.........
funtionHolder = ::method2 //getting compile time error
.........
funtionHolder = ::method3 //getting compile time error
}
After holding the function_reference I need to invoke it later. So I need to holds it parameter type and state also.
You can hold them in a KFunction<Any> or its superclass KCallable<Any> because you know nothing about the parameter list and nothing about the return type, so you have to go to something that can reference at that level of abstraction. These instances can then be invoked more generically using the call() or callBy() methods. (this requires the kotlin-reflect dependency). To do something safer and to call like a normal function you'd have to cast back to the specific function type later.
If you want to avoid this, you'll need to unify your signatures to something you can point to with another function type (i.e. KFunction1 or KFunction2). Otherwise how you'll call this, what you'll do with it will be up to you at this point because you erased all the information that allows you to easily call the function.
val functionHolder1: KFunction<Any> = ::method1 // success!
val functionHolder2: KFunction<Any> = ::method2 // success!
val functionHolder3: KFunction<Any> = ::method3 // success!
You can then make a DeferredFunction class to hold these along with parameters you want to later pass, and then invoke it whenever in the future.
class DeferredFunction(val function: KFunction<Any>, vararg val params: Any?) {
#Suppress("UNCHECKED_CAST")
operator fun <T> invoke(): T {
return function.call(params) as T
}
}
fun whatever(name: String, age: Int): String {
return "$name of age $age"
}
val functionHolder = DeferredFunction(::whatever, "Fred", 65)
println(functionHolder<String>()) // "Fred of age 65"
You do not need the generic return type on the invoke function and could just make it return Any or call it as functionHolder<Any>() but it is nice if you know what to expect for the return. You can decide what to do there based on your actual use case. Also no need to special case for no parameters, just don't pass any, i.e. DeferredFunction(::otherFunc)
With reference from Jayson's answer, added extra code to hold the state of the function by using vararg and spread operator(*).
var functionHolder: KFunction<Any> ?= null
var paramsHolder : Array<out Any?> ?= null
fun hold(functionReference : KFunction<Any>, vararg args : Any?) {
this.functionHolder = functionReference
this.paramsHolder = args
}
fun release() {
if (functionHolder != null) {
if (paramsHolder != null) {
functionHolder?.call(*paramsHolder!!)
} else {
functionHolder?.call()
}
}
}
......
fun method3(par: Boolean, par2: Boolean) : Int{return 1}
......
hold(::method3, true, false)
release()//it works
No. Kotlin is static typed language and doesn't allow this. Else what happens when this is called?
functionHolder->invoke(3)
and when functionHolder is assigned a lamda that doesn't take parameter?

How to implement mutable optional in Kotlin?

I want a class which is equivalent to Java Optional but also
Properly handles null value ("Not set" state is different from "Null set")
Is mutable
Uses Kotlin built-in null-safety, type parameter can be either nullable or non-nullable which affects all methods.
Non-working code:
class MutableOptional<T> {
private var value: T? = null
private var isSet: Boolean = false
fun set(value: T)
{
this.value = value
isSet = true
}
fun unset()
{
isSet = false
value = null
}
fun get(): T
{
if (!isSet) {
throw Error("Value not set")
}
return value!! // <<< NPE here
}
}
fun f()
{
val opt = MutableOptional<Int?>()
opt.set(null)
assertNull(opt.get())
}
The problem is that if I try to set null, get() call fails with null pointer exception (caused by !! operator).
Some not-working proposals:
Do not use members of type "T?" in such class. I would not use it if I knew how to leave them uninitialized (not allowed by the compiler) or how to make them to have default initialization.
Use "fun get(): T?" (with nullable result). I want the result type to have the same nullability as the class type parameter. Otherwise there is no meaning in such null-safety if it is lost in a simple generic class, and I will need to set !! manually where I am sure it is non-nullable (the thing the compiler should ensure), making my code looking like wedge-writing.
Note: This example is synthetic, I do not really need the mutable optional, it is just a simple and understandable example, illustrating a problem I encounter occasionally with Kotlin generics and null-safety. Finding solution to this particular example will help with many similar problems. Actually I have a solution for immutable version of this class but it involves making interface and two implementation classes for present and non-present values. Such immutable optional can be used as type of "value" member but I think it's quite big overhead (accounting also wrapper object creation for each set()) just to overcome the language constraints.
The compiler wants you to write code that will be type-safe for all possible T, both nullable and not-null (unless you specify a not-null upper bound for the type parameter, such as T : Any, but this is not what you need here).
If you store T? in a property, it is a different type from T in case of not-null type arguments, so you are not allowed to use T and T? interchangeably.
However, making an unchecked cast allows you to bypass the restriction and return the T? value as T. Unlike the not-null assertion (!!), the cast is not checked at runtime, and it won't fail when it encounters a null.
Change the get() function as follows:
fun get(): T {
if (!isSet) {
throw Error("Value not set")
}
#Suppress("unchecked_cast")
return value as T
}
I got a similar issue. My use case was to differentiate null and undefined value when I deserialize JSON object. So I create an immutable Optional that was able to handle null value. Here I share my solution:
interface Optional<out T> {
fun isDefined(): Boolean
fun isUndefined(): Boolean
fun get(): T
fun ifDefined(consumer: (T) -> Unit)
class Defined<out T>(private val value: T) : Optional<T> {
override fun isDefined() = true
override fun isUndefined() = false
override fun get() = this.value
override fun ifDefined(consumer: (T) -> Unit) = consumer(this.value)
}
object Undefined : Optional<Nothing> {
override fun isDefined() = false
override fun isUndefined() = true
override fun get() = throw NoSuchElementException("No value defined")
override fun ifDefined(consumer: (Nothing) -> Unit) {}
}
}
fun <T> Optional<T>.orElse(other: T): T = if (this.isDefined()) this.get() else other
The trick: the orElse method have to be defined as an extension to not break the covariance, because Kotlin does not support lower bound for now.
Then we can define a MutableOptional with no cast in the following way:
class MutableOptional<T> {
private var value: Optional<T> = Optional.Undefined
fun get() = value.get()
fun set(value: T) { this.value = Optional.Defined(value) }
fun unset() { this.value = Optional.Undefined }
}
I am happy with my immutable Optional implementation. But I am not very happy with MutableOptional: I dislike the previous solution based on casting (I dislike to cast). But my solution creates unnecessary boxing, it can be worst...

kotlin: list properties of any object - variance error

I'm trying to write a function that produces map of properties and values for any type
inline fun <reified T : Any> T.propertiesMap() {
for (property in this::class.memberProperties) {
property.get(this)
}
}
i get a compilation error in property.get(this) about
out-projected type [...] prohibits the use of 'public abstract fun get(receiver...
The issue is that this::class produces a KClass<out T> instead of KClass<T> which is what would be needed to use anything of type T in the property.get(...) call. So you can do an unchecked cast to do what you want:
fun <T : Any> T.propertiesMap() {
#Suppress("UNCHECKED_CAST")
for (property in (this::class as KClass<T>).memberProperties) {
property.get(this)
}
}
Which does not require the function to be inline nor reified type parameter. Otherwise you can change your function to use T::class instead of this::class to create a matching KClass<T>.
inline fun <reified T : Any> T.propertiesMap() {
for (property in T::class.memberProperties) {
property.get(this)
}
}
If you use the type you are reifying rather than an instance of that type the variance issue will go away. When you call T::class.memberProperties you get back a Collection<KProperty<T, *>> which is what I believe you want. On the other hand, if you call that on an instance (this) rather than a type, you get back a Collection<KProperty<out T, Any?>>, which is where your out-variance issue comes from.
inline fun <reified T : Any> T.propertiesMap() {
for (property in T::class.memberProperties) {
property.get(this)
}
}
Essentially, you need to do T::class rather than this::class in order to get the right kind of collection back. I've left your code as-is otherwise because I'm not clear on what you want this function to do, but I suspect you could drop the for loop in favor of a map call.

Inferring only some type parameters in Kotlin

I have a method with two type parameters, only one of which can be inferred from arguments, something like (no need to comment this cast is evil, the body is purely for the sake of example)
fun <A, B> foo(x: Any, y: A.() -> B) = (x as A).y()
// at call site
foo<String, Int>("1", { toInt() })
However, the compiler can tell B is Int if A is String. And more generally, if it knows A, B can be inferred.
Is there a way to only provide A at the call site and infer B?
Of course, the standard Scala approach works:
class <A> Foo() {
fun <B> apply(x: Any, y: A.() -> B) = ...
}
// at call site
Foo<String>().apply("1", { toInt() })
I was interested in whether Kotlin has a more direct solution.
Based on this issue/proposal, I'd say no(t yet):
Hello, I am proposing two new feature for kotlin which go hand in
hand: partial type parameter list and default type parameters :) Which
in essence allows to do something as the following:
data class Test<out T>(val value: T)
inline fun <T: Any, reified TSub: T> Test<T>.narrow(): Test<TSub>{
return if(value is TSub) Test(value as TSub) else throw ClassCastException("...")
}
fun foo() {
val i: Any = 1
Test(i).narrow<_, Int>() // the _ means let Kotlin infer the first type parameter
// Today I need to repeat the obvious:
Test(i).narrow<Any, Int>()
}
It would be even nicer, if we can define something like:
inline fun <default T: Any, reified TSub: T> Test<T>.narrow(): Test<TSub>{
return if(value is TSub) Test(value as TSub) else throw ClassCastException("...")
}
And then don't even have to write _
fun foo() {
val i: Any = 1
Test(i).narrow<Int>() //default type parameter, let Kotlin infer the first type parameter
}