580

I am using Android Database Component Room

I've configured everything, but when I compile, Android Studio gives me this warning:

Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide room.schemaLocation annotation processor argument OR set exportSchema to false.

As I understand it is the location where DB file will be located

How can it affect my app? What is the best practice here? Should I use the default location (false value)?

0

18 Answers 18

602

In the build.gradle file for your app module, add this to the defaultConfig section (under the android section). This will write out the schema to a schemas subfolder of your project folder.

javaCompileOptions {
    annotationProcessorOptions {
        arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
    }
}

Like this:

// ...

android {
    
    // ... (compileSdkVersion, buildToolsVersion, etc)

    defaultConfig {

        // ... (applicationId, miSdkVersion, etc)
        
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }
   
    // ... (buildTypes, compileOptions, etc)

}

// ...
Sign up to request clarification or add additional context in comments.

12 Comments

If anyone is wondering, this exact approach also works for Kotlin when using kapt
Should we gitignore the json file generated in the app/schemas directory by this operation. And I heard we should put the schema into a directory that is not included in the apk. How can we do that?
@ravi the generated schema file(s) should be stored in version control as this is used by Room to detect changes and help ensure if the database changes you update the database version and create a migration plan
use arguument += so it does not mess with your DI libraries like Hilt.(see this answer for more information stackoverflow.com/a/62891182/5780236)
@ChantellOsejo updated just now. Changed "arguments = ..." to "arguments += ...".
|
561

As per the docs:

