Kotlin 数据类、Android Room 和自定义设置器

Posted

技术标签:

【中文标题】Kotlin 数据类、Android Room 和自定义设置器【英文标题】:Kotlin's data class, Android Room and custom setter 【发布时间】:2017-12-10 16:56:08 【问题描述】:

我得到了一个看起来像这样的 android Room 实体。到目前为止,不用担心。

@Entity(tableName = "users",
        indices = arrayOf(Index(value = "nickName", unique = true)))
data class User(@ColumnInfo(name = "nickName") var nickName: String,
                @ColumnInfo(name = "password") var password: String) 

    @ColumnInfo(name = "id")
    @PrimaryKey(autoGenerate = true)
    var id: Long = 0

现在我需要加密密码。使用 Java,只需使用 setter 即可完成此操作。

您将如何使用 Kotlin 来做到这一点。我找不到将 Android Room、自定义设置器和数据类结合起来的解决方案。

【问题讨论】:

为什么不能覆盖值的设置器? 您的问题不清楚。 “使用 Java,只需使用 setter 即可完成此操作,这样就可以了。” - Kotlin 的可变属性有什么问题? @Egor 你如何为数据类做到这一点?通过私人_password 字段?在这种情况下,你在哪里连接@ColumnInfo? @VincentMimoun-Prat 我想从设计的角度来看,在 setter 方法中编码密码不是正确的方法,只需在外部编码然后传递给模型 您可能有兴趣知道最佳做法是不存储密码,而是存储密码的盐和散列。例如见jasypt.org/howtoencryptuserpasswords.html 【参考方案1】:

你可以试试这样的:

@Entity(tableName = "users",
        indices = arrayOf(Index(value = "nickName", unique = true)))
data class User(@ColumnInfo(name = "nickName") var nickName: String,
                private var _password: String) 

    @ColumnInfo(name = "id")
    @PrimaryKey(autoGenerate = true)
    var id: Long = 0

    @ColumnInfo(name = "password")
    var password: String = _password
        set(value) 
            field = "encrypted"
        

    override fun toString(): String 
        return "User(id=$id, nickName='$nickName', password='$password')"
    


但我不建议在 Entity 中加密密码或以某种方式修改密码,因为这不是它的责任,而且你可能会遇到密码双重加密的错误,因为当你从数据库中检索实体时,Room 会用数据填充实体这将导致加密已经加密的数据。

【讨论】:

这会解决问题,但现在表中必须有两列,“_password”和“password”。我还尝试用@Ignore 注释“_password”,但 ROOM 无法编译。有什么建议吗? @DariushMalek,正如我在答案中所写 - 我不推荐这种方法,最好对数据类的数据进行任何操作,仅将其用作获取和设置的容器数据。【参考方案2】:
    @Entity(tableName = "users",
            indices = arrayOf(Index(value = "nickName", unique = true)))
    data class User(@ColumnInfo(name = "nickName") var nickName: String,
                    @ColumnInfo(name = "password") var password: String) 
    var _password = password
        set(value): String
           //encrypt password
        
        @ColumnInfo(name = "id")
        @PrimaryKey(autoGenerate = true)
        var id: Long = 0
    

这将创建一个自定义设置器,因此每次设置密码时,您都可以在设置器内对其进行加密。

【讨论】:

甚至没有编译 导致IDE编译错误:“overload resolution ambiguous” Getter 和 setter 可以在数据类中调用自定义,但您必须为它创建一个新变量。所以变量“密码”需要被称为别的东西。例如_密码

以上是关于Kotlin 数据类、Android Room 和自定义设置器的主要内容,如果未能解决你的问题,请参考以下文章

Android的room数据库使用小结(kotlin)

将 Kotlin 内联类作为实体字段的房间数据库

Android Kotlin 中的 ROOM 数据库出错

Android Kotlin Room 与Flow的应用 demo 添加数据并展示

Kotlin Android Room 数据库删除查询问题

Room Kotlin 找不到字段的设置器