Home > front end >  Using kotlin.UByte for Room Entity not working
Using kotlin.UByte for Room Entity not working

Time:05-31

I want to store the following dataclass in my room database. Somehow, I do not succeed:

@Entity
data class UInt8(
    @PrimaryKey(autoGenerate = true)
    var key: Int,
    var name: String = "uint8-test",
    var value: UByte = 0.toUByte(),
    var size: Int = 1,
    var readOnly: Boolean = true
) 

I always get the error for my auto-generated build files:

C:<...>\UInt8.java:15: error: Cannot find getter for field.
    private byte value;
Cannot find getter for field.

Same for UShort, UInt and ULong.

However, If I replace it by an Int, it seems to work, but is not what I intented (it needs to be an UByte.


build.grade (from developer.android.com):

def room_version = "2.4.2"

//implementation "androidx.room:room-runtime:$room_version"
//annotationProcessor "androidx.room:room-compiler:$room_version"


implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:2.5.0-alpha01"
// kapt "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.2.0"
// optional - RxJava2 support for Room

implementation "androidx.room:room-rxjava2:$room_version"

// optional - RxJava3 support for Room
implementation "androidx.room:room-rxjava3:$room_version"

// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"

// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"

// optional - Paging 3 Integration
implementation "androidx.room:room-paging:2.5.0-alpha01"

Update 1:
My TypeConverter (Converters.kt) looks the following:

class Converters {
    @TypeConverter
    fun uByteToInt(uByte: UByte): Int = uByte.toInt()
    @TypeConverter
    fun intToUByte(value: Int): UByte = value.toUByte()
}

and AppDatabase.kt:

@Database(entities = [<...>::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun sensorDao(): SensorDao
    ...
}

Update 2:
Probably it is noteworthy that the Class UInt8 is a nested class in another Entity, i.e.:

@Entity()
data class  simpleConfig(
    @Embedded(prefix = "simplec_version_") val version: UInt8 = 
    UInt8("Field Version"),
...)
   

CodePudding user response:

I believe this may well be a bug.

If you have UInt8 as you do, then Room generates the AppDatabase_Impl with the table recognising UByte as an INTEGER e.g.

_db.execSQL("CREATE TABLE IF NOT EXISTS `UInt8` (`key` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `testvalue` INTEGER NOT NULL, `size` INTEGER NOT NULL, `readOnly` INTEGER NOT NULL)");
  • as per the createAllTables method
  • note value was changed to testvalue to ensure that it was being regenerated.

Thus Room understands that UByte equates to a column type of INTEGER.

The issue, I believe, is that it's handling expects Int and hence why the default getters and setters are insufficient. Additionally the TypeConverters are ignored because Room apparently knows how to handle.

If you instead use:-

@Entity
data class UInt8(
    @PrimaryKey(autoGenerate = true)
    var key: Int,
    var name: String = "uint8-test",
    var testvalue: Int = 0,
    var size: Int = 1,
    var readOnly: Boolean = true
) {
    constructor(key: Int, name: String, testvalue: UByte, size: Int, readOnly: Boolean): this(key,name, testvalue.toInt(),size,readOnly)
}

Then Room doesn't complain BUT testvalue would be an Int when retrieving it. However, you would need to override the getters to return a Ubyte from an Int.

However, if you created a class to mask how Room treats UByte's, and implement suitable type converters then they do come into play.

So if you have for example.

data class MyUByte(
    val value: UByte
)

and had:-

@TypeConverter
fun myUByteToInt(myUByte: MyUByte): Int = myUByte.value.toInt()
@TypeConverter
fun intToMyUByte(value: Int): MyUByte = MyUByte(value.toUByte())

and then finally:-

@Entity
data class UInt8(
    @PrimaryKey(autoGenerate = true)
    var key: Int,
    var name: String = "uint8-test",
    var testvalue: MyUByte = MyUByte(0.toUByte()),
    var size: Int = 1,
    var readOnly: Boolean = true
)

Then the TypeConverters aren't ignored and the compilation is fine.

  • Related