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.