java - studio - Kotlin-genera toString() para una clase que no es de datos
tag android (4)
Situación:
Tengo una clase con campos de lateinit
, por lo que no están presentes en el constructor:
class ConfirmRequest() {
lateinit var playerId: String
}
Me gustaría tener un método toString()
con todos los campos y no quiero escribirlo manualmente, para evitar la impresión de la caldera. En Java usaría la anotación Lombok @ToString
para este problema.
Pregunta:
¿Hay alguna forma de implementarlo en Kotlin?
Al igual que usted, estaba acostumbrado a usar lombok para toString()
y equals()
en Java, por lo que me decepcionó un poco que las clases sin datos en Kotlin requirieran todo el estándar estándar.
Así que creé Kassava , una biblioteca de código abierto que te permite implementar toString()
y equals()
sin ningún tipo de repetición: ¡simplemente proporciona la lista de propiedades y listo!
Por ejemplo:
// 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)
}
Considero que ToStringBuilder
Apache Commons Lang con reflexión es útil, pero llama a hashCode()
y otros métodos cuando no necesito eso (y uno llamado hashCode()
de una hashCode()
de terceros genera un NPE).
Así que solo voy con:
// 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(", ")}]"
}
La forma recomendada es escribir toString
manualmente (o generar por IDE) y esperar que no tenga muchas de estas clases.
El propósito de data class
de data class
es acomodar los casos más comunes del 85%, lo que deja el 15% a otras soluciones.
Puede definir una clase de datos que contenga los datos que desea usar e implementar métodos delegándolos a eso.
https://.com/a/46247234/97777