首页 > 解决方案 > 从 Kotlin 中的位掩码获取枚举列表

问题描述

我在数据库实体中有一个枚举类SettingsVisibility,我将其转换为位掩码以存储在数据库中。我正在尝试将转换反转为位掩码,并获取枚举列表作为返回值。因此,如果我有一个带有 values 的枚举ONE(1), TWO(2), FOUR(4),那么它将存储为Enum(7). 我想把7它转换成{ONE, TWO, FOUR}.

我的代码如下。我有SettingsVisibility存储在数据库中的整数值的枚举。当我尝试从数据库中检索时,Objectbox将使用给定PropertyConvertor的数据来编组/解组数据。当我想要时convertToEntityProperty,它应该返回一个仅包含已保存枚举的列表,但目前它返回一个所有枚举的列表。我可以通过 a databaseValueof 12,它会返回所有枚举,而不仅仅是 2(位置和付款)。

我认为问题在于它的使用,enumClass.enumConstants因为它获取了所有值,但是过滤器对此不起作用,所以我被卡住了。

@Entity
data class Settings(
        @Id override var id: Long = 0,
        @Convert(converter = DocumentVisibilityConverter::class, dbType = Int::class)
        val showItems: List<SettingsVisibility>
) : Identifiable<Long> {
    lateinit var organisation: ToOne<Organisation>
 
    constructor() : this(
            showItems = emptyList(),
    )

    enum class SettingsVisibility(override val bit: Int) : Flags {
        USERS(1),
        FINANCE(2),
        LOCATION(4),
        PAYMENTS(8),
        MESSAGES(16),
        ERRORS(32),
        CANCELLATIONS(64)
    }

    internal class DocumentVisibilityConverter
        : BoxConverters.EnumFlagConverter<SettingsVisibility>(SettingsVisibility::class.java)
}

例如,如果我存储前 3 个,则数据库值为 7 (1+2+4)。

数据库是ObjectBox,这里是属性转换器:

    abstract class EnumFlagConverter<E>(private val enumClass: Class<E>) : PropertyConverter<List<E>, Int> where E : Enum<E>, E : Flags {
        override fun convertToDatabaseValue(entityProperty: List<E>?): Int? {
            return entityProperty?.toBitMask()?.value
        }

        override fun convertToEntityProperty(databaseValue: Int?): List<E>? {
            return databaseValue?.let(::BitMask)?.enabledValues(enumClass)
        }
    }

class BitMask(val value: Int)

interface Flags {
    val bit: Int

    fun toBitMask() = BitMask(bit)


fun <T> BitMask.enabledValues(enumClass: Class<T>): List<T>? where T : Enum<T>, T : Flags? {
    return enumClass.enumConstants?.filter(::hasFlag)
}

infix fun <T : Flags?> BitMask.hasFlag(flag: T): Boolean {
    if (value == 0 || (value > 0 && flag?.bit == 0)) {
        return false
    }

    return true
}

也许其中的逻辑hasFlag是错误的,因为我认为如果它不是 0,它只会获取每个枚举。

标签: kotlinenumsbitmask

解决方案


答案是将 , 替换return true为:

if (flag?.bit?.toByte() == null) {
    return false
}
return (this.value.toByte().and(flag.bit.toByte()) == flag.bit.toByte())

这基本上是:bit & mask == bit


推荐阅读