How to annotate Column as NOT NULL using Android Room Persistence Library

36,095

Solution 1

In order to identify exact annotation for NOT NULL I went through the list of all annotations provided at this link: android.arch.persistence.room but could not find any relevant annotation:

enter image description here

My assumption is that since you are using Kotlin, which by default treats a var as non-optional, all the attributes declared by you are NOT NULL. In order to declare a var as optional probably you have to use a ? operator, an example below:

var name: String // NOT NULL 
var name: String? // OPTIONAL

Updated based on comment:

I guess you are confused with NULL and empty string. NULL means no value, in the shared code you are providing a default value to each column which is an empty string and that is not equal to NULL, so even though you might not have provided a value for that attribute it is by default assigning an empty string to it.

Try removing value assignment operator and RHS value for an attribute and then insert the record without assigning value to that attribute, you should get appropriate error.

Basically, convert below statement:

@ColumnInfo(name = "name") var name: String = ""

To

@ColumnInfo(name = "name") var name: String

Solution 2

For Java you should annotate with @android.support.annotation.NonNull

DO NOT CONFUSE WITH @io.reactivex.annotations.NonNull

Solution 3

For Java I used @NonNull after the @ColumnInfo:

@ColumnInfo(name = "column_name")
@NonNull private String str;

Ensure that you have imported the correct library in the class:

import android.support.annotation.NonNull;

Solution 4

Complementary answer for those using Kotlin:

please note that marking a type as non optional will automatically make it not null (and an optional type will not do that).

You can check it in the schema generated by room with @Database(exportSchema = true) on your database.

For example I have something like that:

@Entity(tableName = "messages")
data class Message (
        @PrimaryKey
        val messageId: UUID = UUID.randomUUID(),
        val date: Date = Date(),
        val receivedDate: Date? = null
)

And in the generated schema I can read:

"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (
    `messageId` TEXT NOT NULL, 
    `date` INTEGER NOT NULL, 
    `receivedDate` INTEGER, 
    PRIMARY KEY(`messageId`)
)"

(Note: the Date type is here an Int and the UUID a string due to converters I use elsewhere)

Solution 5

As a work around to actual table constraints, you could use a single method TypeConverter class to make sure your String members are not null.

For example, for a Non-null String, you could use:

public class RoomConverterNullString {
    @TypeConverter
    public static String fromNullToString(String value) {
        if (value == null) {
            return "";
        } else {
            return value;
        }
    }
}

You can simplify it like this, of course:

public class RoomConverterNullString {
    @TypeConverter
    public static String fromNullToString(String value) {
        return (value == null) ? "" : value;
    }
}

And you can use it like this:

@TypeConverters(RoomConverterNullString.class)
public String stringMember;

Any assignments and update/insert actions will store an empty string value when the value is null and any retrieval will force a null value to be converted to an empty string.

You can do this for other types and for any default values you wish to have.

Share:
36,095
Tuby
Author by

Tuby

Writing Point Of Sale applications for Android

Updated on January 08, 2021

Comments

  • Tuby
    Tuby over 3 years

    My data class looks like this

    @Entity(tableName = "items")
    data class Item(
            @ColumnInfo(name = "name") var name: String = "",
            @ColumnInfo(name = "room") var room: String = "",
            @ColumnInfo(name = "quantity") var quantity: String = "",
            @ColumnInfo(name = "description") var description: String = "",
            @PrimaryKey(autoGenerate = true)
            @ColumnInfo(name = "id") var id: Long = 0
    )
    

    Room uses SQLite and SQLite supports NOT NULL columns in its database. I tried annotating columns with @NonNull but it has no effect.

    Is there a way to make columns in Room Database not nullable?

  • Tuby
    Tuby almost 7 years
    My understanding of what NOT NULL in database means it cannot be empty field, it needs to have a value assigned so that empty string "" would be considered NULL. In kotlin String means it has object assigned that is not null, empty string by default in my case. I just want my database to throw exception when it is assigned empty string. I guess you can't do that in Room
  • Tuby
    Tuby almost 7 years
    I will mark it as correct because it clarified my confusion between empty string and null. However in my particular case your proposed converted statement(second one) is not compilable because Room requires default constructor, and to do so each parameter has to have default value. But thanks for help!
  • codeyourstack
    codeyourstack over 5 years
    You just saved my day!
  • Ishwor Khanal
    Ishwor Khanal over 5 years
    What else if we need to use RxJava with Room then which should we import while creating entity?
  • Nokuap
    Nokuap over 5 years
    Ishwor Khanal, same @android.support.annotation.NonNull, rx's annottation mostly used for internal purposes
  • daka
    daka over 5 years
    Thanks, initially, this answer wasn't working for me because I had the scope set to private on the variable.
  • Beer Me
    Beer Me over 5 years
    Note that primitive types (int, long, etc) are always considered to be NonNull, and you don't have to annotate them as such.
  • mochadwi
    mochadwi about 5 years
    Thanks. with NonNull annotation + set the properties without assignment fixed the issue for me as well @Devarshi
  • user1713450
    user1713450 about 4 years
    "it needs to have a value assigned so that empty string "" would be considered NULL" That is not correct. An empty string is not null. Null is null. Empty string is a string object of length 0.
  • shield
    shield over 3 years
    @BeerMe, do you know where it is documented? I just found a mention of the management of the primitive types in this article. It seems that float types are not treated the same and are nullable by default.
  • Beer Me
    Beer Me over 3 years
    @shield, I don't have the actual documentation handy, but this answer sums it up pretty well: stackoverflow.com/a/11047335/295028
  • Beer Me
    Beer Me over 3 years
    Also, I don't see any reference to float types in your linked article, but it does say "All the primitive types are by default non null in Room".
  • shield
    shield over 3 years
    @BeerMe, thanks. My mistake regarding the float type. In the example I looked at, the column type was not primitive. It was declared as Float, not float, and was therefore nullable by default.