Revert "Optimization for storing enums in databases."
This reverts commit ae093dec7bfdc578cf0d7cd2ee6c8563ddd4f5ed.
Reason for revert: Causes undesired type converters to be used in query parameters. b/173130710
Bug: 173130710
Change-Id: I7ad29cb08bcd15c1b67b09bbba6fd746888c8b99
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
index db41d40..8ba6067 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
@@ -134,11 +134,6 @@
fun isType(): Boolean
/**
- * Returns true if this represented by an [Enum].
- */
- fun isEnum(): Boolean
-
- /**
* Returns `true` if this is the same raw type as [other]
*/
fun isTypeOf(other: KClass<*>): Boolean
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
index dc9a6be..de5dc66 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
@@ -25,7 +25,6 @@
import androidx.room.compiler.processing.safeTypeName
import com.google.auto.common.MoreTypes
import com.squareup.javapoet.TypeName
-import javax.lang.model.element.ElementKind
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
import kotlin.reflect.KClass
@@ -139,7 +138,4 @@
private val BOXED_LONG = TypeName.LONG.box()
private val BOXED_BYTE = TypeName.BYTE.box()
}
-
- override fun isEnum() = typeMirror.kind == TypeKind.DECLARED &&
- MoreTypes.asElement(typeMirror).kind == ElementKind.ENUM
}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 5329363..aad772f 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -20,7 +20,6 @@
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XTypeElement
-import com.google.devtools.ksp.symbol.ClassKind
import androidx.room.compiler.processing.tryBox
import androidx.room.compiler.processing.tryUnbox
import com.google.devtools.ksp.symbol.KSClassDeclaration
@@ -152,8 +151,4 @@
override fun toString(): String {
return ksType.toString()
}
-
- override fun isEnum(): Boolean {
- return (ksType.declaration as? KSClassDeclaration)?.classKind == ClassKind.ENUM_CLASS
- }
}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeArgumentType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeArgumentType.kt
index 19ac355..36a3e12 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeArgumentType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeArgumentType.kt
@@ -17,9 +17,9 @@
package androidx.room.compiler.processing.ksp
import androidx.room.compiler.processing.XType
+import com.squareup.javapoet.TypeName
import com.google.devtools.ksp.symbol.KSTypeArgument
import com.google.devtools.ksp.symbol.KSTypeParameter
-import com.squareup.javapoet.TypeName
/**
* The typeName for type arguments requires the type parameter, hence we have a special type
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 f4cf3a5..d79a71c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -16,16 +16,16 @@
package androidx.room.solver
+import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.GuavaBaseTypeNames
+import androidx.room.ext.isEntityElement
+import androidx.room.parser.ParsedQuery
+import androidx.room.parser.SQLTypeAffinity
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.asDeclaredType
import androidx.room.compiler.processing.isArray
import androidx.room.compiler.processing.isDeclared
-import androidx.room.ext.CommonTypeNames
-import androidx.room.ext.GuavaBaseTypeNames
-import androidx.room.ext.isEntityElement
import androidx.room.ext.isNotByte
-import androidx.room.parser.ParsedQuery
-import androidx.room.parser.SQLTypeAffinity
import androidx.room.processor.Context
import androidx.room.processor.EntityProcessor
import androidx.room.processor.FieldProcessor
@@ -86,7 +86,6 @@
import androidx.room.solver.types.CompositeAdapter
import androidx.room.solver.types.CompositeTypeConverter
import androidx.room.solver.types.CursorValueReader
-import androidx.room.solver.types.EnumColumnTypeAdapter
import androidx.room.solver.types.NoOpConverter
import androidx.room.solver.types.PrimitiveBooleanToIntConverter
import androidx.room.solver.types.PrimitiveColumnTypeAdapter
@@ -219,26 +218,13 @@
if (adapter != null) {
return adapter
}
-
- fun findTypeConverterAdapter(): ColumnTypeAdapter? {
- val targetTypes = targetTypeMirrorsFor(affinity)
- val binder = findTypeConverter(input, targetTypes) ?: return null
- // columnAdapter should not be null but we are receiving errors on crash in `first()` so
- // this safeguard allows us to dispatch the real problem to the user (e.g. why we couldn't
- // find the right adapter)
- val columnAdapter = getAllColumnAdapters(binder.to).firstOrNull() ?: return null
- return CompositeAdapter(input, columnAdapter, binder, null)
- }
-
- val adapterByTypeConverter = findTypeConverterAdapter()
- if (adapterByTypeConverter != null) {
- return adapterByTypeConverter
- }
- val enumAdapter = createEnumTypeAdapter(input)
- if (enumAdapter != null) {
- return enumAdapter
- }
- return null
+ val targetTypes = targetTypeMirrorsFor(affinity)
+ val binder = findTypeConverter(input, targetTypes) ?: return null
+ // columnAdapter should not be null but we are receiving errors on crash in `first()` so
+ // this safeguard allows us to dispatch the real problem to the user (e.g. why we couldn't
+ // find the right adapter)
+ val columnAdapter = getAllColumnAdapters(binder.to).firstOrNull() ?: return null
+ return CompositeAdapter(input, columnAdapter, binder, null)
}
/**
@@ -265,28 +251,13 @@
// two way is better
return adapter
}
-
- fun findTypeConverterAdapter(): ColumnTypeAdapter? {
- val targetTypes = targetTypeMirrorsFor(affinity)
- val converter = findTypeConverter(targetTypes, output) ?: return null
- return CompositeAdapter(
- output,
- getAllColumnAdapters(converter.from).first(), null, converter
- )
- }
-
// we could not find a two way version, search for anything
- val typeConverterAdapter = findTypeConverterAdapter()
- if (typeConverterAdapter != null) {
- return typeConverterAdapter
- }
-
- val enumAdapter = createEnumTypeAdapter(output)
- if (enumAdapter != null) {
- return enumAdapter
- }
-
- return null
+ val targetTypes = targetTypeMirrorsFor(affinity)
+ val converter = findTypeConverter(targetTypes, output) ?: return null
+ return CompositeAdapter(
+ output,
+ getAllColumnAdapters(converter.from).first(), null, converter
+ )
}
/**
@@ -322,34 +293,15 @@
if (adapter != null) {
return adapter
}
-
- fun findTypeConverterAdapter(): ColumnTypeAdapter? {
- val targetTypes = targetTypeMirrorsFor(affinity)
- val intoStatement = findTypeConverter(out, targetTypes) ?: return null
- // ok found a converter, try the reverse now
- val fromCursor = reverse(intoStatement) ?: findTypeConverter(intoStatement.to, out)
- ?: return null
- return CompositeAdapter(
- out, getAllColumnAdapters(intoStatement.to).first(), intoStatement, fromCursor
- )
- }
-
- val adapterByTypeConverter = findTypeConverterAdapter()
- if (adapterByTypeConverter != null) {
- return adapterByTypeConverter
- }
- val enumAdapter = createEnumTypeAdapter(out)
- if (enumAdapter != null) {
- return enumAdapter
- }
- return null
- }
-
- private fun createEnumTypeAdapter(type: XType): ColumnTypeAdapter? {
- if (type.isEnum()) {
- return EnumColumnTypeAdapter(type)
- }
- return null
+ val targetTypes = targetTypeMirrorsFor(affinity)
+ val intoStatement = findTypeConverter(out, targetTypes) ?: return null
+ // ok found a converter, try the reverse now
+ val fromCursor = reverse(intoStatement) ?: findTypeConverter(intoStatement.to, out)
+ ?: return null
+ return CompositeAdapter(
+ out, getAllColumnAdapters(intoStatement.to).first(), intoStatement,
+ fromCursor
+ )
}
private fun findDirectAdapterFor(
@@ -561,17 +513,17 @@
if (typeMirror.isType() &&
context.COMMON_TYPES.COLLECTION.rawType.isAssignableFrom(typeMirror)
) {
- val collectionBinder = findStatementValueBinder(typeMirror, null)
- if (collectionBinder != null) {
- // user has a converter for the collection itself
- return BasicQueryParameterAdapter(collectionBinder)
- }
-
val declared = typeMirror.asDeclaredType()
val binder = findStatementValueBinder(
declared.typeArguments.first().extendsBoundOrSelf(), null
- ) ?: return null
- return CollectionQueryParameterAdapter(binder)
+ )
+ if (binder != null) {
+ return CollectionQueryParameterAdapter(binder)
+ } else {
+ // maybe user wants to convert this collection themselves. look for a match
+ val collectionBinder = findStatementValueBinder(typeMirror, null) ?: return null
+ return BasicQueryParameterAdapter(collectionBinder)
+ }
} else if (typeMirror.isArray() && typeMirror.componentType.isNotByte()) {
val component = typeMirror.componentType
val binder = findStatementValueBinder(component, null) ?: return null
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt
deleted file mode 100644
index 1194b1d..0000000
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/EnumColumnTypeAdapter.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 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.types
-
-import androidx.room.compiler.processing.XType
-import androidx.room.ext.L
-import androidx.room.ext.T
-import androidx.room.parser.SQLTypeAffinity.TEXT
-import androidx.room.solver.CodeGenScope
-
-/**
- * Uses enum string representation.
- */
-class EnumColumnTypeAdapter(out: XType) :
- ColumnTypeAdapter(out, TEXT) {
- private val enumTypeName = out.typeName
- override fun readFromCursor(
- outVarName: String,
- cursorVarName: String,
- indexVarName: String,
- scope: CodeGenScope
- ) {
- scope.builder()
- .addStatement(
- "$L = $T.valueOf($L.getString($L))", outVarName, enumTypeName,
- cursorVarName,
- indexVarName
- )
- }
-
- override fun bindToStmt(
- stmtName: String,
- indexVarName: String,
- valueVarName: String,
- scope: CodeGenScope
- ) {
- scope.builder().apply {
- beginControlFlow("if ($L == null)", valueVarName)
- .addStatement("$L.bindNull($L)", stmtName, indexVarName)
- nextControlFlow("else")
- .addStatement("$L.bindString($L, $L.name())", stmtName, indexVarName, valueVarName)
- endControlFlow()
- }
- }
-}
\ No newline at end of file
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
index 1f1d6cb..085b391 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
@@ -50,24 +50,6 @@
}
@Test
- fun testUnusedEnumCompilesWithoutError() {
- singleDao(
- """
- @Dao abstract class MyDao {
- @Query("SELECT uid FROM User")
- abstract int[] getIds();
- enum Fruit {
- APPLE,
- BANANA,
- STRAWBERRY
- }
- }
- """
- ) { _, _ ->
- }.compilesWithoutError()
- }
-
- @Test
fun testNonAbstract() {
singleDao("@Dao public class MyDao {}") { _, _ -> }
.failsToCompile()
diff --git a/room/compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt b/room/compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
index 3d437fc..e520c12 100644
--- a/room/compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
@@ -20,8 +20,6 @@
import androidx.paging.DataSource
import androidx.paging.PagingSource
import androidx.room.Entity
-import androidx.room.compiler.processing.XProcessingEnv
-import androidx.room.compiler.processing.asDeclaredType
import androidx.room.ext.GuavaUtilConcurrentTypeNames
import androidx.room.ext.L
import androidx.room.ext.LifecyclesTypeNames
@@ -32,6 +30,8 @@
import androidx.room.ext.RxJava3TypeNames
import androidx.room.ext.T
import androidx.room.parser.SQLTypeAffinity
+import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.asDeclaredType
import androidx.room.processor.Context
import androidx.room.processor.ProcessorErrors
import androidx.room.solver.binderprovider.DataSourceFactoryQueryResultBinderProvider
@@ -44,7 +44,6 @@
import androidx.room.solver.shortcut.binderprovider.RxCallableDeleteOrUpdateMethodBinderProvider
import androidx.room.solver.shortcut.binderprovider.RxCallableInsertMethodBinderProvider
import androidx.room.solver.types.CompositeAdapter
-import androidx.room.solver.types.EnumColumnTypeAdapter
import androidx.room.solver.types.TypeConverter
import androidx.room.testing.TestInvocation
import androidx.room.testing.TestProcessor
@@ -104,30 +103,6 @@
}
@Test
- fun testJavaLangEnumCompilesWithoutError() {
- simpleRun(
- JavaFileObjects.forSourceString(
- "foo.bar.Fruit",
- """ package foo.bar;
- import androidx.room.*;
- enum Fruit {
- APPLE,
- BANANA,
- STRAWBERRY}
- """.trimMargin()
- )
- ) { invocation ->
- val store = TypeAdapterStore.create(Context(invocation.processingEnv))
- val enum = invocation
- .processingEnv
- .requireType("foo.bar.Fruit")
- val adapter = store.findColumnTypeAdapter(enum, null)
- assertThat(adapter, notNullValue())
- assertThat(adapter, instanceOf(EnumColumnTypeAdapter::class.java))
- }.compilesWithoutError()
- }
-
- @Test
fun testVia1TypeAdapter() {
singleRun { invocation ->
val store = TypeAdapterStore.create(Context(invocation.processingEnv))
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EnumColumnTypeAdapterTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EnumColumnTypeAdapterTest.java
deleted file mode 100644
index 4c0df94..0000000
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/EnumColumnTypeAdapterTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.integration.testapp.test;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import android.content.Context;
-
-import androidx.room.Dao;
-import androidx.room.Database;
-import androidx.room.Entity;
-import androidx.room.PrimaryKey;
-import androidx.room.Query;
-import androidx.room.Room;
-import androidx.room.RoomDatabase;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class EnumColumnTypeAdapterTest {
-
- private EnumColumnTypeAdapterDatabase mDb;
-
- @Entity
- public static class EntityWithEnum {
- @PrimaryKey
- public Long id;
- public Fruit fruit;
- }
-
- public enum Fruit {
- BANANA,
- STRAWBERRY,
- WILDBERRY
- }
-
- @Dao
- public interface SampleDao {
- @Query("INSERT INTO EntityWithEnum (id, fruit) VALUES (:id, :fruit)")
- long insert(long id, Fruit fruit);
-
- @Query("SELECT * FROM EntityWithEnum WHERE id = :id")
- EntityWithEnum getValueWithId(long id);
- }
-
- @Database(entities = {EntityWithEnum.class}, version = 1, exportSchema = false)
- public abstract static class EnumColumnTypeAdapterDatabase extends RoomDatabase {
- public abstract EnumColumnTypeAdapterTest.SampleDao dao();
- }
-
- @Before
- public void initDb() {
- Context context = ApplicationProvider.getApplicationContext();
- mDb = Room.inMemoryDatabaseBuilder(
- context,
- EnumColumnTypeAdapterDatabase.class)
- .build();
- }
-
- @Test
- public void readAndWriteEnumToDatabase() {
- final long id1 = mDb.dao().insert(1, Fruit.BANANA);
- final long id2 = mDb.dao().insert(2, Fruit.STRAWBERRY);
-
- assertThat(mDb.dao().getValueWithId(1).fruit, is(equalTo(Fruit.BANANA)));
- assertThat(mDb.dao().getValueWithId(2).fruit, is(equalTo(Fruit.STRAWBERRY)));
- }
-}