Added ImmutableList as a possible return collection type for room
Bug:146107232
Test: unit test passes, also exported to my app and played with it a bit.
Change-Id: If4f349450823a7a475c05698ba91c631494b6d73
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index f528444..c652658 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -54,6 +54,7 @@
import androidx.room.solver.query.result.ArrayQueryResultAdapter
import androidx.room.solver.query.result.EntityRowAdapter
import androidx.room.solver.query.result.GuavaOptionalQueryResultAdapter
+import androidx.room.solver.query.result.ImmutableListQueryResultAdapter
import androidx.room.solver.query.result.InstantQueryResultBinder
import androidx.room.solver.query.result.ListQueryResultAdapter
import androidx.room.solver.query.result.OptionalQueryResultAdapter
@@ -98,6 +99,7 @@
import com.google.auto.common.MoreElements
import com.google.auto.common.MoreTypes
import com.google.common.annotations.VisibleForTesting
+import com.google.common.collect.ImmutableList
import java.util.LinkedList
import javax.lang.model.type.ArrayType
import javax.lang.model.type.TypeKind
@@ -409,6 +411,10 @@
val typeArg = declared.typeArguments.first()
val rowAdapter = findRowAdapter(typeArg, query) ?: return null
return OptionalQueryResultAdapter(SingleEntityQueryResultAdapter(rowAdapter))
+ } else if (MoreTypes.isTypeOf(ImmutableList::class.java, typeMirror)) {
+ val typeArg = declared.typeArguments.first().extendsBoundOrSelf()
+ val rowAdapter = findRowAdapter(typeArg, query) ?: return null
+ return ImmutableListQueryResultAdapter(rowAdapter)
} else if (MoreTypes.isTypeOf(java.util.List::class.java, typeMirror)) {
val typeArg = declared.typeArguments.first().extendsBoundOrSelf()
val rowAdapter = findRowAdapter(typeArg, query) ?: return null
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/ImmutableListQueryResultAdapter.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/ImmutableListQueryResultAdapter.kt
new file mode 100644
index 0000000..33dd5ab
--- /dev/null
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/ImmutableListQueryResultAdapter.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 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.solver.query.result
+
+import androidx.room.ext.L
+import androidx.room.ext.T
+import androidx.room.ext.typeName
+import androidx.room.solver.CodeGenScope
+import com.google.common.collect.ImmutableList
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
+
+class ImmutableListQueryResultAdapter(rowAdapter: RowAdapter) : QueryResultAdapter(rowAdapter) {
+ val type = rowAdapter.out
+ override fun convert(outVarName: String, cursorVarName: String, scope: CodeGenScope) {
+ scope.builder().apply {
+ rowAdapter?.onCursorReady(cursorVarName, scope)
+ val collectionType = ParameterizedTypeName
+ .get(ClassName.get(ImmutableList::class.java), type.typeName())
+ val immutableListBuilderType = ParameterizedTypeName
+ .get(ClassName.get(ImmutableList.Builder::class.java), type.typeName())
+ val immutableListBuilderName = scope.getTmpVar("_immutableListBuilder")
+ addStatement("final $T $L = $T.<$T>builder()",
+ immutableListBuilderType, immutableListBuilderName,
+ ClassName.get(ImmutableList::class.java), type.typeName())
+ val tmpVarName = scope.getTmpVar("_item")
+ beginControlFlow("while($L.moveToNext())", cursorVarName).apply {
+ addStatement("final $T $L", type.typeName(), tmpVarName)
+ rowAdapter?.convert(tmpVarName, cursorVarName, scope)
+ addStatement("$L.add($L)", immutableListBuilderName, tmpVarName)
+ }
+ endControlFlow()
+ addStatement("final $T $L = $L.build()",
+ collectionType, outVarName, immutableListBuilderName)
+ rowAdapter?.onCursorFinished()?.invoke(scope)
+ }
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt b/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
index 09a37e8..2b8ba75 100644
--- a/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
@@ -44,6 +44,7 @@
package foo.bar;
import androidx.room.*;
import java.util.*;
+ import com.google.common.collect.ImmutableList;
@Dao
abstract class MyClass {
"""
@@ -174,6 +175,18 @@
}
@Test
+ fun aLongAndIntegerImmutableList() {
+ singleQueryMethod("""
+ @Query("SELECT id FROM users WHERE id IN(:ids) AND age > :time")
+ abstract ImmutableList<Integer> selectAllIds(long time, List<Integer> ids);
+ """) { writer ->
+ val scope = testCodeGenScope()
+ writer.prepareReadAndBind("_sql", "_stmt", scope)
+ assertThat(scope.generate().toString().trim(), `is`(collectionOut))
+ }.compilesWithoutError()
+ }
+
+ @Test
fun aLongAndIntegerSet() {
singleQueryMethod("""
@Query("SELECT id FROM users WHERE id IN(:ids) AND age > :time")
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/BlobEntityDao.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/BlobEntityDao.java
index 3c582fd..205699a 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/BlobEntityDao.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/BlobEntityDao.java
@@ -21,6 +21,8 @@
import androidx.room.Query;
import androidx.room.integration.testapp.vo.BlobEntity;
+import com.google.common.collect.ImmutableList;
+
import java.util.List;
@Dao
@@ -32,6 +34,9 @@
@Query("SELECT * FROM BlobEntity")
List<BlobEntity> selectAll();
+ @Query("SELECT * FROM BlobEntity")
+ ImmutableList<BlobEntity> selectAllImmutable();
+
@Query("SELECT content FROM BlobEntity WHERE id = :id")
byte[] getContent(long id);
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/SimpleEntityReadWriteTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/SimpleEntityReadWriteTest.java
index fa94e6b..8530604 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/SimpleEntityReadWriteTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/SimpleEntityReadWriteTest.java
@@ -55,6 +55,7 @@
import androidx.test.filters.SmallTest;
import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
@@ -493,11 +494,24 @@
mBlobEntityDao.insert(b);
List<BlobEntity> list = mBlobEntityDao.selectAll();
assertThat(list, hasSize(2));
+ ImmutableList<BlobEntity> immutableList = mBlobEntityDao.selectAllImmutable();
+ assertThat(immutableList, hasSize(2));
mBlobEntityDao.updateContent(2, "ghi".getBytes(Charsets.UTF_8));
assertThat(mBlobEntityDao.getContent(2), is(equalTo("ghi".getBytes(Charsets.UTF_8))));
}
@Test
+ public void blobImmutable() {
+ BlobEntity a = new BlobEntity(1, "abc".getBytes(Charsets.UTF_8));
+ BlobEntity b = new BlobEntity(2, "def".getBytes(Charsets.UTF_8));
+ mBlobEntityDao.insert(a);
+ mBlobEntityDao.insert(b);
+ ImmutableList<BlobEntity> immutableList = mBlobEntityDao.selectAllImmutable();
+ assertThat(immutableList, hasSize(2));
+ assertThat(immutableList.get(1).content, is(equalTo("def".getBytes(Charsets.UTF_8))));
+ }
+
+ @Test
public void transactionByRunnable() {
User a = TestUtil.createUser(3);
User b = TestUtil.createUser(5);