I am currently developing a new android app using Kotlin. I tried implementing Room for data storage, but I didn't get it to work with Kotlin delegates.
I created an Identifier
delegate in order to ensure the id is not changed after initialization. The delegate looks like this:
class Identifier: ReadWriteProperty<Any?, Long> {
private var currentValue = -1L
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
if (currentValue == -1L) throw IllegalStateException("${property.name} is not initialized.")
return currentValue
}
override fun setValue(thisRef: Any?, property KProperty<*>, value: Long) {
if (currentValue != -1L) throw IllegalStateException("${property.name} can not be changed.")
currentValue = value
}
}
My entity class looks like this:
@Entity
class Sample {
@delegate:PrimaryKey(autoGenerate = true)
var id by Identifier()
}
When I try to start the app, kapt gives me the following error message:
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final com.myapp.persistence.delegates.Identifier id$delegate = null;
Can I somehow get this to work without writing a TypeConverter
for every delegate?
Use @delegate:Ignore
.
I had similar problem with my Entity Object and ... by lazy
properties.
For example:
var name: String = "Alice"
val greeting: String by lazy { "Hi $name" }
The issue here is Room "cannot figure out how to save this field into database". I tried to add "@Ignore" but got a lint message saying "This annotation is not applicable to target 'member property with delegate'."
Turns out, the correct annotation in this case is @delegate:Ignore
.
Solution:
var name: String = "Alice"
@delegate:Ignore
val greeting: String by lazy { "Hi $name" }
Unfortunatelly, no - Room by default creates a column for each field that's defined in the entity and when we use delegate
we get generated code like this:
@PrimaryKey(autoGenerate = true)
@NotNull
private final Identifier id$delegate = new Identifier();
public final long getId() {
return this.id$delegate.getValue(this, $$delegatedProperties[0]);
}
public final void setId(long var1) {
this.id$delegate.setValue(this, $$delegatedProperties[0], var1);
}
and that's why Room tries to create column for Identifier id$delegate
.
However, if you just want to ensure id
is not changed after object initialization you don't need delegate at all, simply mark variable as final
and place it in constructor eg:
@Entity
data class Sample(
@PrimaryKey(autoGenerate = true)
val id: Long
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With