Situation:
I have a class with lateinit
fields, so they are not present in the constructor:
class ConfirmRequest() {
lateinit var playerId: String
}
I'd like to have a toString()
method with all fields and don't want to write it manually, to avoid boiler print. In Java I'd use the Lombok @ToString
annotation for this problem.
Question:
Is there any way to implement it in Kotlin?
The recommended way is to write toString
manually (or generate by IDE) and hope that you don't have too many of such classes.
The purpose of data class
is to accommodate the most common cases of 85%, which leaves 15% to other solutions.
Like you, I was used to using lombok for toString()
and equals()
in Java, so was a bit disappointed that non-data classes in Kotlin required all of the standard boilerplate.
So I created Kassava, an open source library that lets you implement toString()
and equals()
without any boilerplate - just supply the list of properties and you're done!
For example:
// 1. Import extension functions
import au.com.console.kassava.kotlinEquals
import au.com.console.kassava.kotlinToString
import java.util.Objects
class Employee(val name: String, val age: Int? = null) {
// 2. Optionally define your properties for equals()/toString() in a companion
// object (Kotlin will generate less KProperty classes, and you won't have
// array creation for every method call)
companion object {
private val properties = arrayOf(Employee::name, Employee::age)
}
// 3. Implement equals() by supplying the list of properties to be included
override fun equals(other: Any?) = kotlinEquals(
other = other,
properties = properties
)
// 4. Implement toString() by supplying the list of properties to be included
override fun toString() = kotlinToString(properties = properties)
// 5. Implement hashCode() because you're awesome and know what you're doing ;)
override fun hashCode() = Objects.hash(name, age)
}
I find Apache Commons Lang's ToStringBuilder
with reflection useful, but it calls hashCode()
and other methods when I don't need that (and one called hashCode()
from a 3rd-party lib generates an NPE).
So I just go with:
// class myClass
override fun toString() = MiscUtils.reflectionToString(this)
// class MiscUTils
fun reflectionToString(obj: Any): String {
val s = LinkedList<String>()
var clazz: Class<in Any>? = obj.javaClass
while (clazz != null) {
for (prop in clazz.declaredFields.filterNot { Modifier.isStatic(it.modifiers) }) {
prop.isAccessible = true
s += "${prop.name}=" + prop.get(obj)?.toString()?.trim()
}
clazz = clazz.superclass
}
return "${obj.javaClass.simpleName}=[${s.joinToString(", ")}]"
}
You can define a data class that contains the data that you want to use and implement methods by delegating to that.
What about using Kotlin reflection? I am into Kotlin for a few days, so apologies, if I misunderstood question, or wrote "Kotlin inefficient" example.
override fun toString() : String{
var ret : String = ""
for (memberProperty in this.javaClass.kotlin.memberProperties){
ret += ("Property:${memberProperty.name} value:${memberProperty.get(this).toString()}\n");
}
return ret
}
This can also could be implemented in newly created interface for example ToString2Interface as fun toString2. Then all classes which implements ToString2Interface would have toString2()
来源:https://stackoverflow.com/questions/40862207/kotlin-generate-tostring-for-a-non-data-class