web-dev-qa-db-fra.com

Kotlin - génère toString () pour une classe non-data

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?

21
awfun

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.

9
voddan

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(", ")}]"
}
8
junique

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)
}
7
James Bassett

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.

https://stackoverflow.com/a/46247234/97777

1
Duncan McGregor