从 Kotlin 中的位掩码获取枚举列表
Getting list of enums from bitmask in Kotlin
我在数据库实体中有一个枚举 class SettingsVisibility
,我正在将其转换为位掩码以存储在数据库中。我正在尝试反向转换为位掩码,并获取枚举列表作为 return 值。因此,如果我有一个值为 ONE(1), TWO(2), FOUR(4)
的枚举,那么它将存储为 Enum(7)
。我想把 7
转换成 {ONE, TWO, FOUR}
.
我的代码如下。我有 SettingsVisibility
枚举,其中包含存储在数据库中的整数值。当我尝试从数据库中检索时,Objectbox
将使用给定的 PropertyConvertor
到 marshall/unmarshall 数据。当我想要 convertToEntityProperty
时,它应该 return 只是保存的枚举的列表,但目前它 return 是所有枚举的列表。我可以传递 12
的 databaseValue
,它将 return 所有枚举,而不仅仅是 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 就获取它。
答案是将 return true
替换为:
if (flag?.bit?.toByte() == null) {
return false
}
return (this.value.toByte().and(flag.bit.toByte()) == flag.bit.toByte())
这基本上是:bit & mask == bit
我在数据库实体中有一个枚举 class SettingsVisibility
,我正在将其转换为位掩码以存储在数据库中。我正在尝试反向转换为位掩码,并获取枚举列表作为 return 值。因此,如果我有一个值为 ONE(1), TWO(2), FOUR(4)
的枚举,那么它将存储为 Enum(7)
。我想把 7
转换成 {ONE, TWO, FOUR}
.
我的代码如下。我有 SettingsVisibility
枚举,其中包含存储在数据库中的整数值。当我尝试从数据库中检索时,Objectbox
将使用给定的 PropertyConvertor
到 marshall/unmarshall 数据。当我想要 convertToEntityProperty
时,它应该 return 只是保存的枚举的列表,但目前它 return 是所有枚举的列表。我可以传递 12
的 databaseValue
,它将 return 所有枚举,而不仅仅是 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 就获取它。
答案是将 return true
替换为:
if (flag?.bit?.toByte() == null) {
return false
}
return (this.value.toByte().and(flag.bit.toByte()) == flag.bit.toByte())
这基本上是:bit & mask == bit