The simplest way to solve this is not to use reflection at all. You can pass the property values directly to the class constructor:
data class Member(val firstName: String, val lastName: String)
fun readCsvFileKotlin() {
// ...
for (line in reader) {
val mbrProperties = line.split(",")
memberList.add(Member(mbrProperties[0], mbrProperties[1]))
}
}
If you want to set properties through reflection, you need to declare them as var rather than val, so that they can be changed after the object is created. Then you can use the set method on the property object to change the property value:
data class Member(var firstName: String? = null, var lastName: String? = null)
fun readCsvFileKotlin() {
// ...
val prop = Member::firstName
for (line in reader) {
val mbrProperties = line.split(",")
val member = Member()
prop.set(member, mbrProperties[0])
memberList.add(member)
}
}
Answer from yole on Stack OverflowThe simplest way to solve this is not to use reflection at all. You can pass the property values directly to the class constructor:
data class Member(val firstName: String, val lastName: String)
fun readCsvFileKotlin() {
// ...
for (line in reader) {
val mbrProperties = line.split(",")
memberList.add(Member(mbrProperties[0], mbrProperties[1]))
}
}
If you want to set properties through reflection, you need to declare them as var rather than val, so that they can be changed after the object is created. Then you can use the set method on the property object to change the property value:
data class Member(var firstName: String? = null, var lastName: String? = null)
fun readCsvFileKotlin() {
// ...
val prop = Member::firstName
for (line in reader) {
val mbrProperties = line.split(",")
val member = Member()
prop.set(member, mbrProperties[0])
memberList.add(member)
}
}
If you still look to do that, I created my own CSV library that uses reflection to instantiate POJOs directly from the CSV input and manages errors in the CSV much better than regular parsers I tested, called Kotlin CSV Stream
I actually created it after giving up on traditional parsers because they all did not fill my needs.
This can be achieved using basic Kotlin instead of an external library.
data class
data class Category(
val id: String,
val name: String,
)
utility function
fun <T> csvOf(
headers: List<String>,
data: List<T>,
itemBuilder: (T) -> List<String>
) = buildString {
append(headers.joinToString(",") { "\"$it\"" })
append("\n")
data.forEach { item ->
append(itemBuilder(item).joinToString(",") { "\"$it\"" })
append("\n")
}
}
usage
fun main() {
val firstCategory = Category(0, "Phone")
val secondCategory = Category(1, "Laptop")
val categories = listOf(firstCategory, secondCategory)
val csv = csvOf(
listOf("id", "name"),
categories
) {
listOf(it.id.toString(), it.name)
}
println(csv)
}
You can use the solution offered by this medium article:
To sum up
You can create a simple generic function
import java.io.FileWriter
inline fun <reified T> writeCsvFile(data: Collection<T>, fileName: String) {
FileWriter(fileName).use { writer ->
csvMapper.writer(csvMapper.schemaFor(T::class.java).withHeader())
.writeValues(writer)
.writeAll(data)
.close()
}
}
I tested it with the following dependencies:
com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.11.1
com.fasterxml.jackson.module:jackson-module-kotlin:2.12.5