当前位置: 首页 > 知识库问答 >
问题:

将Kotlin数据对象映射到数据对象的更好方法

吕永嘉
2023-03-14
data class PersonForm(
    val firstName: String,
    val lastName: String,
    val age: Int,
    // maybe many fields exist here like address, card number, etc.
    val tel: String
)
// maps to ...
data class PersonRecord(
    val name: String, // "${firstName} ${lastName}"
    val age: Int, // copy of age
    // maybe many fields exist here like address, card number, etc.
    val tel: String // copy of tel
)

更新:每个类的用途取决于哪种应用程序,但这些类可能被放置在应用程序的不同层中。

例如:

  • 数据从数据库(数据库实体)到HTML表单(模型/视图模型)的数据
  • REST API结果到数据库的数据
    null

当然,一个具有类似特性的库是有意的,但是Kotlin特性的信息也是受欢迎的(比如在ECMAScript中传播)。

共有1个答案

黄景胜
2023-03-14

>

  • 最简单(最好?):

    fun PersonForm.toPersonRecord() = PersonRecord(
            name = "$firstName $lastName",
            age = age,
            tel = tel
    )
    

    反思(不是很好的表现):

    fun PersonForm.toPersonRecord() = with(PersonRecord::class.primaryConstructor!!) {
        val propertiesByName = PersonForm::class.memberProperties.associateBy { it.name }
        callBy(args = parameters.associate { parameter ->
            parameter to when (parameter.name) {
                "name" -> "$firstName $lastName"
                else -> propertiesByName[parameter.name]?.get(this@toPersonRecord)
            }
        })
    }
    

    缓存反射(性能不错,但不如#1):

    open class Transformer<in T : Any, out R : Any>
    protected constructor(inClass: KClass<T>, outClass: KClass<R>) {
        private val outConstructor = outClass.primaryConstructor!!
        private val inPropertiesByName by lazy {
            inClass.memberProperties.associateBy { it.name }
        }
    
        fun transform(data: T): R = with(outConstructor) {
            callBy(parameters.associate { parameter ->
                parameter to argFor(parameter, data)
            })
        }
    
        open fun argFor(parameter: KParameter, data: T): Any? {
            return inPropertiesByName[parameter.name]?.get(data)
        }
    }
    
    val personFormToPersonRecordTransformer = object
    : Transformer<PersonForm, PersonRecord>(PersonForm::class, PersonRecord::class) {
        override fun argFor(parameter: KParameter, data: PersonForm): Any? {
            return when (parameter.name) {
                "name" -> with(data) { "$firstName $lastName" }
                else -> super.argFor(parameter, data)
            }
        }
    }
    
    fun PersonForm.toPersonRecord() = personFormToPersonRecordTransformer.transform(this)
    
    data class PersonForm(val map: Map<String, Any?>) {
        val firstName: String   by map
        val lastName: String    by map
        val age: Int            by map
        // maybe many fields exist here like address, card number, etc.
        val tel: String         by map
    }
    
    // maps to ...
    data class PersonRecord(val map: Map<String, Any?>) {
        val name: String    by map // "${firstName} ${lastName}"
        val age: Int        by map // copy of age
        // maybe many fields exist here like address, card number, etc.
        val tel: String     by map // copy of tel
    }
    
    fun PersonForm.toPersonRecord() = PersonRecord(HashMap(map).apply {
        this["name"] = "${remove("firstName")} ${remove("lastName")}"
    })
    

  •  类似资料:
    • 问题内容: 我一直在尝试使用PC上的JSON文件将JSON数据映射到Java对象,但是它总是抛出异常: 我的数据类: 我的映射器类: json文件包含以下数据: 我究竟做错了什么?我正在使用Jackson图书馆。 问题答案: 这是我在您的代码中看到的问题列表: 该属性应放在类之上,而不是类之上。查阅文档,最值得注意的是有关“ ignoreUnknown”属性的说法,默认为false: 公共抽象布尔

    • 我已经建立了一个网络爬虫收集数据并存储在RDF/XML文件中,现在我想把数据映射到我的java对象...我该怎么做呢? 我找到了这段代码,可能对我有用,但我似乎不能正确地使用它...它从我的RDF/XML文件中收集主语、谓词和对象,但我可以用我的java指定对象来表示这些数据,我不知道如何...我搜索了很多,但没有很多有用的东西,所以对伙计们有帮助!:d 我想用这个java对象来表示它...这是我

    • 映射对象的每一个属性到一个变量中,这个过程就是我们知道的多声明。这就是为什么会有componentX函数被自动创建。使用上面的Forecast类举个例子: val f1 = Forecast(Date(), 27.5f, "Shiny day") val (date, temperature, details) = f1 上面这个多声明会被编译成下面的代码: val date = f1.compo

    • 我正在尝试将我的对象[]数组映射并过滤到int[]数组。如果对象是int,效果很好,但如果不是int,则抛出强制转换异常。我想知道我是否可以在lambda表达式中附加一个try/catch?这是我的代码: 或者更好的方法是试着抓住整个街区?

    • 使用一个函数将数组的值映射到对象,其键值对中,原始值作为键,映射值作为值。 使用一个匿名的内部函数作用域来声明一个 undefined 的内存空间,使用闭包来存储返回值。 使用一个新的 Array 来存储带有函数映射的数组和一个逗号运算符来返回第二个步骤,而不需要从一个上下文移动到另一个上下文(由于闭包和操作顺序)。 const mapObject = (arr, fn) => (a => (

    • A Table 对象可以被指示从数据库中已经存在的相应数据库架构对象加载关于其自身的信息。此过程称为 反射 。在最简单的情况下,您只需指定表名,即 MetaData 对象,而 autoload_with 参数:: >>> messages = Table('messages', meta, autoload_with=engine) >>> [c.name for c in messages.co