5

Assume the following simple example data class:

data class SomeDataClass(
  var id: String,
  var name: String,
  var deleted: String
)

With the following code it is possible to get the properties (and set or get their values):

import kotlin.reflect.full.memberProperties

val properties = SomeDataClass::class.memberProperties

print(properties.map { it.name })   // prints:   [deleted, id, name]

The map within the print statement will return a List with the name of the properties in alphabetical order. I need the list in the order they have been defined in the source code, in this case: [id, name, deleted].

It doesn't seem achievable purely through reflection. The only solution I could come up with is to use a helper class defining the order:

val SomeDataClass_Order = listOf("id", "name", "deleted")

This wouldn't be a problem for one or two classes, but it is for hundreds of data classes with the largest one having up to almost one hundred properties.

Any idea would be welcome. I do not need detailed code, rather hints (like parsing the source code, annotations, etc).

lukas.j
  • 6,453
  • 2
  • 5
  • 24

1 Answers1

4

If all the properties are declared in the primary constructor, you could "cheat":

val propertyNames = SomeDataClass::class.primaryConstructor!!.parameters.map { it.name }

If you want the KPropertys:

val properties = propertyNames.map { name -> 
    SomeDataClass::class.memberProperties.find { it.name == name } 
}

This unfortunately doesn't find the properties that are declared in the class body.

I don't know about other platforms, but on Kotlin/JVM, the order in which the backing fields for the properties are generated in the class file is not specified, and a quick experiment finds that the order (at least for the version of kotlinc that I'm using right now), the order is the same as the declaration order. So in theory, you could read the class file of the data class, and find the fields. See this related answer for getting the methods in order. Alternatively, you can use Java reflection, which also doesn't guarantee any order to the returned fields, but "just so happens" to return them in declaration order:

// not guaranteed, might break in the future
val fields = SomeDataClass::class.java.declaredFields.toList()

If you do want to get the properties declared inside the class body in order too, I would suggest that you don't depend on the order at all.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • 1
    You saved me with ...::class.java.declaredFields.toList(). – lukas.j Nov 11 '21 at 18:33
  • @lukas.j I should warn you again that the order is not guaranteed, and can very well break in other Kotlin compiler versions and/or JDK versions. – Sweeper Nov 11 '21 at 18:36
  • I'm aware of this. I need this only for a one-time transfer from a legacy system to a new application. I use to create exports to Excel files, so a team of employees can check data quickly and correct it in the legacy system before it is imported into the new one. And for these non-IT-employees the order of the columns in the Excel files is important. – lukas.j Nov 11 '21 at 19:52