Calling generated AutoMigration class in the generated code from the database writer.
Test: AutoMigrationProcessorTest.kt, AutoMigrationWriterTest.kt
Bug: 180395129
Change-Id: I4a7ac3495dd21b296d2ea291c4ec7a67cbe772f4
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
index 4aedd7a..a98a1ce 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
@@ -130,6 +130,7 @@
}
object CommonTypeNames {
+ val ARRAYS = ClassName.get("java.util", "Arrays")
val LIST = ClassName.get("java.util", "List")
val MAP = ClassName.get("java.util", "Map")
val SET = ClassName.get("java.util", "Set")
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
index b9d992c..00268f2 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
@@ -115,13 +115,13 @@
private fun getValidatedSchemaFile(version: Int): File? {
val schemaFile = File(
context.schemaOutFolder,
- "${element.qualifiedName}/$version.json"
+ "${element.className.enclosingClassName()}/$version.json"
)
if (!schemaFile.exists()) {
context.logger.e(
ProcessorErrors.autoMigrationSchemasNotFound(
context.schemaOutFolder.toString(),
- "${element.qualifiedName}/$version.json"
+ "${element.className.enclosingClassName()}/$version.json"
),
element
)
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
index c6a7b9c..0661aa1 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
@@ -36,7 +36,7 @@
class AutoMigrationWriter(
private val dbElement: XElement,
val autoMigrationResult: AutoMigrationResult
-) : ClassWriter(autoMigrationResult.element.className) {
+) : ClassWriter(autoMigrationResult.implTypeName) {
override fun createTypeSpecBuilder(): TypeSpec.Builder {
val builder = TypeSpec.classBuilder(autoMigrationResult.implTypeName)
@@ -98,7 +98,7 @@
"${it.fieldBundle.affinity} "
)
if (it.fieldBundle.isNonNull) {
- append("NOT NULL DEFAULT `${it.fieldBundle.defaultValue}`")
+ append("NOT NULL DEFAULT ${it.fieldBundle.defaultValue}")
} else {
append("DEFAULT NULL")
}
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
index 9902227..c88bb6a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
@@ -31,6 +31,7 @@
import androidx.room.vo.DaoMethod
import androidx.room.vo.Database
import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
import com.squareup.javapoet.FieldSpec
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterSpec
@@ -62,6 +63,7 @@
addMethod(createCreateInvalidationTracker())
addMethod(createClearAllTables())
addMethod(createCreateTypeConvertersMap())
+ addMethod(getAutoMigrations())
}
addDaoImpls(builder)
return builder
@@ -301,4 +303,20 @@
addStatement("return $L", openHelperVar)
}.build()
}
+
+ private fun getAutoMigrations(): MethodSpec {
+ return MethodSpec.methodBuilder("getAutoMigrations").apply {
+ addModifiers(PROTECTED)
+ addAnnotation(Override::class.java)
+ returns(ParameterizedTypeName.get(CommonTypeNames.LIST, RoomTypeNames.MIGRATION))
+ val autoMigrationsList = database.autoMigrations.map {
+ CodeBlock.of("new $L()", it.implTypeName)
+ }
+ addStatement(
+ "return $T.asList( $L )",
+ CommonTypeNames.ARRAYS,
+ CodeBlock.join(autoMigrationsList, ",")
+ )
+ }.build()
+ }
}
diff --git a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
index b0882e0..c75033d 100644
--- a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
+++ b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
@@ -17,7 +17,7 @@
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
- database.execSQL("ALTER TABLE `Song` ADD COLUMN `artistId` INTEGER NOT NULL DEFAULT `0`");
+ database.execSQL("ALTER TABLE `Song` ADD COLUMN `artistId` INTEGER NOT NULL DEFAULT 0");
onPostMigrate(database);
}
}
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index aa123f3..6b6c6d5 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -5,6 +5,7 @@
import androidx.room.RoomOpenHelper;
import androidx.room.RoomOpenHelper.Delegate;
import androidx.room.RoomOpenHelper.ValidationResult;
+import androidx.room.migration.Migration;
import androidx.room.util.DBUtil;
import androidx.room.util.TableInfo;
import androidx.room.util.TableInfo.Column;
@@ -19,6 +20,7 @@
import java.lang.Override;
import java.lang.String;
import java.lang.SuppressWarnings;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -185,6 +187,11 @@
}
@Override
+ protected List<Migration> getAutoMigrations() {
+ return Arrays.asList( );
+ }
+
+ @Override
ComplexDao getComplexDao() {
if (_complexDao != null) {
return _complexDao;
diff --git a/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json
new file mode 100644
index 0000000..8f1c4a3
--- /dev/null
+++ b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json
@@ -0,0 +1,54 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 1,
+ "identityHash": "83c0712e9973d534e0a9b882f1d7c4ce",
+ "entities": [
+ {
+ "tableName": "Entity1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `value1` INTEGER NOT NULL DEFAULT 1, `value2` INTEGER NOT NULL DEFAULT 2, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "value1",
+ "columnName": "value1",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "1"
+ },
+ {
+ "fieldPath": "value2",
+ "columnName": "value2",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "2"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "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, '83c0712e9973d534e0a9b882f1d7c4ce')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json
new file mode 100644
index 0000000..da1b494
--- /dev/null
+++ b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json
@@ -0,0 +1,61 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 2,
+ "identityHash": "78c7261f6c50da0e69cf00d3277c1994",
+ "entities": [
+ {
+ "tableName": "Entity1",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `value1` INTEGER NOT NULL DEFAULT 1, `value2` INTEGER NOT NULL DEFAULT 2, `addedInV2` INTEGER NOT NULL DEFAULT 3, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "value1",
+ "columnName": "value1",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "1"
+ },
+ {
+ "fieldPath": "value2",
+ "columnName": "value2",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "2"
+ },
+ {
+ "fieldPath": "addedInV2",
+ "columnName": "addedInV2",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "3"
+ }
+ ],
+ "primaryKey": {
+ "columnNames": [
+ "id"
+ ],
+ "autoGenerate": false
+ },
+ "indices": [],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "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, '78c7261f6c50da0e69cf00d3277c1994')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java
new file mode 100644
index 0000000..5e3c4aa
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.integration.testapp.migration;
+
+
+import androidx.room.AutoMigration;
+import androidx.room.ColumnInfo;
+import androidx.room.Dao;
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.Query;
+import androidx.room.RoomDatabase;
+import androidx.room.migration.AutoMigrationCallback;
+
+import java.util.List;
+
+@Database(
+ version = AutoMigrationDb.LATEST_VERSION,
+ entities = AutoMigrationDb.Entity1.class,
+ autoMigrations = AutoMigrationDb.SimpleAutoMigration.class,
+ exportSchema = true
+)
+public abstract class AutoMigrationDb extends RoomDatabase {
+ static final int LATEST_VERSION = 2;
+ abstract AutoMigrationDb.AutoMigrationDao dao();
+ @Entity
+ static class Entity1 {
+ public static final String TABLE_NAME = "Entity1";
+ @PrimaryKey
+ public int id;
+ public String name;
+ @ColumnInfo(defaultValue = "1")
+ public int value1;
+ @ColumnInfo(defaultValue = "2")
+ public int value2;
+ @ColumnInfo(defaultValue = "3")
+ public int addedInV2;
+ }
+
+ @Dao
+ interface AutoMigrationDao {
+ @Query("SELECT * from Entity1")
+ List<Entity1> getAllEntity1s();
+ @Insert
+ void insert(AutoMigrationDb.Entity1... entity1);
+ }
+
+ @AutoMigration(from=1, to=2)
+ interface SimpleAutoMigration extends AutoMigrationCallback {}
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
new file mode 100644
index 0000000..cf53daf
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.integration.testapp.migration;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import androidx.room.Room;
+import androidx.room.testing.MigrationTestHelper;
+import androidx.sqlite.db.SupportSQLiteDatabase;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+/**
+ * Test custom database migrations.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class AutoMigrationTest {
+ private static final String TEST_DB = "auto-migration-test";
+ @Rule
+ public MigrationTestHelper helper;
+
+ // TODO: (b/181985265) Implement running AutoMigrations and validate.
+ public AutoMigrationTest() {
+ helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
+ AutoMigrationDb.class.getCanonicalName());
+ }
+
+
+ // Run this to create the very 1st version of the db.
+ public void createFirstVersion() throws IOException {
+ SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);
+ db.close();
+ }
+
+ @Test
+ public void addColumnToDatabaseWithOneTable() throws IOException {
+ try (SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1)) {
+ db.execSQL("INSERT INTO Entity1 (id, name) VALUES (1, 'row1')");
+ }
+ AutoMigrationDb autoMigrationDbV2 = getLatestDb();
+
+ assertThat(autoMigrationDbV2.dao().getAllEntity1s().size(), is(1));
+ }
+
+ private AutoMigrationDb getLatestDb() {
+ AutoMigrationDb db = Room.databaseBuilder(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(),
+ AutoMigrationDb.class, TEST_DB).build();
+ db.getOpenHelper().getWritableDatabase(); // trigger open
+ helper.closeWhenFinished(db);
+ return db;
+ }
+}
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index 061b0ad..d708dbf 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -51,6 +51,7 @@
method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
method protected abstract androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration!);
method @Deprecated public void endTransaction();
+ method protected java.util.List<androidx.room.migration.Migration!> getAutoMigrations();
method public androidx.room.InvalidationTracker getInvalidationTracker();
method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
method public java.util.concurrent.Executor getQueryExecutor();
@@ -108,6 +109,7 @@
public static class RoomDatabase.MigrationContainer {
ctor public RoomDatabase.MigrationContainer();
method public void addMigrations(androidx.room.migration.Migration!...);
+ method public void addMigrations(java.util.List<androidx.room.migration.Migration!>);
method public java.util.List<androidx.room.migration.Migration!>? findMigrationPath(int, int);
}
diff --git a/room/runtime/api/public_plus_experimental_current.txt b/room/runtime/api/public_plus_experimental_current.txt
index b1f6259..608cd54 100644
--- a/room/runtime/api/public_plus_experimental_current.txt
+++ b/room/runtime/api/public_plus_experimental_current.txt
@@ -54,6 +54,7 @@
method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
method protected abstract androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration!);
method @Deprecated public void endTransaction();
+ method protected java.util.List<androidx.room.migration.Migration!> getAutoMigrations();
method public androidx.room.InvalidationTracker getInvalidationTracker();
method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
method public java.util.concurrent.Executor getQueryExecutor();
@@ -113,6 +114,7 @@
public static class RoomDatabase.MigrationContainer {
ctor public RoomDatabase.MigrationContainer();
method public void addMigrations(androidx.room.migration.Migration!...);
+ method public void addMigrations(java.util.List<androidx.room.migration.Migration!>);
method public java.util.List<androidx.room.migration.Migration!>? findMigrationPath(int, int);
}
diff --git a/room/runtime/api/restricted_current.txt b/room/runtime/api/restricted_current.txt
index 9d4e534..8662b57 100644
--- a/room/runtime/api/restricted_current.txt
+++ b/room/runtime/api/restricted_current.txt
@@ -92,6 +92,7 @@
method protected abstract androidx.room.InvalidationTracker createInvalidationTracker();
method protected abstract androidx.sqlite.db.SupportSQLiteOpenHelper createOpenHelper(androidx.room.DatabaseConfiguration!);
method @Deprecated public void endTransaction();
+ method protected java.util.List<androidx.room.migration.Migration!> getAutoMigrations();
method public androidx.room.InvalidationTracker getInvalidationTracker();
method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
method public java.util.concurrent.Executor getQueryExecutor();
@@ -151,6 +152,7 @@
public static class RoomDatabase.MigrationContainer {
ctor public RoomDatabase.MigrationContainer();
method public void addMigrations(androidx.room.migration.Migration!...);
+ method public void addMigrations(java.util.List<androidx.room.migration.Migration!>);
method public java.util.List<androidx.room.migration.Migration!>? findMigrationPath(int, int);
}
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 9b652bf..3411a26 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -45,6 +45,7 @@
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
@@ -184,6 +185,10 @@
@CallSuper
public void init(@NonNull DatabaseConfiguration configuration) {
mOpenHelper = createOpenHelper(configuration);
+ List<Migration> autoMigrations = getAutoMigrations();
+ if (autoMigrations.size() > 0) {
+ configuration.migrationContainer.addMigrations(autoMigrations);
+ }
// Configure SqliteCopyOpenHelper if it is available:
SQLiteCopyOpenHelper copyOpenHelper = unwrapOpenHelper(SQLiteCopyOpenHelper.class,
@@ -256,6 +261,17 @@
}
}
+ @NonNull
+ /**
+ * Returns a list of {@link Migration} of a database that have been generated using
+ * {@link AutoMigration}.
+ *
+ * @return A list of migration instances each of which is a generated autoMigration
+ */
+ protected List<Migration> getAutoMigrations() {
+ return Arrays.asList();
+ }
+
/**
* Unwraps (delegating) open helpers until it finds clazz, otherwise returns null.
*
@@ -1380,6 +1396,12 @@
}
}
+ public void addMigrations(@NonNull List<Migration> migrations) {
+ for (Migration migration : migrations) {
+ addMigration(migration);
+ }
+ }
+
private void addMigration(Migration migration) {
final int start = migration.startVersion;
final int end = migration.endVersion;
@@ -1390,6 +1412,7 @@
}
Migration existing = targetMap.get(end);
if (existing != null) {
+ // TODO: (b/182251019) Favor user specified migration over generated automigrations
Log.w(Room.LOG_TAG, "Overriding migration " + existing + " with " + migration);
}
targetMap.put(end, migration);