You can set annotation processor argument (room.schemaLocation) to tell Room to export the schema into a folder. Even though it is not mandatory, it is a good practice to have version history in your codebase and you should commit that file into your version control system (but don't ship it with your app!).

So if you don't need to check the schema and you want to get rid of the warning, just add exportSchema = false to your RoomDatabase, as follows.

@Database(entities = { YourEntity.class }, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
   //...
}

If you follow @mikejonesguy answer below, you will follow the good practice mentioned in the docs. Basically you will get a .json file in your ../app/schemas/ folder, which looks something like this:

{
  "formatVersion": 1,
  "database": {
    "version": 1,
    "identityHash": "53db508c5248423325bd5393a1c88c03",
    "entities": [
      {
        "tableName": "sms_table",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `message` TEXT, `date` INTEGER, `client_id` INTEGER)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER"
          },
          {
            "fieldPath": "message",
            "columnName": "message",
            "affinity": "TEXT"
          },
          {
            "fieldPath": "date",
            "columnName": "date",
            "affinity": "INTEGER"
          },
          {
            "fieldPath": "clientId",
            "columnName": "client_id",
            "affinity": "INTEGER"
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"53db508c5248423325bd5393a1c88c03\")"
    ]
  }
}

If my understanding is correct, you will get such a file with every database version update, so that you can easily follow the history of your db.

11 Comments

What does it really mean "Don't ship with your app" ? It will included in APK ?
If follow "Don't ship with your app", should I remove JSON files before generating APK?
"Don't ship with your app" means "Don't set schemaLocation to like 'app/res/raw'. Set the schemaLocation to a directory not included in the APK."
@galcyurio $projectDir/schemas is a directory out of the APK, right? I have explored the generated APK and I don't see it over there. Although I see /res (which accounts for app/src/main/res) for example.
@xarlymg89 Were you able to confirm that $projectDir/schemas is NOT included in the APK? According to this answer, custom subdirectories are not.
|
353

Kotlin? Here we go:

android {

    // ... (compileSdkVersion, buildToolsVersion, etc)

    defaultConfig {

        // ... (applicationId, miSdkVersion, etc)

        kapt {
            arguments {
                arg("room.schemaLocation", "$projectDir/schemas")
            }
        }
    }

    buildTypes {
        // ... (buildTypes, compileOptions, etc)
    }
}

//...

Don't forget about plugin:

apply plugin: 'kotlin-kapt'

For more information about kotlin annotation processor please visit: Kotlin docs

6 Comments

I got a > No signature of method: build_xyz.android() is applicable for argument types: (build_xyz$_run_closure1) values: [build_xyz$_run_closure1@719007a9] where xyz is a long random string... is it a bug?
This is probably a better option
@mikejonesguy's answer above worked for me.
Same issue here with the missing signature method.
When using javaCompileOptions as suggested by other answers I saw an error "Caused by: groovy.lang.MissingMethodException: No signature of method: build_....android() is applicable for argument types... ". It looks like javaCompileOptions might have been deprecated. I'm using AGP v7.0.2. I needed to use kapt{} instead to set the argument as described by Ivanov (I used it within android{} and the schema was output).
|
133

For Kotlin KSP:

ksp {
    arg('room.schemaLocation', "$projectDir/schemas")
}

(it's Groovy DSL, in Kotlin DSL use double quotes)

5 Comments

You can paste this wherever you want to the build.gradle (:app).
where to paste this guys?
@josh you can paste in your defaultConfig tag in build.gradle (:app)
I was told to turn the single quotes into double quotes, but otherwise this worked for me!
@PaulStephenson Single quotes are used in Groovy DSL. In Kotlin DSL you should use double quotes.
18

Above answers are correct. This version is easy to follow:

Because "Schema export directory is not provided to the annotation processor", So we need to provide the directory for schema export:

Step [1] In your file which extends the RoomDatabase, change the line to:

`@Database(entities = ???.class,version = 1, exportSchema = true)`

Or

`@Database(entities = ???.class,version = 1)` 

(because the default value is always true)

Step [2] In your build.gradle(project:????) file, inside the defaultConfig{ } (which is inside android{ } big section), add the javaCompileOptions{ } section, it will be like:

         android{
                defaultConfig{
                      //javaComplieOptions SECTION
                      javaCompileOptions {
                            annotationProcessorOptions {
                                     arguments = ["room.schemaLocation":"$projectDir/schemas".toString()]
                            }
                       }
                      //Other SECTION
                      ...
                }
         }

$projectDir:is a variable name, you cannot change it. it will get your own project directory

schemas:is a string, you can change it to any you like. For example: "$projectDir/MyOwnSchemas".toString()

1 Comment

in step[2], are you sure it's the build.gradle(project:????) and not build.gradle(app:????)?
16

@mikejonesguy answer is perfect, just in case you plan to test room migrations (recommended), add the schema location to the source sets.

In your build.gradle file you specify a folder to place these generated schema JSON files. As you update your schema, you’ll end up with several JSON files, one for every version. Make sure you commit every generated file to source control. The next time you increase your version number again, Room will be able to use the JSON file for testing.

build.gradle

android {

    // [...]

    defaultConfig {

        // [...]

        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }

    // add the schema location to the source sets
    // used by Room, to test migrations
    sourceSets {
        androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
    }

    // [...]
}

1 Comment

this causes some conflicts with Hilt, just replace the arguments = with arguments +=
11

Just posting what worked for me using Kotlin DSL

defaultConfig {
        applicationId = ""
        minSdk = 26
        targetSdk = 33
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
        
        //add this in the build.gradle.kts(app) file
        javaCompileOptions {
            annotationProcessorOptions {
                arguments["room.schemaLocation"] =
                    "$projectDir/schemas"
            }
        }
    }

For this to work you also need to set exportSchema to true

@Database(entities = [Entity::class], version = 1, exportSchema = true)
@TypeConverters(Converters::class)
abstract class ScoresDatabase : RoomDatabase() {

    abstract val dao: ScoresDAO
}

To confirm it worked, you should see the newly created schemas directory off the module root directory with the next build as illustrated below.

enter image description here

Comments

11

LATEST method

For room version higher 2.6.0 you can use the Room gradle plugin as mentioned in the doc

In the Gradle top level build.gradle[.kts] file add the following line in the Gradle plugin block

plugins {
    id("androidx.room") version "$room_version" apply false
}

In the app module(or lib module where your Room db is defined) you can add the following Gradle plugin

plugins {
    id("androidx.room")
}

And then in the file level of the build.gradle[.kts] add room block just like we add android block below

room {
    schemaDirectory("$projectDir/schemas")
}

OLDER method

In case either you are not using the Room Gradle plugin or you are using an older Room version than 2.6.0. Add the below blocks in the file level(in the app or lib module where db is present) as per the doc

// For KSP
ksp {
    arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
}

// For javac and KAPT
android {
    ...
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                compilerArgumentProviders(
                    RoomSchemaArgProvider(File(projectDir, "schemas"))
                )
            }
        }
    }
}

// This is required as schema location is directory and using Gradle `CommandLineArgumentProvider` is important for correctness and incremental build 
class RoomSchemaArgProvider(
    @get:InputDirectory
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val schemaDir: File,
) : CommandLineArgumentProvider {
    override fun asArguments(): Iterable<String> {
        // Note: If you're using KAPT and javac, change the line below to
        // return listOf("-Aroom.schemaLocation=${schemaDir.path}").
        return listOf("room.schemaLocation=${schemaDir.path}")
    }
}

