You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Edit: The original issue described below about default values has moved to #157.
ℹ This issue is now about correctly detecting not-nullable properties of Kotlin data classes.
Issue Basics
ObjectBox version (are using the latest version?): 2.2
I added a new int (not Integer) property into an existing entity. And I found that the new property values for existing record are all null instead of default value (0 in this case), and the the equal query will always return empty result.
box.query().equal( intProperty, 0) -> zero result
box.query().notEqual( intProperty, 0) -> zero result
box.query().isNull( intProperty ) -> non-empty result
Is this considered a bug? Or I should expect null for primitive property
Interesting that we got a crash in case when we add new field to entity with not nullable type. E.g.
Create entity with one field.
Run the app. Put new entity in db.
Add new field to entity e.g. var someField: Int = 0.
Run the app and get all saved entities from db.
In our case it crashes. Is it means that automatic migration is totally broken when we use kotlin? @greenrobot-team@greenrobot Should I create standalone ticket for this case with an example of project where bug can be reproduced?
@Yazon2006 Just tried this with a very simple example and val someField: Int = 0 works, but obviously val anotherField: String = "default" does not.
As a rule of thumb: when adding new properties make them nullable (so String? instead of String). Maybe someone can also come up with some constructor magic (probably only for regular classes).
// before
@Entity
data classExample(
@Id varid:Long = 0
)
// after
@Entity
data classExample(
@Id varid:Long = 0,
valsomeProperty:Int = 42, // primitive type, maps to 0 for existing entitiesvalanotherProperty:String? = "default"// nullable for compat with previous model
)
The issue is that for properties stored as primitives (internally we call this scalars, like long, double, Date) in ObjectBox a null entry is mapped to a non-nullable type when getting an object, e.g. 0 for int. But if the property is stored as a nullable type, like String, ObjectBox will map no entry to null instead when getting the object.
Yes it's pretty reasonable, I understand. But it can be a bit painful and confusing. E.g. when Entity implements some interface with non null fields we still need to use non null values. And for such case I used workaround like this:
interface SyncItem {
var itemId: String
var isSynchronized: Boolean
}
class Entity(
//ugly duplicated field
var dbItemId: String? = null,
override var isSynchronized: Boolean = false
) : SyncItem {
override var itemId: String
get() = dbItemId ?: generateItemId()
set(value) {
dbItemId = value
}
}
I would be glad to know if there are other more convenient ways to handle such kind of problems.
We could probably fix this by trying to detect non-null Kotlin properties. Then flag them as such so ObjectBox will not try to init them with null.
The byte-code produced by Kotlin annotates non-null properties with org/jetbrains/annotations/NotNull. Based on a quick check the ObjectBox processor can see it.
-ut
There are a ton of other artifacts providing these kind of annotations. Here is the relevant ones from the list IntelliJ IDEA covers by default, with Maven coordinates for the artifacts containing them just for the reference:
com.android.annotations.NonNull (part of Android SDK)
I don't say every one of them should be supported, but it might be reasonable to cover at least javax.annotation and maybe Android ones in addition to Kotlin / JetBrains ones, if Java people find this convenient.
OK, sorry, I completely let multiple issues get mangled together here.
@LeeKingHung@jrcacd and others, refer to #157 for the issue that default values are not as expected.
ℹ This issue is now about correctly detecting not-nullable properties of Kotlin data classes.
@r4zzz4k Thanks for adding this. For now with Kotlin it is more pressing as it will actually lead to a crash due to Kotlin's runtime nullability checks.
changed the title [-]New property in existing entity (ObjectBox default values)[/-][+]Adding non-null Kotlin property causes crash when getting existing entity[/+]on Mar 4, 2019
I used an annotation that seemed to solve the problem, at least I did.
The object to add a field is called Apple, use @BaseEntity to declare an abstract class Fruit, move the new field in Apple to Fruit, and make Apple extend Fruit to solve this problem. I hope to help you.
Actually adding a non-null property still crashes, but with 2.6.0-RC you will now see a Java exception with the actual reason.
Also, with 2.6.0-RC, instead of manually adding a converter as suggested above, you can now just annotate a non-null String property with @DefaultValue(""):
@DefaultValue("")
var nonNull:String=""
Keeping this open to as mentioned add support for adding non-null Kotlin properties without user intervention.
Activity
greenrobot-team commentedon Oct 29, 2018
Thanks for reporting!
Internally, added properties are by default
null. That should be correct.ping @greenrobot Though not sure if the database should treat
nullas if the default value was set (0,false, etc.) for primitive types?-ut
jrcacd commentedon Nov 8, 2018
the same in our code.
We added a field
And the field is null (and it makes no sense)
motornyimaksym commentedon Feb 25, 2019
Interesting that we got a crash in case when we add new field to entity with not nullable type. E.g.
In our case it crashes. Is it means that automatic migration is totally broken when we use kotlin?
@greenrobot-team @greenrobot Should I create standalone ticket for this case with an example of project where bug can be reproduced?
[-]New property in existing entity[/-][+]New property in existing entity (ObjectBox default values)[/+]greenrobot-team commentedon Feb 26, 2019
@Yazon2006 Just tried this with a very simple example and
val someField: Int = 0works, but obviouslyval anotherField: String = "default"does not.As a rule of thumb: when adding new properties make them nullable (so
String?instead ofString). Maybe someone can also come up with some constructor magic (probably only for regular classes).The issue is that for properties stored as primitives (internally we call this scalars, like long, double, Date) in ObjectBox a null entry is mapped to a non-nullable type when getting an object, e.g.
0for int. But if the property is stored as a nullable type, like String, ObjectBox will map no entry tonullinstead when getting the object.motornyimaksym commentedon Feb 26, 2019
Yes it's pretty reasonable, I understand. But it can be a bit painful and confusing. E.g. when Entity implements some interface with non null fields we still need to use non null values. And for such case I used workaround like this:
I would be glad to know if there are other more convenient ways to handle such kind of problems.
greenrobot-team commentedon Feb 26, 2019
We could probably fix this by trying to detect non-null Kotlin properties. Then flag them as such so ObjectBox will not try to init them with
null.The byte-code produced by Kotlin annotates non-null properties with
org/jetbrains/annotations/NotNull. Based on a quick check the ObjectBox processor can see it.-ut
motornyimaksym commentedon Feb 26, 2019
Sounds awesome! Thank you for your efforts! Looking forward.
r4zzz4k commentedon Feb 27, 2019
There are a ton of other artifacts providing these kind of annotations. Here is the relevant ones from the list IntelliJ IDEA covers by default, with Maven coordinates for the artifacts containing them just for the reference:
org.jetbrains.annotations.NotNull(org.jetbrains:annotations:17.0.0)javax.annotation.Nonnull(e.g.com.google.code.findbugs:jsr305:3.0.2)edu.umd.cs.findbugs.annotations.NonNull(com.google.code.findbugs:findbugs-annotations:3.0.1)android.support.annotation.NonNull(com.android.support:support-annotations:28.0.0from https://maven.google.com)androidx.annotation.NonNull(androidx.annotation:annotation:1.0.2from https://maven.google.com)org.checkerframework.checker.nullness.qual.NonNull(org.checkerframework:checker-qual:2.6.0)com.android.annotations.NonNull(part of Android SDK)I don't say every one of them should be supported, but it might be reasonable to cover at least
javax.annotationand maybe Android ones in addition to Kotlin / JetBrains ones, if Java people find this convenient.greenrobot-team commentedon Mar 4, 2019
OK, sorry, I completely let multiple issues get mangled together here.
@LeeKingHung @jrcacd and others, refer to #157 for the issue that default values are not as expected.
ℹ This issue is now about correctly detecting not-nullable properties of Kotlin data classes.
@r4zzz4k Thanks for adding this. For now with Kotlin it is more pressing as it will actually lead to a crash due to Kotlin's runtime nullability checks.
[-]New property in existing entity (ObjectBox default values)[/-][+]Adding non-null Kotlin property causes crash when getting existing entity[/+]chaxiu commentedon Oct 14, 2019
@greenrobot-team
Hi, greenrobot team, any update for this issue?
greenrobot-team commentedon Oct 15, 2019
@chaxiu No. But it's easy to avoid by making sure to use nullable properties. See my comment: #589 (comment)
FeamCoco commentedon Jan 15, 2020
I used an annotation that seemed to solve the problem, at least I did.
The object to add a field is called Apple, use
@BaseEntityto declare an abstract class Fruit, move the new field in Apple to Fruit, and make Apple extend Fruit to solve this problem. I hope to help you.greenrobot-team commentedon Apr 27, 2020
An alternative workaround to keep a non-null Kotlin property: use
@Convert. An example using String:greenrobot commentedon Apr 28, 2020
We just published 2.6.0-RC which should not crash.
Additionally, you can now use
@DefaultValue("")to introduce a new non-optional string property.We'd love some feedback on this before releasing! E.g.
@DefaultValuemay suggest "too much", another name might be@AbsentValue.greenrobot-team commentedon May 4, 2020
Actually adding a non-null property still crashes, but with
2.6.0-RCyou will now see a Java exception with the actual reason.Also, with
2.6.0-RC, instead of manually adding a converter as suggested above, you can now just annotate a non-null String property with@DefaultValue(""):Keeping this open to as mentioned add support for adding non-null Kotlin properties without user intervention.