Reputation: 2242
I have an enum class SettingsVisibility
inside an database entity, which I am converting to a bitmask to store in the database. I am trying to reverse the conversion to bitmask, and get a list of enums as a return value. So if I have an enum with values ONE(1), TWO(2), FOUR(4)
, then it'll store as Enum(7)
. I want to take 7
and convert it to {ONE, TWO, FOUR}
.
My code is below. I have the SettingsVisibility
enum with integer values which are stored in the DB. When I try to retrieve from the database, Objectbox
will use the given PropertyConvertor
to marshall/unmarshall the data. When I want to convertToEntityProperty
, it should return a list of just the saved enums, but at the moment it returns a list of all the enums. I can pass a databaseValue
of 12
and it will return all enums instead of just 2 (LOCATION AND PAYMENTS).
I think the issue is the usage of enumClass.enumConstants
because it gets all the values, but then the filter doesn't work on this, so I am stuck.
@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)
}
So for example, if I store the first 3, the database value will be 7 (1+2+4).
The database is ObjectBox
and here are the property converters:
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
}
Maybe the logic in hasFlag
is wrong, because I think that just gets every enum if it isn't 0.
Upvotes: 0
Views: 802
Reputation: 2242
Answer was to replace return true
, with:
if (flag?.bit?.toByte() == null) {
return false
}
return (this.value.toByte().and(flag.bit.toByte()) == flag.bit.toByte())
This is basically: bit & mask == bit
Upvotes: 0