538

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)?

Samet ÖZTOPRAK
  • 3,112
  • 3
  • 32
  • 33
Misha Akopov
  • 12,241
  • 27
  • 68
  • 82

13 Answers13

582

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)

}

// ...
mikejonesguy
  • 9,779
  • 2
  • 35
  • 49
  • 73
    If anyone is wondering, this exact approach also works for Kotlin when using *kapt* – DanielDiSu Dec 02 '17 at 11:40
  • 2
    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 Jul 08 '18 at 09:57
  • 7
    @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 – appmattus Aug 27 '18 at 07:54
  • 2
    Does this configuration affect to the release version? I mean, when I export the project to a release app. – Anargu Sep 12 '18 at 19:39
  • If this solution results in **ERROR: Could not find method annotationProcessorOptions() for arguments**, check out Luna's answer, below: https://stackoverflow.com/a/54366985/1617737 – ban-geoengineering Oct 02 '19 at 11:50
  • Desse jeito funcionou, a solução anterior do @DoruChidean não funcionou no meu cenário. – Diego Farias Nov 08 '19 at 04:11
  • 7
    use `arguument +=` so it does not mess with your DI libraries like Hilt.(see this answer for more information https://stackoverflow.com/a/62891182/5780236) – Ahmad Reza Enshaee Sep 27 '20 at 14:11
  • @mikejonesguy an edit with the information in these comments would be super helpful. Knowing it works with kapt - I missed that and also went down a rabbit hole with the Hilt problem mentioned by Ahmad. – Chantell Osejo Jan 19 '21 at 00:41
  • 3
    @ChantellOsejo updated just now. Changed "arguments = ..." to "arguments += ...". – mikejonesguy Jan 20 '21 at 01:11
  • I added the javaCompileOptions to my gradle file but still get the warning. What am I missing? – Lance Jun 28 '21 at 15:06
  • this should be upvoted for good reasons – Anuj Jun 29 '22 at 21:47
541

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. And it 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.

Tupio
  • 432
  • 7
  • 19
DoruChidean
  • 7,941
  • 1
  • 29
  • 33
  • I ran into this same error but it was due to adding a constructor to my Entity. Simply add '@Ignore' to any constructor that errors and ad a new blank constructor. – Codeversed Feb 14 '18 at 19:02
  • 12
    What does it really mean "Don't ship with your app" ? It will included in APK ? – Jongz Puangput Mar 10 '18 at 00:48
  • Yes, I got a similar json file with all the details. – Prashant Apr 28 '18 at 15:35
  • 3
    If follow "Don't ship with your app", should I remove JSON files before generating APK? – illusionJJ May 15 '18 at 02:47
  • 14
    "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 Jul 06 '18 at 09:38
  • 3
    @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 Jul 11 '18 at 09:55
  • 2
    @xarlymg89 Were you able to confirm that `$projectDir/schemas` is _NOT_ included in the APK? According to [this answer](https://stackoverflow.com/a/10927390/11566289), custom subdirectories are not. –  Jul 18 '19 at 12:31
  • 2
    @glucaio I explored the APK (and the App bundle too) and didn't find it. So I believe we're safe. – xarlymg89 Jul 18 '19 at 12:47
  • How do we keep this out of a release APK? – justColbs Jan 08 '20 at 01:00
  • use `exportSchema = false` and it will not be generated – DoruChidean Jan 09 '20 at 08:34
  • The link in the answer points to the deprecated documentation of android.arch package. The corresponding documentation in androidx.* is: https://developer.android.com/reference/androidx/room/Database#exportSchema() – M.Paunov Apr 06 '22 at 13:17
332

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

Nicolas
  • 6,611
  • 3
  • 29
  • 73
Ivanov Maksim
  • 3,460
  • 1
  • 11
  • 10
  • 2
    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? – Minh Nghĩa Nov 24 '20 at 15:08
  • 1
    [This](https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schema) is probably a better option – sprajagopal Jun 13 '21 at 13:36
  • @mikejonesguy's answer above worked for me. – sprajagopal Jun 13 '21 at 13:45
  • Same issue here with the missing signature method. – Akito Oct 09 '21 at 21:21
  • 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). – Ollie C Oct 19 '21 at 09:45
  • When using this solution, i had to move the DB definition as described here: https://stackoverflow.com/a/68649685/2664521 Using https://developer.android.com/training/data-storage/room/migrating-db-versions#export-schema prevented the need of moving the file – CyclingSir Jun 29 '22 at 17:37
46

For Kotlin KSP:

ksp {
    arg('room.schemaLocation', "$projectDir/schemas")
}
Eyjafl
  • 1,046
  • 6
  • 14
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()

LunaRivolxoxo
  • 330
  • 2
  • 5
  • 1
    in step[2], are you sure it's the `build.gradle(project:????)` and not `build.gradle(app:????)`? – Ace Mar 08 '20 at 11:10
15

@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())
    }

    // [...]
}
chebaby
  • 7,362
  • 50
  • 46
7

kapt {
  arguments {
    arg("room.schemaLocation", "$projectDir/schemas")
  }
}
Sagar Balyan
  • 620
  • 6
  • 20
6

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 "$projectDir/schemas")
            }
        }
    }
}
jsa
  • 1,050
  • 10
  • 22
  • Nothing is working for me either. I am using Kotlin. – nyxee Apr 06 '20 at 21:42
  • How does this answer work? arguments is a MutableMap, `val arguments: MutableMap` 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. – Thracian Aug 30 '20 at 12:34
4

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"
            )
        }
    }
}
}
Ali Zarei
  • 3,523
  • 5
  • 33
  • 44
3

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

Tonnie
  • 4,865
  • 3
  • 34
  • 50
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" 
Haider Malik
  • 1,581
  • 1
  • 20
  • 23
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")))
}
reznic
  • 672
  • 6
  • 9
0

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

Neuron
  • 1,020
  • 2
  • 13
  • 28