2 Comments

After trying all the other solutions, adding the block "room { schemaDirectory(...) }" did the trick for me (using Room 2.6.1 and ksp)
Yeah it depends on the Room version as based on the lib version they have changes their recommendation
7

kapt {
  arguments {
    arg("room.schemaLocation", "$projectDir/schemas")
  }
}

Comments

7

I use .kts Gradle files (Kotlin Gradle DSL) and the kotlin-kapt plugin but I still get a script compilation error when I use Ivanov Maksim's answer.

Unresolved reference: kapt

For me this was the only thing which worked:

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments += mapOf("room.schemaLocation" to "$rootDir/schemas")
            }
        }
    }
}

2 Comments

Nothing is working for me either. I am using Kotlin.
How does this answer work? arguments is a MutableMap, val arguments: MutableMap<String, String> and gives compile error when you try to assign anything, and adding with arguments["room.schemaLocation"] ="$projectDir/schemas"does not work for me. Other answer also does not work.
6

If using room 2.6.0 and above + version catalog + Kotlin DSL:

Versions catalog:

[versions]
room = "2.6.1"

[plugins]
room = { id = "androidx.room", version.ref = "room" }

build.gradle(app):

plugins {
    alias(libs.plugins.room)
}

android {
    room {
        schemaDirectory("$projectDir/schemas")
    }
}

build.gradle(project):

plugins {
    alias(libs.plugins.room) apply false
}

Comments

5

Kotlin way according to official document:

android {
...
defaultConfig {
    ...
    javaCompileOptions {
        annotationProcessorOptions {
            arguments += mapOf(
                "room.schemaLocation" to "$projectDir/schemas",
                "room.incremental" to "true",
                "room.expandProjection" to "true"
            )
        }
    }
}
}

Comments

5

If you are using room with ksp add this in your app-module-build

android {
...
defaultConfig {
    ...
    /**
     * Set the Room database schema export location for debug build to inspect the database
     */
    ksp {
        arg("room.schemaLocation", "$projectDir/schemas")
    }
  }
}

Comments

1

If like me you recently moved certain classes to different packages ect. and you use android navigation. Make sure to change the argType to you match you new package address. from:

app:argType="com.example.app.old.Item" 

to:

app:argType="com.example.app.new.Item" 

1 Comment

So weird, mine was because of the import statement in DataBinding XML
1
// For javac or KAPT, configure using android DSL:
android {
  ...
  defaultConfig {
    javaCompileOptions {
      annotationProcessorOptions {
        compilerArgumentProviders(
          RoomSchemaArgProvider(File(projectDir, "schemas"))
        )
      }
    }
  }
}

// For KSP, configure using KSP extension:
ksp {
  arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
}

Comments

0

Probably you didn't add your room class to child RoomDatabase child class in @Database(entities = {your_classes})

Comments

0

If you are using room with ksp in the module build you have to define RoomSchemaArgProvider

class RoomSchemaArgProvider(
    @get:InputDirectory
    @get:PathSensitive(PathSensitivity.RELATIVE)
    val schemaDir: File
) : CommandLineArgumentProvider {

    override fun asArguments(): Iterable<String> {
        // Note: If you're using KSP, change the line below to return
         return listOf("room.schemaLocation=${schemaDir.path}")
//        return listOf("-Aroom.schemaLocation=${schemaDir.path}")
    }
}

android {


    // For KSP, configure using KSP extension:
    ksp {
        arg(RoomSchemaArgProvider(File(projectDir, "schemas")))
    }
}

And then make sure that you have directory in app/schemas Do not know why it was not created automatically in my case.

Comments

0

With version 2.7.2 none of this changes anything, likely because method schemaDirectory(path: String) of the RoomExtension does not function.

When passing Pair(key, value) instead of mapOf(key to value), it stops complaining.
One can then also remove the Room plug-in altogether, as it probably does not much else,
except: warning that the annotation-processor does not know about the export location.

android.defaultConfig {
    javaCompileOptions {
        annotationProcessorOptions {
            arguments += Pair("room.schemaLocation", "$rootDir/schemas")
        }
    }
}

It seems as if AnnotationProcessorOptions used to be an array of Map and is now Pair.
But the AGP documentation clearly reads: val arguments: MutableMap<String, String>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.