Home > Blockchain >  Kotlin Data Class Parsing Mutiple member properties at once
Kotlin Data Class Parsing Mutiple member properties at once

Time:02-11

Let say I have a data class called Class A

data class ClassA {
 val x0 = ""
 val x1 = "some string"
 val x2 = "some string"
 val x3 = "some string"
 val x4 = "some string"
 val x5 = ""
 val x6 = ""
 val y = ""
 val z = ""
}

I can retrieve the value of these class member thru its class object

val obj = ClassA()
// if the properties has prefix x and not empty then concatenate to this x variable
val x = obj.x1   obj.x2   etc...
...

Let say if this data class has 50 x(n) in it and I want to retrieve any member that does not have an "empty string or null" and match the prefix then how do I do it dynamically (can be a for-loop), instead of type out statically every single properties that I want to retrieve, is there an alternative way to do it?

CodePudding user response:

You could solve that with Reflection:

data class ClassA (
  val x0: String = "",
  val x1: String = "some string 1",
  val x2: String = "some string 2",
  val x3: String = "some string 3",
  val x4: String = "some string 4",
  val x5: String = "",
  val x6: String = "",
  val y: String = "",
  val z: String = ""
)

val obj = ClassA()

val result = ClassA::class.java.declaredFields   // or: 
  .filter { it.name.startsWith("x") }
  .onEach { it.isAccessible = true }
  .map { it.get(obj) }
  .joinToString("; ")


println(result)

This will print:

; some string 1; some string 2; some string 3; some string 4; ; 

If you want to omit x0, x5, and x6, which all are empty strings, and you want to concatenate without semicolon:

val result = Class::class.java.declaredFields
  .filter { it.name.startsWith("x") }
  .onEach { it.isAccessible = true }
  .map { it.get(obj) }
  .filter { it != "" }
  .joinToString("")

CodePudding user response:

I'm going to answer you question and provide a way of doing it, however, I highly recommend against doing it this way simply because while it works, it is seen as hacky and you'd be better off solving this by changing the multiple fields/properties into a collection of some sort instead.

You can use reflection to do it without having to type out all of the values manually.

To do it via reflection, you will have to do something like this.

fun getNonEmptyStrings(input: A): List<String> {
    val members = A::class.memberProperties

    return members
        .filter { it.name.startsWith("x") }
        .map { it.get(input) }
        .filterIsInstance<String>()
        .filter { it.isNotBlank() }
}

There might be some other form of meta-programming that is better suited to this, but I'm not sure what that would be.

  • Related