get declared fields in kotlin multiplatform - kotlin

is there a way, to dynamically get reference to object field in kotlin multiplatform? I am trying to dynamically create instances of generic object from json input, in which I need to define exact field of a data object.
I have tried using reflections, but it is not available in multiplatform.
So I need something like
class User(
var lastName: String? = null,
var firstName: String? = null,
)
val jsonName="firstname"
val jsonModel="User::firstName"
val referenceJvm = User::class.declaredMembers // I cannot use this, only available for JVM
val referenceToField=User::firstName // I need to get this dynamically by using value in jsonModel property
StringField(
fieldName = jsonName,
model = referenceToField //this should be reference to firstName field in User class
)
Only solution I can think of is to have one huge dictionary/map where I would hardcode this. But application has hundreds possible models, so it is not really a solution I am looking for.

Related

Difference between accessing via property access and destructuring in kotlin data class

I have a data class like this
data class Task(
var id: Int,
var description: String,
var priority: Int
)
I implement it the following
val foo = Task(1, "whatever", 10)
I read about accessing whatever like this
foo.description
or
foo.component2()
What is the difference?
There is no difference in behaviour, but use foo.description.
It's extremely rare to use a componentN() function directly. If you know which component you're accessing, it's just way more readable to use the property directly.
The componentN() functions are mostly a tool to implement actual destructuring declarations like:
val (id, desc, prio) = task
Which is a shortcut that is equivalent to:
val id = task.component1()
val desc = task.component2()
val prio = task.component3()
..which you should probably never write in source code.

How can I create a List (or any other collection) of another class property's type dynamically?

This feature is inspired by TypeScript which allows us to create arrays based on the property of another class, whatever that property's type is.
For example assume you have this class in Kotlin:
class Person(
val name: String,
val age: Int
)
And later, somewhere else in the code I want to have a list of names, so I would do something like this:
val namesList = List<Person::name>()
And Kotlin will know that this will be equivalent to List<String>() at compile time.
This avoids me to manually propagate the type of a field I already declared in one place. Plus, if one day the name type changes from String to something else, all the collections would get updated automatically.
Can this be done in Kotlin?
No, Kotlin is very explicit about types. It is a strongly-typed language.
Maybe the closest you could do is define a type alias next to your class and use that:
typealias PersonName = String
data class Person(val name: PersonName, val age: Int)
and then:
val namesList = mutableListOf<PersonName>()
However, in most cases you don't have to explicitly write the types anyway because they can be inferred.
// Is a List<String> and would automatically update if name type changed
val nameList = personList.map(Person::name)
// Or to get an empty mutable list:
val nameList = emptyList<Person>().map(Person::name).toMutableList()
The standard thing to do is to use map to extract the type you need:
val people = listOf(
Person("a", 1),
Person("b", 2),
Person("c", 3),
)
val names = people.map { it.name } // statically inferred to List<String>
If you changed the type of name to something else, you wouldn't need to change the val names = people.map { it.name } line - the new type will be inferred automatically.

Kotlin multiple class for data storage

I am developing a simple Android app, that will display an icon of a vehicle and the user can click on the icon to display the vehicle information. I want to load the data dynamically when I build the app i.e. the data will come from an external source including the picture for the icon.
I am new to Kotlin and not sure what to search for to understand a suitable solution. What is the correct way to define the data, is it best to create an class as below then create an array of the class (not sure if this is possible)
public class VehicleSpec()
{
var OEM: String? = null
var ModelName: String? = null
var EngineSize: String? = null
}
Or would be better to create a multiple dimension array and then link the data to the cells?
var VehicleSpec = arrayOf(20,20)
VehicleSpec[0][0] = Null //OEM
VehicleSpec[0][1] = Null //ModelName
VehicleSpec[0][2] = Null //EngineSize
What is the best way to set up the data storage, is there any good references to understand how this should be setup?
What is the correct way to define the data, is it best to create an class as below then create an array of the class
Using an array for the properties of an object is not making the full use of the type safety you have in Kotlin (and even Java for that matter).
If what you want to express is multiple properties of an object, then you should use a class to define those properties. This is especially true if the properties have different types.
There is no performance difference between an array and a class, because you'll get a reference to the heap in both cases. You could save on performance only if you convert your multi-dimensional array approach to a single-dimension array with smart indexing. Most of the time, you should not consider this option unless you are handling a lot of data and if you know that performance is an issue at this specific level.
(not sure if this is possible)
Defining lists/arrays of classes is definitely possible.
Usually, for classes that are only used as data containers, you should prefer data classes, because they give you useful methods for free, and these methods totally make sense for simple "data bags" like in your case (equals, hashcode, component access, etc.).
data class Vehicle(
val OEM: String,
val ModelName: String,
val EngineSize: String
)
Also, I suggest using val instead of var as much as possible. Immutability is more idiomatic in Kotlin.
Last but not least, prefer non-null values to null values if you know a value must always be present. If there are valid cases where the value is absent, you should use null instead of a placeholder value like empty string or -1.
First at all, using the "class aprocah" makes it easy for you to understand and give you the full benefits of the language itself... so dont dry to save data in an array .. let the compiler handle those stuff.
Secondly i suggest you have maybe two types (and use data classes ;-) )
data class VehicleListEntry(
val id: Long,
val name: String
)
and
data class VehicleSpec(
val id: Long,
val oem: String = "",
val modelName: String = "",
val engineSize: String = ""
)
from my perspective try to avoid null values whenever possible.
So if you have strings - which you are display only - use empty strings instead of null.
and now have a Model to store your data
class VehicleModel() {
private val specs: MutableMap<Long, VehicleSpec> = mutableMapOf()
private var entries: List<VehicleListEntry> = listOf()
fun getSpec(id: Long) = specs[id]
fun addSpec(spec: VehicleSpec) = specs[spec.id] = spec
fun getEntries(): List<VehicleListEntry> = entries
fun setEntries(data: List<VehicleListEntry>) {
entries = data.toMutableList()
}
}
You could also use a data class for your model which looks like
data class VehicleModel(
val specs: MutableMap<Long, VehicleSpec> = mutableMapOf(),
var entries: List<VehicleListEntry> = listOf()
)
And last but not least a controller for getting stuff together
class VehicleController() {
private val model = VehicleModel()
init{
// TODO get the entries list together
}
fun getEntries() = model.entries
fun getSpec(id: Long) : VehicleSpec? {
// TODO load the data from external source (or check the model first)
// TODO store the data into the model
// TODO return result
}
}

