Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

159
Views
Cómo actualizar la clase de datos de Kotlin con propiedades de una clase de datos diferente

Si tengo por ejemplo una entidad:

 data class SampleEntity( val a: Int, val b: Int, val c: Int, val d: Int){ fun update(form: SampleEntityUpdateForm): SampleEntity{ ... return this SampleEntity updated with form } }

y un formulario para actualizar esta entidad:

 data class SampleEntityUpdateForm( val a: Int?, val b: Int?, val c: Int?, val d: Int? )

¿Cuál es la mejor manera de actualizar la entidad con este formulario (es decir, implementar SampleEntity.update(...)), dejando las propiedades que son nulas en SampleEntityUpdateForm como estaban en la entidad original, con una placa de caldera mínima.

Así por ejemplo:

 val sampleEntityInst = SampleEntity(1,2,3,4) val sampleEntityUpdateForm(b = 20, d = 40) val updatedSampleEntityInst = sampleEntityInst.update(sampleEntityUpdateForm)

donde actualizadoSampleEntityInst será igual a SampleEntity(1,20,3,40).

obviamente podría implementar SampleEntity.update como:

 fun update(form: SampleEntityUpdateForm) = SampleEntity( a = form.a ?: this.a, b = form.b ?: this.b, c = form.c ?: this.c, d = form.d ?: this.d, )

Pero esto tiene un poco de repetición/repetición. ¿Hay algo ya hecho para permitir hacer esto con menos repetición/placa de caldera?

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Compruebe el método de copia disponible en todas las clases de datos, por ejemplo:

 data class SampleEntity( val a: Int, val b: Int, val c: Int, val d: Int){ fun update(form: SampleEntityUpdateForm): SampleEntity{ return this.copy(a = form.a, b = form.b, ...) } }

Editar : me perdí el giro de nulabilidad. El uso de la función magic a continuación funciona, pero en mi opinión, el enfoque directo tiene una mejor ergonomía.

Puede haber casos de uso en los que la reflexión esté bien: una gran cantidad de propiedades, una transformación complicada de los parámetros entrantes, etc.

 fun main() { val sampleEntityForm = SampleEntityUpdateForm(a = null, b = 20, c = null, d = 40) val sampleEntityInst = SampleEntity(1, 2, 3, 4) magic(sampleEntityForm, sampleEntityInst).also { println(it) } // prints: SampleEntity(a=1, b=20, c=3, d=40) } fun magic(from: SampleEntityUpdateForm, using: SampleEntity): SampleEntity { val fromValues = from::class.members.filterIsInstance<KProperty1<SampleEntityUpdateForm, Int?>>().map { it.get(from) } val usingValues = using::class.members.filterIsInstance<KProperty1<SampleEntity, Int>>().map { it.get(using) } val nullsEliminated = usingValues.mapIndexed { i, value -> fromValues[i] ?: value }.toTypedArray() return SampleEntity::class.primaryConstructor!!.call(*nullsEliminated) }
over 4 years ago · Santiago Trujillo Report

0

Este es el problema con la escritura estática. El modelo y la repetitividad vienen incorporados. Creo que tu ejemplo con a = form.a ?: this.a es una buena solución. Al usar un lenguaje escrito estáticamente como Kotlin, es mejor aceptar el modelo estándar y seguir adelante.

Si quieres ser más elegante, tienes que usar algo más dinámico. Por ejemplo, puede utilizar JSON, que es más flexible. Esta solución utiliza JsonMergePatch de JSON-P para crear un parche y aplicarlo a su objeto. Estoy usando Jackson para convertir entre objetos POJO y JSON a través de la reflexión.

Este método tiene la ventaja de poder establecer valores en null a través del parche también. Si el valor en el parche es null , establece el valor de destino en null . Si el valor no está en el parche, se conserva el valor existente. Esto es algo que no puedes hacer muy bien de forma nativa; tienes que empezar a volverte loco con cosas como nullable Optional s.

 fun main() { val original = SampleEntity(a = 0, b = 0, c = 0, d = 0) val patch = Json.createObjectBuilder() .add("b", 2) .add("d", 4) .build().let { Json.createMergePatch(it) } val patched: SampleEntity = original.update(patch) println(patched) } data class SampleEntity( val a: Int, val b: Int, val c: Int, val d: Int ) { fun update(patch: JsonMergePatch): SampleEntity { val jsonValue = objectMapper.convertValue<JsonValue>(this) val patched = patch.apply(jsonValue) return objectMapper.convertValue(patched) } companion object { private val objectMapper: ObjectMapper = ObjectMapper() .registerKotlinModule() .registerModule(JSONPModule()) } }

Producción:

 SampleEntity(a=0, b=2, c=0, d=4)

Dependencias:

 dependencies { implementation("jakarta.json", "jakarta.json-api", "2.0.1") implementation("org.glassfish", "jakarta.json", "2.0.1") implementation("com.fasterxml.jackson.core", "jackson-core", "2.13.0") implementation("com.fasterxml.jackson.datatype", "jackson-datatype-jakarta-jsonp", "2.12.2") implementation("com.fasterxml.jackson.module", "jackson-module-kotlin", "2.13.0") }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!