realm-java: Cannot be @Required or @NotNull.

Goal

Compile the project

Expected Results

Compile without errors

Actual Results

Error: Field “fields” with type “com.myApp.sample” cannot be @Required or @NotNull.

Steps & Code to Reproduce

I just updated the Realm version (realm-gradle-plugin) from 3.5.0 to 3.7.2. If I move back to 3.5.0 it works.

Code Sample

class Class(@PrimaryKey var id: Int = 0, var fields: Fields): RealmObject()

Version of Realm and tooling

Realm version(s): 3.7.2

Realm sync feature enabled: No

Android Studio version: 3.0 Beta 6

Which Android version and device: None

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 5
  • Comments: 20 (12 by maintainers)

Most upvoted comments

Hi folks.

You are breaking the implementation of the library on all possible Kotlin projects just to satisfy a new behavior. I recommend you to think again the implementation and stop forcing the developer to, in a very hard way, change the source code. Just because Realm is not capable to always return a non null object, it doesn’t means that the library can’t handle it. Should be good to have a way to disable this nullability verification or add a default value. But let the developer choose what to do with the project, not the inverse. I will expend a lot of time just to solve this nullability issue and I will increase the risk of failure on my software.

Sorry, but this is very frustating and annoying.

@ppamorim It isn’t really a new behavior, but just exposing the reality of the underlying Realm correctly.

If you can guarantee internally that the reference is never null, you can use it as a backing property: https://kotlinlang.org/docs/reference/properties.html#backing-properties and then do the conversion in custom getters and setters, like:

    var _person: Person? = null

    // Automatically ignored as it doesn't have a backing field
    var person: Person
        get() = _person!!
        set(value) {
            _person = value
        }

@nkanellopoulos

Added realm.ignoreKotlinNullability as a kapt argument to disable treating kotlin non-null types as @Required (#5412) (introduced in v3.6.0.)

@cmelchior If I get this right, what you have done destroys a very nice feature of Kotlin: lateinit variables. And will force us to scatter null checks all over the place.

Plus, I now have to correct 23 compilation errors (and I’m lucky, could be a lot more!)

Because in Realm 3.5.0

class Class(@PrimaryKey var id: Int = 0, var fields: Fields): RealmObject()

var fields : Fields was automatically treated as nullable even though in the Kotlin type system it was non-null.

In 3.6 we added support for the Kotlin type-system which means that the fields variable is now correctly identified as non-null, but non-null object references are not supported by Realm (as we cannot guarantee that invariant), which is why you are getting that error.

// This would be the accurate class declaration in 3.7.2
class Class(@PrimaryKey var id: Int = 0, var fields: Fields?): RealmObject()

If your object has an Id, you can treat it as foreign key and make it required. for example

public class Category extends RealmObject {

    @PrimaryKey
    private long id;
}

public class Item extends RealmObject {
    @PrimaryKey
    private long id;

    private long categoryId; // primitive types cant be null

    public getCategory(Realm realm) {
        return realm.where(Category.class).equalTo("id", categoryId).findFirst();
    }
}

@cmelchior

    var _person: Person? = null

    // Automatically ignored as it doesn't have a backing field
    var person: Person
        get() = _person!!
        set(value) {
            _person = value
        }

This in Kotlin will fail to compile, var _person: Person? = null requires to have a getter or setter. Try it yourself using Kotlin 1.1.51 and you’ll get a lint error.

Let’s face the truth, Realm is in any way Kotlin friendly, would that be the case then Data Classes which are the proper way of defining entities in Kotlin will work out of the box instead of getting the classical “must declare a public constructor” error at compile-time.

@cmelchior I am doing something similar, but just renaming the variable to avoid any Realm migration. Something like this:

open class Foo(@PrimaryKey var id: Int = 0, var bar: Bar?): RealmObject() {

  @Ignore
  var unwrappedBar: Bar = bar!!
    private set

}

What is Fields? Maybe it should be Fields??