Matius Nugroho Aryanto
Matius Nugroho Aryanto

Reputation: 901

Kotlin How to create dynamic Object

In javascript we can do something like this

function putritanjungsari(data){
	console.log(data.name)
}

let data = {
	name:"putri",
	div:"m4th"
}
putritanjungsari(data)

In kotlin, i'am creating a function that accept an object as parameter then read it's properties later, how to do that in kotlin that targeting JVM?

Upvotes: 2

Views: 17891

Answers (5)

skrymir1
skrymir1

Reputation: 607

Just for the sake of inspiration. In Kotlin, you can create ad hoc objects:

val adHoc = object {
    var x = 1
    var y = 2
}
println(adHoc.x + adHoc.y)

Upvotes: -1

IlyaMuravjov
IlyaMuravjov

Reputation: 2492

You can apply the property design pattern to solve your problem.

Here is its implementation in Kotlin:

interface DynamicProperty<T> {
    fun cast(value: Any?): T
    fun default(): T

    companion object {
        inline fun <reified T> fromDefaultSupplier(crossinline default: () -> T) =
            object : DynamicProperty<T> {
                override fun cast(value: Any?): T = value as T
                override fun default(): T = default()
            }

        inline operator fun <reified T> invoke(default: T) = fromDefaultSupplier { default }

        inline fun <reified T> required() = fromDefaultSupplier<T> {
            throw IllegalStateException("DynamicProperty isn't initialized")
        }

        inline fun <reified T> nullable() = DynamicProperty<T?>(null)
    }
}

operator fun <T> DynamicProperty<T>.invoke(value: T) = DynamicPropertyValue(this, value)

data class DynamicPropertyValue<T>(val property: DynamicProperty<T>, val value: T)

class DynamicObject(vararg properties: DynamicPropertyValue<*>) {
    private val properties = HashMap<DynamicProperty<*>, Any?>().apply {
        properties.forEach { put(it.property, it.value) }
    }

    operator fun <T> get(property: DynamicProperty<T>) =
        if (properties.containsKey(property)) property.cast(properties[property])
        else property.default()

    operator fun <T> set(property: DynamicProperty<T>, value: T) = properties.put(property, value)
    operator fun <T> DynamicProperty<T>.minus(value: T) = set(this, value)
}

fun dynamicObj(init: DynamicObject.() -> Unit) = DynamicObject().apply(init)

You can define your properties these ways:

val NAME = DynamicProperty.required<String>() // throws exceptions on usage before initialization
val DIV = DynamicProperty.nullable<String>() // has nullable type String?
val IS_ENABLED = DynamicProperty(true) // true by default

Now you can use them:

fun printObjName(obj: DynamicObject) {
    println(obj[NAME])
}

val data = dynamicObj {
    NAME - "putri"
    DIV - "m4th"
}
printObjName(data)

// throws exception because name isn't initialized
printObjName(DynamicObject(DIV("m4th"), IS_ENABLED(false)))

Reasons to use DynamicObject instead of Map<String, Any?>:

  1. Type-safety (NAME - 3 and NAME(true) will not compile)
  2. No casting is required on properties usage
  3. You can define what the program should do when a property isn't initialized

Upvotes: 6

DownloadPizza
DownloadPizza

Reputation: 3466

If I understood your question correct, you are trying to have a variable that associates keys with some value or undefined(null in kt) if none are found. You are searching for a Map If you don't know what types you want, you can make a map of type Any? So

Map<String, Any?>

Which is also nullable

Map<String, Any>

If you don't want nullables

Your code for example:

fun putritanjungsari(data: Map<String, Any?>){
print(data["name"]) 
}

val data: Map<String, Any?> =mapOf(        
"name" to "putri",
"div" to "m4th" 
)
putritanjungsari(data)

Note that you can't add new keys or edit any data here, the default map is immutable. There is MutableMap (which is implemented the same, only it has a method to put new data)

Upvotes: 6

lotor
lotor

Reputation: 1090

Kotlin is statically typed language, so it required a param type to be precisely defined or unambiguously inferred (Groovy, for instance, addresses the case by at least two ways). But for JS interoperability Kotlin offers dynamic type.

Meanwhile, in your particular case you can type data structure to kt's Map and do not argue with strict typing.

Upvotes: 0

Akshay Raiyani
Akshay Raiyani

Reputation: 1323

You have to use Any and after that, you have to cast your object, like this

private fun putritanjungsari(data : Any){
    if(data is Mydata){
        var data =  data as? Mydata
        data.name
    }
}

Upvotes: -1

Related Questions