How to make a builder for a Kotlin data class with many immutable properties

I have a Kotlin data class that I am constructing with many immutable properties, which are being fetched from separate SQL queries. If I want to construct the data class using the builder pattern, how do I do this without making those properties mutable?
For example, instead of constructing via
var data = MyData(val1, val2, val3)
I want to use
builder.someVal(val1)
// compute val2
builder.someOtherVal(val2)
// ...
var data = builder.build()
while still using Kotlin's data class feature and immutable properties.
I agree with the data copy block in Grzegorz answer, but it's essentially the same syntax as creating data classes with constructors. If you want to use that method and keep everything legible, you'll likely be computing everything beforehand and passing the values all together in the end.
To have something more like a builder, you may consider the following:
Let's say your data class is
data class Data(val text: String, val number: Int, val time: Long)
You can create a mutable builder version like so, with a build method to create the data class:
class Builder {
var text = "hello"
var number = 2
var time = System.currentTimeMillis()
internal fun build()
= Data(text, number, time)
}
Along with a builder method like so:
fun createData(action: Builder.() -> Unit): Data {
val builder = Builder()
builder.action()
return builder.build()
}
Action is a function from which you can modify the values directly, and createData will build it into a data class for you directly afterwards.
This way, you can create a data class with:
val data: Data = createData {
//execute stuff here
text = "new text"
//calculate number
number = -1
//calculate time
time = 222L
}
There are no setter methods per say, but you can directly assign the mutable variables with your new values and call other methods within the builder.
You can also make use of kotlin's get and set by specifying your own functions for each variable so it can do more than set the field.
There's also no need for returning the current builder class, as you always have access to its variables.
Addition note: If you care, createData can be shortened to this:
fun createData(action: Builder.() -> Unit): Data = with(Builder()) { action(); build() }.
"With a new builder, apply our action and build"
I don't think Kotlin has native builders. You can always compute all values and create the object at the end.
If you still want to use a builder you will have to implement it by yourself. Check this question
There is no need for creating custom builders in Kotlin - in order to achieve builder-like semantics, you can leverage copy method - it's perfect for situations where you want to get object's copy with a small alteration.
data class MyData(val val1: String? = null, val val2: String? = null, val val3: String? = null)
val temp = MyData()
.copy(val1 = "1")
.copy(val2 = "2")
.copy(val3 = "3")
Or:
val empty = MyData()
val with1 = empty.copy(val1 = "1")
val with2 = with1.copy(val2 = "2")
val with3 = with2.copy(val3 = "3")
Since you want everything to be immutable, copying must happen at every stage.
Also, it's fine to have mutable properties in the builder as long as the result produced by it is immutable.
It's possible to mechanize the creation of the builder classes with annotation processors.
I just created ephemient/builder-generator to demonstrate this.
Note that currently, kapt works fine for generated Java code, but there are some issues with generated Kotlin code (see KT-14070). For these purposes this isn't an issue, as long as the nullability annotations are copied through from the original Kotlin classes to the generated Java builders (so that Kotlin code using the generated Java code sees nullable/non-nullable types instead of just platform types).

Class declarations in Kotlin

I was creating a sample Android project using Kotlin programming language using this blog. I'm new to Kotlin programming. I came across this line,
data class Cats(var data: Data? = null)
which I believe that it is, creating a class named Cats that has a variable named data. What does this data: Data? = null means? My whole class model is:
data class Cats(var data: Data? = null)
data class Data(var images: ArrayList<Image>? = null)
data class Image(var url: String? = "", var id: String? = "", var source_url: String? = "")
You are right that Cats class will have a mutable property named data, since it is declared inside a primary constructor of a class with var keyword (see the docs pages about classes and properties).
Next, question mark at type name in Kotlin means that a variable has nullable type, that is, it can store null value. Variables with not-null types, on the other hand, cannot hold nulls in Kotlin.
data: Data? = null is syntax for default parameter value. It allows not to pass data parameter to the constructor invocation, and in this case default value null will be used. This also works for functions.
And finally, data modifier at class declaration means that equals, hashCode, toString, copy and destructuring will be generated for the class, based on the properties declared in primary constructor.
=> Classes in Kotlin are declared using the keyword class:
class Invoice { }
=> Both the header and the body are optional; if the class has no body, curly braces can be omitted.
class Invoice