Situation:
J'ai une classe avec des champs lateinit
, ils ne sont donc pas présents dans le constructeur:
class ConfirmRequest() {
lateinit var playerId: String
}
Je voudrais avoir une méthode toString()
avec tous les champs et je ne veux pas l'écrire manuellement, pour éviter l'impression de la chaudière. En Java, j'utilisais l'annotation Lombok@ToString
pour résoudre ce problème.
Question:
Y a-t-il un moyen de le mettre en œuvre à Kotlin?
La méthode recommandée consiste à écrire toString
manuellement (ou à générer par l'EDI) en espérant que vous n'avez pas trop de telles classes.
Le but de data class
est de prendre en charge les cas les plus courants de 85%, ce qui laisse 15% d’autres solutions.
Je trouve la variable ToStringBuilder
avec réflexion d'Apache Commons Lang utile, mais elle appelle hashCode()
et d'autres méthodes lorsque je n'en ai pas besoin (et une méthode appelée hashCode()
à partir d'une bibliothèque tierce génère un NPE).
Alors je viens avec:
// 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(", ")}]"
}
Comme vous, j'étais habitué à utiliser lombok pour toString()
et equals()
en Java. J'étais donc un peu déçu que les classes non-données de Kotlin requièrent tout le standard standard.
J'ai donc créé Kassava , une bibliothèque open source qui vous permet d'implémenter toString()
et equals()
sans aucun passe-partout - il suffit de fournir la liste des propriétés et vous avez terminé!
Par exemple:
// 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)
}
Vous pouvez définir une classe de données contenant les données que vous souhaitez utiliser et implémenter des méthodes en déléguant à celle-ci.