Enforce base class for classes annotated with RoomDatabase
Also renamed support db classes to match the framework's naming.
Bug: 32342709
Test: DatabaseProcessorTest
Change-Id: I588d8ddf42b3c91c5b709090659c56ce04a576b8
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt
index 5657867..4968fd1 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt
@@ -32,8 +32,8 @@
fun TypeMirror.typeName() = TypeName.get(this)
object SupportDbTypeNames {
- val DB: ClassName = ClassName.get("com.android.support.db", "SupportDb")
- val SQLITE_STMT : ClassName = ClassName.get("com.android.support.db", "SupportSqliteStatement")
+ val DB: ClassName = ClassName.get("com.android.support.db", "SupportSQLiteDatabase")
+ val SQLITE_STMT : ClassName = ClassName.get("com.android.support.db", "SupportSQLiteStatement")
}
object RoomTypeNames {
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/processor/DatabaseProcessor.kt b/room/compiler/src/main/kotlin/com/android/support/room/processor/DatabaseProcessor.kt
index 320c5d9..9694a24 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/processor/DatabaseProcessor.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/processor/DatabaseProcessor.kt
@@ -16,6 +16,7 @@
package com.android.support.room.processor
+import com.android.support.room.ext.RoomTypeNames
import com.android.support.room.ext.hasAnyOf
import com.android.support.room.vo.DaoMethod
import com.android.support.room.vo.Database
@@ -36,13 +37,22 @@
val entityParser = EntityProcessor(context)
val daoParser = DaoProcessor(context)
+ val baseClassElement : TypeMirror by lazy {
+ context.processingEnv.elementUtils.getTypeElement(
+ RoomTypeNames.ROOM_DB.packageName() + "." + RoomTypeNames.ROOM_DB.simpleName())
+ .asType()
+ }
+
fun parse(element: TypeElement): Database {
val dbAnnotation = MoreElements
.getAnnotationMirror(element, com.android.support.room.Database::class.java)
.orNull()
-
val entities = processEntities(dbAnnotation, element)
+ val extendsRoomDb = context.processingEnv.typeUtils.isAssignable(
+ MoreElements.asType(element).asType(), baseClassElement)
+ context.checker.check(extendsRoomDb, element, ProcessorErrors.DB_MUST_EXTEND_ROOM_DB)
+
val allMembers = context.processingEnv.elementUtils.getAllMembers(element)
val daoMethods = allMembers.filter {
it.hasAnyOf(Modifier.ABSTRACT) && it.kind == ElementKind.METHOD
@@ -53,6 +63,7 @@
val dao = daoParser.parse(MoreTypes.asTypeElement(executable.returnType))
DaoMethod(executable, executable.simpleName.toString(), dao)
}
+
return Database(element = element,
entities = entities,
daoMethods = daoMethods)
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt
index 5686408..47253bb 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt
@@ -18,6 +18,7 @@
import com.android.support.room.Insert
import com.android.support.room.Query
+import com.android.support.room.ext.RoomTypeNames
import com.android.support.room.vo.Field
object ProcessorErrors {
@@ -74,6 +75,9 @@
val CANNOT_FIND_ENTITY_FOR_INSERT_PARAMETER = "Cannot find the entity type for the" +
" insert parameter."
+ val DB_MUST_EXTEND_ROOM_DB = "Classes annotated with @Database should extend " +
+ RoomTypeNames.ROOM_DB
+
private val TOO_MANY_MATCHING_GETTERS = "Ambiguous getter for %s. All of the following " +
"match: %s. You can @Ignore the ones that you don't want to match."
diff --git a/room/compiler/src/test/data/daoWriter/output/WriterDao.java b/room/compiler/src/test/data/daoWriter/output/WriterDao.java
index ee99ec9..e5dc0c9 100644
--- a/room/compiler/src/test/data/daoWriter/output/WriterDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/WriterDao.java
@@ -16,7 +16,7 @@
package foo.bar;
-import com.android.support.db.SupportSqliteStatement;
+import com.android.support.db.SupportSQLiteStatement;
import com.android.support.room.EntityInsertionAdapter;
import com.android.support.room.RoomDatabase;
import java.lang.Override;
@@ -39,7 +39,7 @@
}
@Override
- public void bind(SupportSqliteStatement stmt, User value) {
+ public void bind(SupportSQLiteStatement stmt, User value) {
stmt.bindLong(0, value.uid);
}
};
@@ -51,7 +51,7 @@
}
@Override
- public void bind(SupportSqliteStatement stmt, User value) {
+ public void bind(SupportSQLiteStatement stmt, User value) {
stmt.bindLong(0, value.uid);
}
};
@@ -90,4 +90,4 @@
__db.endTransaction();
}
}
-}
\ No newline at end of file
+}
diff --git a/room/compiler/src/test/kotlin/com/android/support/room/processor/DatabaseProcessorTest.kt b/room/compiler/src/test/kotlin/com/android/support/room/processor/DatabaseProcessorTest.kt
index 3fa8d27..b772007 100644
--- a/room/compiler/src/test/kotlin/com/android/support/room/processor/DatabaseProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/com/android/support/room/processor/DatabaseProcessorTest.kt
@@ -37,6 +37,7 @@
const val DATABASE_PREFIX = """
package foo.bar;
import com.android.support.room.*;
+ import com.android.support.db.SupportSQLiteDatabase;
"""
val USER: JavaFileObject = JavaFileObjects.forSourceString("foo.bar.User",
"""
@@ -84,8 +85,11 @@
fun simple() {
singleDb("""
@Database(entities = {User.class})
- public interface MyDb {
- UserDao userDao();
+ public abstract class MyDb extends RoomDatabase {
+ public MyDb(SupportSQLiteDatabase supportDb) {
+ super(supportDb);
+ }
+ abstract UserDao userDao();
}
""", USER, USER_DAO) { db, invocation ->
assertThat(db.daoMethods.size, `is`(1))
@@ -97,7 +101,10 @@
fun multiple() {
singleDb("""
@Database(entities = {User.class, Book.class})
- public abstract class MyDb {
+ public abstract class MyDb extends RoomDatabase {
+ public MyDb(SupportSQLiteDatabase supportDb) {
+ super(supportDb);
+ }
abstract UserDao userDao();
abstract BookDao bookDao();
}
@@ -110,6 +117,16 @@
}.compilesWithoutError()
}
+ @Test
+ fun detectMissingBaseClass() {
+ singleDb("""
+ @Database(entities = {User.class, Book.class})
+ public abstract class MyDb {
+ }
+ """, USER, BOOK) { db, invocation ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.DB_MUST_EXTEND_ROOM_DB)
+ }
+
fun singleDb(input: String, vararg otherFiles: JavaFileObject,
handler: (Database, TestInvocation) -> Unit): CompileTester {
return Truth.assertAbout(JavaSourcesSubjectFactory.javaSources())
diff --git a/room/db/src/main/java/com/android/support/db/SupportDb.java b/room/db/src/main/java/com/android/support/db/SupportSQLiteDatabase.java
similarity index 94%
rename from room/db/src/main/java/com/android/support/db/SupportDb.java
rename to room/db/src/main/java/com/android/support/db/SupportSQLiteDatabase.java
index e1bf01d..f9d9c1f 100644
--- a/room/db/src/main/java/com/android/support/db/SupportDb.java
+++ b/room/db/src/main/java/com/android/support/db/SupportSQLiteDatabase.java
@@ -23,8 +23,8 @@
* sql versions.
*/
@SuppressWarnings("unused")
-public interface SupportDb {
- // TODO override all and rename to SupportSqliteDatabase
+public interface SupportSQLiteDatabase {
+ // TODO override all methods
/**
* Runs the query with the given arguments and returns the result Cursor.
*
@@ -42,7 +42,7 @@
*
* @return Compiled statement.
*/
- SupportSqliteStatement compileStatement(String sql);
+ SupportSQLiteStatement compileStatement(String sql);
/**
* Begins a transaction in EXCLUSIVE mode.
diff --git a/room/db/src/main/java/com/android/support/db/SupportSqliteProgram.java b/room/db/src/main/java/com/android/support/db/SupportSQLiteProgram.java
similarity index 98%
rename from room/db/src/main/java/com/android/support/db/SupportSqliteProgram.java
rename to room/db/src/main/java/com/android/support/db/SupportSQLiteProgram.java
index d042551..c23568c 100644
--- a/room/db/src/main/java/com/android/support/db/SupportSqliteProgram.java
+++ b/room/db/src/main/java/com/android/support/db/SupportSQLiteProgram.java
@@ -21,7 +21,7 @@
*/
@SuppressWarnings("unused")
-public interface SupportSqliteProgram {
+public interface SupportSQLiteProgram {
/**
* Bind a NULL value to this statement. The value remains bound until
* {@link #clearBindings} is called.
diff --git a/room/db/src/main/java/com/android/support/db/SupportSqliteStatement.java b/room/db/src/main/java/com/android/support/db/SupportSQLiteStatement.java
similarity index 97%
rename from room/db/src/main/java/com/android/support/db/SupportSqliteStatement.java
rename to room/db/src/main/java/com/android/support/db/SupportSQLiteStatement.java
index ba40227..e3ebc5e 100644
--- a/room/db/src/main/java/com/android/support/db/SupportSqliteStatement.java
+++ b/room/db/src/main/java/com/android/support/db/SupportSQLiteStatement.java
@@ -22,7 +22,7 @@
* An interface to map the behavior of {@link android.database.sqlite.SQLiteStatement}.
*/
@SuppressWarnings("unused")
-public interface SupportSqliteStatement extends SupportSqliteProgram {
+public interface SupportSQLiteStatement extends SupportSQLiteProgram {
/**
* Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
* CREATE / DROP table, view, trigger, index etc.
diff --git a/room/runtime/src/main/java/com/android/support/room/EntityInsertionAdapter.java b/room/runtime/src/main/java/com/android/support/room/EntityInsertionAdapter.java
index 66e0686..8882b72 100644
--- a/room/runtime/src/main/java/com/android/support/room/EntityInsertionAdapter.java
+++ b/room/runtime/src/main/java/com/android/support/room/EntityInsertionAdapter.java
@@ -16,8 +16,8 @@
package com.android.support.room;
-import com.android.support.db.SupportDb;
-import com.android.support.db.SupportSqliteStatement;
+import com.android.support.db.SupportSQLiteDatabase;
+import com.android.support.db.SupportSQLiteStatement;
import java.util.ArrayList;
import java.util.List;
@@ -35,15 +35,15 @@
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class EntityInsertionAdapter<T> {
private final AtomicBoolean mStmtLock = new AtomicBoolean(false);
- private final SupportDb mDatabase;
- private volatile SupportSqliteStatement mStmt;
+ private final SupportSQLiteDatabase mDatabase;
+ private volatile SupportSQLiteStatement mStmt;
/**
* Creates an InsertionAdapter that can insert the entity type T into the given database.
*
* @param database The database to insert into.
*/
- public EntityInsertionAdapter(SupportDb database) {
+ public EntityInsertionAdapter(SupportSQLiteDatabase database) {
mDatabase = database;
}
@@ -61,15 +61,15 @@
* createInsertQuery.
* @param entity The entity of type T.
*/
- protected abstract void bind(SupportSqliteStatement statement, T entity);
+ protected abstract void bind(SupportSQLiteStatement statement, T entity);
- private SupportSqliteStatement createNewStatement() {
+ private SupportSQLiteStatement createNewStatement() {
String query = createInsertQuery();
return mDatabase.compileStatement(query);
}
- private SupportSqliteStatement getStmt(boolean canUseCached) {
- final SupportSqliteStatement stmt;
+ private SupportSQLiteStatement getStmt(boolean canUseCached) {
+ final SupportSQLiteStatement stmt;
if (canUseCached) {
if (mStmt == null) {
mStmt = createNewStatement();
@@ -90,7 +90,7 @@
public final void insert(T entity) {
boolean useCached = !mStmtLock.getAndSet(true);
try {
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
bind(stmt, entity);
stmt.executeInsert();
} finally {
@@ -108,7 +108,7 @@
public final void insert(T[] entities) {
boolean useCached = !mStmtLock.getAndSet(true);
try {
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
for (T entity : entities) {
bind(stmt, entity);
}
@@ -127,7 +127,7 @@
public final void insert(List<T> entities) {
boolean useCached = !mStmtLock.getAndSet(true);
try {
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
for (T entity : entities) {
bind(stmt, entity);
}
@@ -147,7 +147,7 @@
public final long insertAndReturnId(T entity) {
boolean useCached = !mStmtLock.getAndSet(true);
try {
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
bind(stmt, entity);
return stmt.executeInsert();
} finally {
@@ -167,7 +167,7 @@
boolean useCached = !mStmtLock.getAndSet(true);
try {
final long[] result = new long[entities.size()];
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
int index = 0;
for (T entity : entities) {
bind(stmt, entity);
@@ -192,7 +192,7 @@
boolean useCached = !mStmtLock.getAndSet(true);
try {
final long[] result = new long[entities.length];
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
int index = 0;
for (T entity : entities) {
bind(stmt, entity);
@@ -217,7 +217,7 @@
boolean useCached = !mStmtLock.getAndSet(true);
try {
final List<Long> result = new ArrayList<>(entities.length);
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
int index = 0;
for (T entity : entities) {
bind(stmt, entity);
@@ -242,7 +242,7 @@
boolean useCached = !mStmtLock.getAndSet(true);
try {
final List<Long> result = new ArrayList<>(entities.size());
- final SupportSqliteStatement stmt = getStmt(useCached);
+ final SupportSQLiteStatement stmt = getStmt(useCached);
int index = 0;
for (T entity : entities) {
bind(stmt, entity);
diff --git a/room/runtime/src/main/java/com/android/support/room/RoomDatabase.java b/room/runtime/src/main/java/com/android/support/room/RoomDatabase.java
index 3d43bc5..e7e9a25 100644
--- a/room/runtime/src/main/java/com/android/support/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/com/android/support/room/RoomDatabase.java
@@ -18,23 +18,18 @@
import android.database.Cursor;
-import com.android.support.db.SupportDb;
-import com.android.support.db.SupportSqliteStatement;
-
-import java.util.HashMap;
-import java.util.Map;
+import com.android.support.db.SupportSQLiteDatabase;
+import com.android.support.db.SupportSQLiteStatement;
/**
* Base class for all Room databases.
*/
@SuppressWarnings("unused")
-public abstract class RoomDatabase implements SupportDb {
- private ThreadLocal<Map<String, SupportSqliteStatement>> mStatementCache;
- private final SupportDb mDb;
+public abstract class RoomDatabase implements SupportSQLiteDatabase {
+ private final SupportSQLiteDatabase mDb;
- public RoomDatabase(SupportDb supportDb) {
+ public RoomDatabase(SupportSQLiteDatabase supportDb) {
mDb = supportDb;
- mStatementCache = new ThreadLocal<>();
}
@Override
@@ -43,17 +38,22 @@
}
@Override
- public SupportSqliteStatement compileStatement(String sql) {
- Map<String, SupportSqliteStatement> cache = mStatementCache.get();
- if (cache == null) {
- cache = new HashMap<>();
- mStatementCache.set(cache);
- }
- SupportSqliteStatement cached = cache.get(sql);
- if (cached == null) {
- cached = mDb.compileStatement(sql);
- cache.put(sql, cached);
- }
- return cached;
+ public SupportSQLiteStatement compileStatement(String sql) {
+ return mDb.compileStatement(sql);
+ }
+
+ @Override
+ public void beginTransaction() {
+ mDb.beginTransaction();
+ }
+
+ @Override
+ public void endTransaction() {
+ mDb.endTransaction();
+ }
+
+ @Override
+ public void setTransactionSuccessful() {
+ mDb.setTransactionSuccessful();
}
}