Merge "Removing usages of $S, $T, $N, $L, $W and `toJavaPoet()` across all files in Room." into androidx-main
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XFunSpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XFunSpec.kt
index 56cc91c..3a1a2ec 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XFunSpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XFunSpec.kt
@@ -36,7 +36,9 @@
 
         val name: String
 
-        fun addAnnotation(annotation: XAnnotationSpec)
+        fun addAnnotation(annotation: XAnnotationSpec): Builder
+
+        fun addAbstractModifier(): Builder
 
         // TODO(b/247247442): Maybe make a XParameterSpec ?
         fun addParameter(
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XPropertySpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XPropertySpec.kt
index a66f12e..50ecd53 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XPropertySpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XPropertySpec.kt
@@ -90,11 +90,4 @@
             }
         }
     }
-}
-
-// TODO(b/127483380): Temporary API for XPoet migration.
-// @Deprecated("Temporary API for XPoet migration.")
-fun XPropertySpec.toJavaPoet(): FieldSpec {
-    check(this is JavaPropertySpec)
-    return this.actual
 }
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XTypeSpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XTypeSpec.kt
index c4608e9..344481a 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XTypeSpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/XTypeSpec.kt
@@ -22,6 +22,7 @@
 import androidx.room.compiler.codegen.kotlin.KotlinTypeSpec
 import androidx.room.compiler.processing.XElement
 import androidx.room.compiler.processing.addOriginatingElement
+import com.squareup.kotlinpoet.KModifier
 import com.squareup.kotlinpoet.javapoet.JTypeSpec
 import com.squareup.kotlinpoet.javapoet.KTypeSpec
 import javax.lang.model.element.Modifier
@@ -39,6 +40,7 @@
         fun addType(typeSpec: XTypeSpec): Builder
         fun setPrimaryConstructor(functionSpec: XFunSpec): Builder
         fun setVisibility(visibility: VisibilityModifier)
+        fun addAbstractModifier(): Builder
         fun build(): XTypeSpec
 
         companion object {
@@ -89,16 +91,28 @@
     }
 
     companion object {
-        fun classBuilder(language: CodeLanguage, className: XClassName): Builder {
+        fun classBuilder(
+            language: CodeLanguage,
+            className: XClassName,
+            isOpen: Boolean = false
+        ): Builder {
             return when (language) {
                 CodeLanguage.JAVA -> JavaTypeSpec.Builder(
                     className = className,
-                    actual = JTypeSpec.classBuilder(className.java)
-                        .addModifiers(Modifier.FINAL)
+                    actual = JTypeSpec.classBuilder(className.java).apply {
+                        if (!isOpen) {
+                            addModifiers(Modifier.FINAL)
+                        }
+                    }
                 )
+
                 CodeLanguage.KOTLIN -> KotlinTypeSpec.Builder(
                     className = className,
-                    actual = KTypeSpec.classBuilder(className.kotlin)
+                    actual = KTypeSpec.classBuilder(className.kotlin).apply {
+                        if (isOpen) {
+                            addModifiers(KModifier.OPEN)
+                        }
+                    }
                 )
             }
         }
@@ -148,11 +162,4 @@
             }
         }
     }
-}
-
-// TODO(b/127483380): Temporary API for XPoet migration.
-// @Deprecated("Temporary API for XPoet migration.")
-fun XTypeSpec.toJavaPoet(): JTypeSpec {
-    check(this is JavaTypeSpec)
-    return this.actual
 }
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaFunSpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaFunSpec.kt
index 1774512e..453ad85 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaFunSpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaFunSpec.kt
@@ -33,17 +33,22 @@
     override val name: String,
     internal val actual: MethodSpec
 ) : JavaLang(), XFunSpec {
+    override fun toString() = actual.toString()
 
     internal class Builder(
         override val name: String,
         internal val actual: MethodSpec.Builder
     ) : JavaLang(), XFunSpec.Builder {
 
-        override fun addAnnotation(annotation: XAnnotationSpec) {
+        override fun addAnnotation(annotation: XAnnotationSpec) = apply {
             require(annotation is JavaAnnotationSpec)
             actual.addAnnotation(annotation.actual)
         }
 
+        override fun addAbstractModifier() = apply {
+            actual.addModifiers(Modifier.ABSTRACT)
+        }
+
         override fun addCode(code: XCodeBlock) = apply {
             require(code is JavaCodeBlock)
             actual.addCode(code.actual)
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaTypeSpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaTypeSpec.kt
index 8a50dae..37d576c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaTypeSpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/java/JavaTypeSpec.kt
@@ -25,11 +25,13 @@
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.XTypeSpec
 import com.squareup.kotlinpoet.javapoet.JTypeSpec
+import javax.lang.model.element.Modifier
 
 internal class JavaTypeSpec(
     private val _className: XClassName?,
     internal val actual: JTypeSpec
 ) : JavaLang(), XTypeSpec {
+    override fun toString() = actual.toString()
 
     override val className: XClassName
         get() {
@@ -78,5 +80,9 @@
         override fun build(): XTypeSpec {
             return JavaTypeSpec(className, actual.build())
         }
+
+        override fun addAbstractModifier(): XTypeSpec.Builder = apply {
+            actual.addModifiers(Modifier.ABSTRACT)
+        }
     }
 }
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinFunSpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinFunSpec.kt
index 68b015a..1a3c0c4 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinFunSpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinFunSpec.kt
@@ -29,17 +29,22 @@
     override val name: String,
     internal val actual: FunSpec
 ) : KotlinLang(), XFunSpec {
+    override fun toString() = actual.toString()
 
     internal class Builder(
         override val name: String,
         internal val actual: FunSpec.Builder
     ) : KotlinLang(), XFunSpec.Builder {
 
-        override fun addAnnotation(annotation: XAnnotationSpec) {
+        override fun addAnnotation(annotation: XAnnotationSpec) = apply {
             require(annotation is KotlinAnnotationSpec)
             actual.addAnnotation(annotation.actual)
         }
 
+        override fun addAbstractModifier() = apply {
+            actual.addModifiers(KModifier.ABSTRACT)
+        }
+
         override fun addCode(code: XCodeBlock) = apply {
             require(code is KotlinCodeBlock)
             actual.addCode(code.actual)
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinTypeSpec.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinTypeSpec.kt
index 3151ff0..a819dd9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinTypeSpec.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/codegen/kotlin/KotlinTypeSpec.kt
@@ -24,12 +24,14 @@
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.XTypeSpec
+import com.squareup.kotlinpoet.KModifier
 import com.squareup.kotlinpoet.javapoet.KTypeSpec
 
 internal class KotlinTypeSpec(
     private val _className: XClassName?,
     internal val actual: KTypeSpec
 ) : KotlinLang(), XTypeSpec {
+    override fun toString() = actual.toString()
 
     override val className: XClassName
         get() {
@@ -81,6 +83,10 @@
             actual.addModifiers(visibility.toKotlinVisibilityModifier())
         }
 
+        override fun addAbstractModifier(): XTypeSpec.Builder = apply {
+            actual.addModifiers(KModifier.ABSTRACT)
+        }
+
         override fun build(): XTypeSpec {
             return KotlinTypeSpec(className, actual.build())
         }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt b/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
index 0ff01df..b6158fa 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/ext/xpoet_ext.kt
@@ -33,12 +33,6 @@
 import java.util.concurrent.Callable
 import kotlin.reflect.KClass
 
-val L = "\$L"
-val T = "\$T"
-val N = "\$N"
-val S = "\$S"
-val W = "\$W"
-
 val KClass<*>.typeName: ClassName
     get() = ClassName.get(this.java)
 val KClass<*>.arrayTypeName: ArrayTypeName
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/TypeWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/TypeWriter.kt
index 7249aa7..2e46c6e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/TypeWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/TypeWriter.kt
@@ -26,7 +26,6 @@
 import androidx.room.compiler.codegen.XTypeSpec.Builder.Companion.apply
 import androidx.room.compiler.processing.XProcessingEnv
 import androidx.room.compiler.processing.writeTo
-import androidx.room.ext.S
 import androidx.room.solver.CodeGenScope
 import com.squareup.kotlinpoet.javapoet.JAnnotationSpec
 import com.squareup.kotlinpoet.javapoet.JClassName
@@ -82,7 +81,7 @@
             javaTypeBuilder = {
                 addAnnotation(
                     com.squareup.javapoet.AnnotationSpec.builder(SuppressWarnings::class.java)
-                        .addMember("value", "{$S, $S}", "unchecked", "deprecation")
+                        .addMember("value", "{\$S, \$S}", "unchecked", "deprecation")
                         .build()
                 )
             },
@@ -107,7 +106,7 @@
                 javaTypeBuilder = {
                     addAnnotation(
                         JAnnotationSpec.builder(JClassName.bestGuess(annotationName))
-                            .addMember("value", "$S", memberValue)
+                            .addMember("value", "\$S", memberValue)
                             .build()
                     )
                 },
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt
index aa449e9..4b9437c 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/CustomConverterProcessorTest.kt
@@ -17,11 +17,22 @@
 package androidx.room.processor
 
 import androidx.room.TypeConverter
-import androidx.room.compiler.codegen.toJavaPoet
+import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.VisibilityModifier
+import androidx.room.compiler.codegen.XAnnotationSpec
+import androidx.room.compiler.codegen.XClassName
+import androidx.room.compiler.codegen.XFunSpec
+import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.addStatement
+import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.codegen.XTypeSpec
+import androidx.room.compiler.codegen.XTypeSpec.Builder.Companion.apply
+import androidx.room.compiler.codegen.asClassName
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
 import androidx.room.compiler.processing.util.runProcessorTest
-import androidx.room.ext.typeName
+import androidx.room.ext.CommonTypeNames
+import androidx.room.ext.CommonTypeNames.MUTABLE_LIST
+import androidx.room.ext.CommonTypeNames.STRING
 import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_EMPTY_CLASS
 import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
 import androidx.room.processor.ProcessorErrors.TYPE_CONVERTER_MUST_BE_PUBLIC
@@ -29,26 +40,18 @@
 import androidx.room.testing.context
 import androidx.room.vo.CustomTypeConverter
 import com.google.common.truth.Truth.assertThat
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.MethodSpec
-import com.squareup.javapoet.ParameterSpec
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-import com.squareup.javapoet.TypeSpec
 import com.squareup.javapoet.TypeVariableName
 import java.util.Date
-import javax.lang.model.element.Modifier
-import org.hamcrest.CoreMatchers.`is`
-import org.hamcrest.MatcherAssert.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
 class CustomConverterProcessorTest {
+
     companion object {
-        val CONVERTER = ClassName.get("foo.bar", "MyConverter")!!
-        val CONVERTER_QNAME = CONVERTER.packageName() + "." + CONVERTER.simpleName()
+        val CONVERTER = XClassName.get("foo.bar", "MyConverter")
+        val CONVERTER_NAME = CONVERTER.canonicalName
         val CONTAINER = Source.java(
             "foo.bar.Container",
             """
@@ -62,53 +65,76 @@
 
     @Test
     fun validCase() {
-        singleClass(createConverter(TypeName.SHORT.box(), TypeName.CHAR.box())) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.SHORT.box()))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.CHAR.box()))
+        singleClass(
+            createConverter(
+                XTypeName.BOXED_SHORT.copy(nullable = true),
+                XTypeName.BOXED_CHAR.copy(nullable = true)
+            )
+        ) {
+                converter, _ ->
+            assertThat(converter?.fromTypeName).isEqualTo(
+                XTypeName.BOXED_SHORT.copy(nullable = true)
+            )
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.BOXED_CHAR.copy(nullable = true))
         }
     }
 
     @Test
     fun primitiveFrom() {
-        singleClass(createConverter(TypeName.SHORT, TypeName.CHAR.box())) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.SHORT))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.CHAR.box()))
+        singleClass(
+            createConverter(
+                XTypeName.PRIMITIVE_SHORT,
+                XTypeName.BOXED_CHAR.copy(nullable = true)
+            )
+        ) {
+                converter, _ ->
+            assertThat(converter?.fromTypeName).isEqualTo(XTypeName.PRIMITIVE_SHORT)
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.BOXED_CHAR.copy(nullable = true))
         }
     }
 
     @Test
     fun primitiveTo() {
-        singleClass(createConverter(TypeName.INT.box(), TypeName.DOUBLE)) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.INT.box()))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.DOUBLE))
+        singleClass(
+            createConverter(
+                XTypeName.BOXED_INT.copy(nullable = true),
+                XTypeName.PRIMITIVE_DOUBLE)
+        ) {
+                converter, _ ->
+            assertThat(converter?.fromTypeName).isEqualTo(XTypeName.BOXED_INT.copy(nullable = true))
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.PRIMITIVE_DOUBLE)
         }
     }
 
     @Test
     fun primitiveBoth() {
-        singleClass(createConverter(TypeName.INT, TypeName.DOUBLE)) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.INT))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.DOUBLE))
+        singleClass(createConverter(XTypeName.PRIMITIVE_INT, XTypeName.PRIMITIVE_DOUBLE)) {
+                converter, _ ->
+            assertThat(converter?.fromTypeName).isEqualTo(XTypeName.PRIMITIVE_INT)
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.PRIMITIVE_DOUBLE)
         }
     }
 
     @Test
     fun nonNullButNotBoxed() {
-        val string = String::class.typeName
-        val date = Date::class.typeName
-        singleClass(createConverter(string, date)) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(string as TypeName))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(date as TypeName))
+        val date = Date::class.asClassName()
+        singleClass(createConverter(STRING, date)) { converter, _ ->
+            assertThat(converter?.fromTypeName).isEqualTo(STRING)
+            assertThat(converter?.toTypeName).isEqualTo(date)
         }
     }
 
     @Test
     fun parametrizedTypeUnbound() {
         val typeVarT = TypeVariableName.get("T")
-        val list = ParameterizedTypeName.get(List::class.typeName, typeVarT)
+        val list = CommonTypeNames.MUTABLE_LIST.parametrizedBy(XClassName.get("", "T"))
         val typeVarK = TypeVariableName.get("K")
-        val map = ParameterizedTypeName.get(Map::class.typeName, typeVarK, typeVarT)
-        singleClass(createConverter(list, map, listOf(typeVarK, typeVarT))) { _, invocation ->
+        val map = CommonTypeNames.MUTABLE_MAP.parametrizedBy(
+            XClassName.get("", "K"),
+            XClassName.get("", "T")
+        )
+        singleClass(createConverter(list, map, listOf(typeVarK, typeVarT))) {
+                _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(TYPE_CONVERTER_UNBOUND_GENERIC)
             }
@@ -117,13 +143,12 @@
 
     @Test
     fun parametrizedTypeSpecific() {
-        val string = String::class.typeName
-        val date = Date::class.typeName
-        val list = ParameterizedTypeName.get(List::class.typeName, string)
-        val map = ParameterizedTypeName.get(Map::class.typeName, string, date)
+        val date = Date::class.asClassName()
+        val list = CommonTypeNames.MUTABLE_LIST.parametrizedBy(STRING)
+        val map = CommonTypeNames.MUTABLE_MAP.parametrizedBy(STRING, date)
         singleClass(createConverter(list, map)) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(list as TypeName))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(map as TypeName))
+            assertThat(converter?.fromTypeName).isEqualTo(list)
+            assertThat(converter?.toTypeName).isEqualTo(map)
         }
     }
 
@@ -131,10 +156,10 @@
     fun testNoConverters() {
         singleClass(
             Source.java(
-                CONVERTER_QNAME,
+                CONVERTER_NAME,
                 """
-                package ${CONVERTER.packageName()};
-                public class ${CONVERTER.simpleName()} {
+                package ${CONVERTER.packageName};
+                public class ${CONVERTER.simpleNames.first()} {
                 }
                 """
             )
@@ -149,13 +174,13 @@
     fun checkNoArgConstructor() {
         singleClass(
             Source.java(
-                CONVERTER_QNAME,
+                CONVERTER_NAME,
                 """
-                package ${CONVERTER.packageName()};
+                package ${CONVERTER.packageName};
                 import androidx.room.TypeConverter;
 
-                public class ${CONVERTER.simpleName()} {
-                    public ${CONVERTER.simpleName()}(int x) {}
+                public class ${CONVERTER.simpleNames.first()} {
+                    public ${CONVERTER.simpleNames.first()}(int x) {}
                     @TypeConverter
                     public int x(short y) {return 0;}
                 }
@@ -172,22 +197,22 @@
     fun checkNoArgConstructor_withStatic() {
         singleClass(
             Source.java(
-                CONVERTER_QNAME,
+                CONVERTER_NAME,
                 """
-                package ${CONVERTER.packageName()};
+                package ${CONVERTER.packageName};
                 import androidx.room.TypeConverter;
 
-                public class ${CONVERTER.simpleName()} {
-                    public ${CONVERTER.simpleName()}(int x) {}
+                public class ${CONVERTER.simpleNames.first()} {
+                    public ${CONVERTER.simpleNames.first()}(int x) {}
                     @TypeConverter
                     public static int x(short y) {return 0;}
                 }
                 """
             )
         ) { converter, _ ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.SHORT))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.INT))
-            assertThat(converter?.isStatic, `is`(true))
+            assertThat(converter?.fromTypeName).isEqualTo(XTypeName.PRIMITIVE_SHORT)
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.PRIMITIVE_INT)
+            assertThat(converter?.isStatic).isTrue()
         }
     }
 
@@ -195,21 +220,21 @@
     fun checkPublic() {
         singleClass(
             Source.java(
-                CONVERTER_QNAME,
+                CONVERTER_NAME,
                 """
-                package ${CONVERTER.packageName()};
+                package ${CONVERTER.packageName};
                 import androidx.room.TypeConverter;
 
-                public class ${CONVERTER.simpleName()} {
+                public class ${CONVERTER.simpleNames.first()} {
                     @TypeConverter static int x(short y) {return 0;}
                     @TypeConverter private static int y(boolean y) {return 0;}
                 }
                 """
             )
         ) { converter, invocation ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.SHORT))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.INT))
-            assertThat(converter?.isStatic, `is`(true))
+            assertThat(converter?.fromTypeName).isEqualTo(XTypeName.PRIMITIVE_SHORT)
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.PRIMITIVE_INT)
+            assertThat(converter?.isStatic).isTrue()
             invocation.assertCompilationResult {
                 hasErrorContaining(TYPE_CONVERTER_MUST_BE_PUBLIC)
                 hasErrorCount(2)
@@ -217,51 +242,47 @@
         }
     }
 
-    @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
     @Test
     fun parametrizedTypeBoundViaParent() {
         val typeVarT = TypeVariableName.get("T")
-        val list = ParameterizedTypeName.get(List::class.typeName, typeVarT)
+        val list = CommonTypeNames.MUTABLE_LIST.parametrizedBy(XClassName.get("", "T"))
         val typeVarK = TypeVariableName.get("K")
-        val map = ParameterizedTypeName.get(Map::class.typeName, typeVarK, typeVarT)
-
-        val baseConverter = createConverter(list, map, listOf(typeVarT, typeVarK))
-        val extendingQName = "foo.bar.Extending"
+        val map = CommonTypeNames.MUTABLE_MAP.parametrizedBy(
+            XClassName.get("", "K"),
+            XClassName.get("", "T")
+        )
+        val baseConverter = createConverter(
+            list,
+            map,
+            typeVariables = listOf(typeVarT, typeVarK)
+        )
+        val extendingClassName = XClassName.get("foo.bar", "Extending")
         val extendingClass = Source.java(
-            extendingQName,
+            extendingClassName.canonicalName,
             "package foo.bar;\n" +
-                TypeSpec.classBuilder(ClassName.bestGuess(extendingQName)).apply {
+                XTypeSpec.classBuilder(
+                    CodeLanguage.JAVA,
+                    extendingClassName
+                ).apply {
                     superclass(
-                        ParameterizedTypeName.get(
-                            CONVERTER, String::class.typeName,
-                            Integer::class.typeName
+                        CONVERTER.parametrizedBy(
+                            STRING,
+                            XTypeName.BOXED_INT
                         )
                     )
                 }.build().toString()
         )
-
         runProcessorTest(
             sources = listOf(baseConverter, extendingClass)
         ) { invocation ->
-            val element = invocation.processingEnv.requireTypeElement(extendingQName)
+            val element = invocation.processingEnv.requireTypeElement(
+                extendingClassName.canonicalName
+            )
             val converter = CustomConverterProcessor(invocation.context, element)
                 .process().firstOrNull()
-            assertThat(
-                converter?.fromTypeName?.toJavaPoet(),
-                `is`(
-                    ParameterizedTypeName.get(
-                        List::class.typeName, String::class.typeName
-                    ) as TypeName
-                )
-            )
-            assertThat(
-                converter?.toTypeName?.toJavaPoet(),
-                `is`(
-                    ParameterizedTypeName.get(
-                        Map::class.typeName,
-                        Integer::class.typeName, String::class.typeName
-                    ) as TypeName
-                )
+            assertThat(converter?.fromTypeName).isEqualTo(MUTABLE_LIST.parametrizedBy(STRING))
+            assertThat(converter?.toTypeName).isEqualTo(
+                CommonTypeNames.MUTABLE_MAP.parametrizedBy(XTypeName.BOXED_INT, STRING)
             )
         }
     }
@@ -269,10 +290,16 @@
     @Test
     fun checkDuplicates() {
         singleClass(
-            createConverter(TypeName.SHORT.box(), TypeName.CHAR.box(), duplicate = true)
+            createConverter(
+                XTypeName.BOXED_SHORT.copy(nullable = true),
+                XTypeName.BOXED_CHAR.copy(nullable = true),
+                duplicate = true
+            )
         ) { converter, invocation ->
-            assertThat(converter?.fromTypeName?.toJavaPoet(), `is`(TypeName.SHORT.box()))
-            assertThat(converter?.toTypeName?.toJavaPoet(), `is`(TypeName.CHAR.box()))
+            assertThat(converter?.fromTypeName).isEqualTo(
+                XTypeName.BOXED_SHORT.copy(nullable = true)
+            )
+            assertThat(converter?.toTypeName).isEqualTo(XTypeName.BOXED_CHAR.copy(nullable = true))
             invocation.assertCompilationResult {
                 hasErrorContaining("Multiple methods define the same conversion")
             }
@@ -284,9 +311,9 @@
         val source = Source.kotlin(
             "MyConverter.kt",
             """
-        package ${CONVERTER.packageName()}
+        package ${CONVERTER.packageName}
         import androidx.room.*
-        class ${CONVERTER.simpleName()} {
+        class ${CONVERTER.simpleNames.first()} {
             @TypeConverter
             fun nonNulls(input: Int): String {
                 TODO()
@@ -345,33 +372,45 @@
     }
 
     private fun createConverter(
-        from: TypeName,
-        to: TypeName,
+        from: XTypeName,
+        to: XTypeName,
         typeVariables: List<TypeVariableName> = emptyList(),
         duplicate: Boolean = false
     ): Source {
-        val code = TypeSpec.classBuilder(CONVERTER).apply {
-            addTypeVariables(typeVariables)
-            addModifiers(Modifier.PUBLIC)
-            fun buildMethod(name: String) = MethodSpec.methodBuilder(name).apply {
-                addAnnotation(TypeConverter::class.java)
-                addModifiers(Modifier.PUBLIC)
+        val code = XTypeSpec.classBuilder(CodeLanguage.JAVA, CONVERTER, isOpen = true).apply {
+            setVisibility(VisibilityModifier.PUBLIC)
+            fun buildMethod(name: String) = XFunSpec.builder(
+                CodeLanguage.JAVA,
+                name,
+                VisibilityModifier.PUBLIC
+            ).apply {
+                addAnnotation(
+                    XAnnotationSpec.builder(
+                        CodeLanguage.JAVA,
+                        TypeConverter::class.asClassName()
+                    ).build()
+                )
                 returns(to)
-                addParameter(ParameterSpec.builder(from, "input").build())
+                addParameter(from, "input")
                 if (to.isPrimitive) {
                     addStatement("return 0")
                 } else {
                     addStatement("return null")
                 }
             }.build()
-            addMethod(buildMethod("convertF"))
+            addFunction(buildMethod("convertF"))
             if (duplicate) {
-                addMethod(buildMethod("convertF2"))
+                addFunction(buildMethod("convertF2"))
             }
-        }.build().toString()
+        }.apply(
+            javaTypeBuilder = {
+                addTypeVariables(typeVariables)
+            },
+            kotlinTypeBuilder = { error("Test converter shouldn't be generated in Kotlin") }
+        ).build().toString()
         return Source.java(
-            CONVERTER.toString(),
-            "package ${CONVERTER.packageName()};\n$code"
+            CONVERTER.canonicalName,
+        "package ${CONVERTER.packageName};\n$code"
         )
     }
 
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
index 1bf4782..f8e5603 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/DaoProcessorTest.kt
@@ -17,7 +17,6 @@
 package androidx.room.processor
 
 import COMMON
-import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.compiler.processing.isTypeElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
@@ -227,7 +226,7 @@
             """
         ) { dao, invocation ->
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val daoProcessor =
                 DaoProcessor(invocation.context, dao.element, dbType, null)
 
@@ -275,7 +274,7 @@
             if (!dao.isTypeElement()) {
                 error("Expected DAO to be a type")
             }
-            val dbType = invocation.context.processingEnv.requireType(ROOM_DB.toJavaPoet())
+            val dbType = invocation.context.processingEnv.requireType(ROOM_DB)
             val daoProcessor =
                 DaoProcessor(invocation.context, dao, dbType, null)
             Truth.assertThat(daoProcessor.context.logger.suppressedWarnings)
@@ -296,7 +295,7 @@
             """
         ) { dao, invocation ->
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val daoProcessor =
                 DaoProcessor(invocation.context, dao.element, dbType, null)
             assertThat(
@@ -460,7 +459,7 @@
         """.trimIndent())
         runProcessorTest(sources = listOf(source)) { invocation ->
             val dao = invocation.processingEnv.requireTypeElement("MyDao")
-            val dbType = invocation.context.processingEnv.requireType(ROOM_DB.toJavaPoet())
+            val dbType = invocation.context.processingEnv.requireType(ROOM_DB)
             DaoProcessor(
                 baseContext = invocation.context,
                 element = dao,
@@ -779,7 +778,7 @@
                 null
             }
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val parser = DaoProcessor(
                 invocation.context,
                 dao, dbType, dbVerifier
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
index 9906e42..de17c33 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/InsertOrUpsertShortcutMethodProcessorTest.kt
@@ -23,7 +23,6 @@
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.asClassName
 import androidx.room.compiler.codegen.asMutableClassName
-import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
@@ -647,7 +646,7 @@
             invocation.assertCompilationResult {
                 hasErrorContaining(
                     ProcessorErrors.missingRequiredColumnsInPartialEntity(
-                        partialEntityName = USERNAME_TYPE_NAME.toJavaPoet().toString(),
+                        partialEntityName = USERNAME_TYPE_NAME.toString(CodeLanguage.JAVA),
                         missingColumnNames = listOf("ageColumn")
                     )
                 )
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
index 3dae9d4..c93ac24 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
@@ -18,7 +18,7 @@
 
 import COMMON
 import androidx.room.Embedded
-import androidx.room.compiler.codegen.toJavaPoet
+import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.processing.XFieldElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
@@ -43,7 +43,6 @@
 import androidx.room.vo.RelationCollector
 import com.google.common.truth.Truth
 import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.TypeName
 import java.io.File
 import org.hamcrest.CoreMatchers.instanceOf
 import org.hamcrest.CoreMatchers.`is`
@@ -213,8 +212,8 @@
             assertThat(parent.prefix, `is`(""))
             assertThat(parent.field.name, `is`("myPoint"))
             assertThat(
-                parent.pojo.typeName.toJavaPoet(),
-                `is`(ClassName.get("foo.bar.MyPojo", "Point") as TypeName)
+                parent.pojo.typeName,
+                `is`(XClassName.get("foo.bar.MyPojo", "Point"))
             )
         }
     }
@@ -316,8 +315,8 @@
             )
             val pointField = pojo.embeddedFields.first { it.field.name == "genericField" }
             assertThat(
-                pointField.pojo.typeName.toJavaPoet(),
-                `is`(ClassName.get("foo.bar", "Point") as TypeName)
+                pointField.pojo.typeName,
+                `is`(XClassName.get("foo.bar", "Point"))
             )
         }
     }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
index 9a18e76..f37014e 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
@@ -23,7 +23,6 @@
 import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.asClassName
-import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.util.Source
@@ -374,7 +373,7 @@
             """
                 @Query("WITH RECURSIVE tempTable(n, fact) AS (SELECT 0, 1 UNION ALL SELECT n+1,"
                 + " (n+1)*fact FROM tempTable WHERE n < 9) SELECT fact FROM tempTable, User")
-                abstract public ${LifecyclesTypeNames.LIVE_DATA.canonicalName}<${LIST.toJavaPoet()}<Integer>>
+                abstract public ${LifecyclesTypeNames.LIVE_DATA.canonicalName}<${LIST.canonicalName}<Integer>>
                 getFactorialLiveData();
                 """
         ) { parsedQuery, _ ->
@@ -409,7 +408,7 @@
             """
                 @Query("WITH RECURSIVE tempTable(n, fact) AS (SELECT 0, 1 UNION ALL SELECT n+1,"
                 + " (n+1)*fact FROM tempTable WHERE n < 9) SELECT fact FROM tempTable")
-                abstract public ${LifecyclesTypeNames.LIVE_DATA.canonicalName}<${LIST.toJavaPoet()}<Integer>>
+                abstract public ${LifecyclesTypeNames.LIVE_DATA.canonicalName}<${LIST.canonicalName}<Integer>>
                 getFactorialLiveData();
                 """
         ) { _, invocation ->
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
index 37534d1..82733cd 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
@@ -19,7 +19,7 @@
 import COMMON
 import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.codegen.XTypeName
-import androidx.room.compiler.codegen.toJavaPoet
+import androidx.room.compiler.codegen.XTypeName.Companion.PRIMITIVE_LONG
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.compileFiles
 import androidx.room.compiler.processing.util.runProcessorTest
@@ -123,9 +123,8 @@
             classpathFiles = libraryClasspath
         ) { _, invocation ->
             invocation.assertCompilationResult {
-                hasError(
-                    ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD +
-                        " - id in test.library.MissingGetterEntity"
+                hasErrorContaining(
+                    ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD
                 )
             }
         }
@@ -2606,7 +2605,7 @@
             )
             val parsed = parser.process()
             val field = parsed.primaryKey.fields.first()
-            assertThat(field.typeName.toJavaPoet()).isEqualTo(TypeName.LONG)
+            assertThat(field.typeName).isEqualTo(PRIMITIVE_LONG)
         }
     }
 }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
index 712dd2b..5033e65 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/CustomTypeConverterResolutionTest.kt
@@ -26,85 +26,82 @@
 import androidx.room.Query
 import androidx.room.TypeConverter
 import androidx.room.TypeConverters
-import androidx.room.compiler.codegen.toJavaPoet
+import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.VisibilityModifier
+import androidx.room.compiler.codegen.XAnnotationSpec
+import androidx.room.compiler.codegen.XClassName
+import androidx.room.compiler.codegen.XCodeBlock
+import androidx.room.compiler.codegen.XFunSpec
+import androidx.room.compiler.codegen.XPropertySpec
+import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.codegen.XTypeSpec
+import androidx.room.compiler.codegen.asClassName
 import androidx.room.compiler.processing.util.CompilationResultSubject
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.ext.CommonTypeNames
 import androidx.room.ext.RoomTypeNames.ROOM_DB
-import androidx.room.ext.S
-import androidx.room.ext.T
 import androidx.room.processor.ProcessorErrors.CANNOT_BIND_QUERY_PARAMETER_INTO_STMT
-import com.squareup.javapoet.AnnotationSpec
-import com.squareup.javapoet.ClassName
-import com.squareup.javapoet.FieldSpec
-import com.squareup.javapoet.MethodSpec
-import com.squareup.javapoet.ParameterSpec
-import com.squareup.javapoet.ParameterizedTypeName
-import com.squareup.javapoet.TypeName
-import com.squareup.javapoet.TypeSpec
-import javax.lang.model.element.Modifier
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 
 @RunWith(JUnit4::class)
 class CustomTypeConverterResolutionTest {
-    fun TypeSpec.toSource(): Source {
+    fun XTypeSpec.toSource(): Source {
         return Source.java(
-            "foo.bar.${this.name}",
+            this.className.canonicalName,
             "package foo.bar;\n" + toString()
         )
     }
 
     companion object {
-        val ENTITY = ClassName.get("foo.bar", "MyEntity")
-        val DB = ClassName.get("foo.bar", "MyDb")
-        val DAO = ClassName.get("foo.bar", "MyDao")
+        val ENTITY = XClassName.get("foo.bar", "MyEntity")
+        val DB = XClassName.get("foo.bar", "MyDb")
+        val DAO = XClassName.get("foo.bar", "MyDao")
 
-        val CUSTOM_TYPE = ClassName.get("foo.bar", "CustomType")
+        val CUSTOM_TYPE = XClassName.get("foo.bar", "CustomType")
         val CUSTOM_TYPE_JFO = Source.java(
-            CUSTOM_TYPE.toString(),
+            CUSTOM_TYPE.canonicalName,
             """
-                package ${CUSTOM_TYPE.packageName()};
-                public class ${CUSTOM_TYPE.simpleName()} {
+                package ${CUSTOM_TYPE.packageName};
+                public class ${CUSTOM_TYPE.simpleNames.first()} {
                     public int value;
                 }
                 """
         )
-        val CUSTOM_TYPE_CONVERTER = ClassName.get("foo.bar", "MyConverter")
+        val CUSTOM_TYPE_CONVERTER = XClassName.get("foo.bar", "MyConverter")
         val CUSTOM_TYPE_CONVERTER_JFO = Source.java(
-            CUSTOM_TYPE_CONVERTER.toString(),
+            CUSTOM_TYPE_CONVERTER.canonicalName,
             """
-                package ${CUSTOM_TYPE_CONVERTER.packageName()};
-                public class ${CUSTOM_TYPE_CONVERTER.simpleName()} {
+                package ${CUSTOM_TYPE_CONVERTER.packageName};
+                public class ${CUSTOM_TYPE_CONVERTER.simpleNames.first()} {
                     @${TypeConverter::class.java.canonicalName}
-                    public static $CUSTOM_TYPE toCustom(int value) {
+                    public static ${CUSTOM_TYPE.canonicalName} toCustom(int value) {
                         return null;
                     }
                     @${TypeConverter::class.java.canonicalName}
-                    public static int fromCustom($CUSTOM_TYPE input) {
+                    public static int fromCustom(${CUSTOM_TYPE.canonicalName} input) {
                         return 0;
                     }
                 }
                 """
         )
-        val CUSTOM_TYPE_SET = ParameterizedTypeName.get(
-            ClassName.get(Set::class.java), CUSTOM_TYPE
-        )
-        val CUSTOM_TYPE_SET_CONVERTER = ClassName.get("foo.bar", "MySetConverter")
+        val CUSTOM_TYPE_SET = CommonTypeNames.SET.parametrizedBy(CUSTOM_TYPE)
+        val CUSTOM_TYPE_SET_CONVERTER = XClassName.get("foo.bar", "MySetConverter")
         val CUSTOM_TYPE_SET_CONVERTER_JFO = Source.java(
-            CUSTOM_TYPE_SET_CONVERTER.toString(),
+            CUSTOM_TYPE_SET_CONVERTER.canonicalName,
             """
-                package ${CUSTOM_TYPE_SET_CONVERTER.packageName()};
+                package ${CUSTOM_TYPE_SET_CONVERTER.packageName};
                 import java.util.HashSet;
                 import java.util.Set;
-                public class ${CUSTOM_TYPE_SET_CONVERTER.simpleName()} {
+                public class ${CUSTOM_TYPE_SET_CONVERTER.simpleNames.first()} {
                     @${TypeConverter::class.java.canonicalName}
-                    public static $CUSTOM_TYPE_SET toCustom(int value) {
+                    public static ${CUSTOM_TYPE_SET.toString(CodeLanguage.JAVA)} toCustom(int value) {
                         return null;
                     }
                     @${TypeConverter::class.java.canonicalName}
-                    public static int fromCustom($CUSTOM_TYPE_SET input) {
+                    public static int fromCustom(${CUSTOM_TYPE_SET.toString(CodeLanguage.JAVA)} input) {
                         return 0;
                     }
                 }
@@ -280,7 +277,7 @@
         hasConverters: Boolean = false,
         hasConverterOnField: Boolean = false,
         useCollection: Boolean = false
-    ): TypeSpec {
+    ): XTypeSpec {
         if (hasConverterOnField && hasConverters) {
             throw IllegalArgumentException("cannot have both converters")
         }
@@ -289,12 +286,20 @@
         } else {
             CUSTOM_TYPE
         }
-        return TypeSpec.classBuilder(ENTITY).apply {
-            addAnnotation(Entity::class.java)
-            addModifiers(Modifier.PUBLIC)
+        return XTypeSpec.classBuilder(CodeLanguage.JAVA, ENTITY).apply {
+            addAnnotation(
+                XAnnotationSpec.builder(CodeLanguage.JAVA, Entity::class.asClassName()).build()
+            )
+            setVisibility(VisibilityModifier.PUBLIC)
             if (hasCustomField) {
-                addField(
-                    FieldSpec.builder(type, "myCustomField", Modifier.PUBLIC).apply {
+                addProperty(
+                    XPropertySpec.builder(
+                        CodeLanguage.JAVA,
+                        "myCustomField",
+                        type,
+                        VisibilityModifier.PUBLIC,
+                        isMutable = true
+                    ).apply {
                         if (hasConverterOnField) {
                             addAnnotation(createConvertersAnnotation())
                         }
@@ -304,10 +309,19 @@
             if (hasConverters) {
                 addAnnotation(createConvertersAnnotation())
             }
-            addField(
-                FieldSpec.builder(TypeName.INT, "id", Modifier.PUBLIC).apply {
-                    addAnnotation(PrimaryKey::class.java)
-                }.build()
+            addProperty(
+                XPropertySpec.builder(
+                    language = CodeLanguage.JAVA,
+                    name = "id",
+                    typeName = XTypeName.PRIMITIVE_INT,
+                    visibility = VisibilityModifier.PUBLIC,
+                    isMutable = true
+                ).addAnnotation(
+                    XAnnotationSpec.builder(
+                        CodeLanguage.JAVA,
+                        PrimaryKey::class.asClassName()
+                    ).build()
+                ).build()
             )
         }.build()
     }
@@ -316,30 +330,67 @@
         hasConverters: Boolean = false,
         hasDao: Boolean = false,
         useCollection: Boolean = false
-    ): TypeSpec {
-        return TypeSpec.classBuilder(DB).apply {
-            addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
-            superclass(ROOM_DB.toJavaPoet())
+    ): XTypeSpec {
+        return XTypeSpec.classBuilder(CodeLanguage.JAVA, DB, isOpen = true).apply {
+            addAbstractModifier()
+            setVisibility(VisibilityModifier.PUBLIC)
+            superclass(ROOM_DB)
             if (hasConverters) {
                 addAnnotation(createConvertersAnnotation(useCollection = useCollection))
             }
-            addField(
-                FieldSpec.builder(TypeName.INT, "id", Modifier.PUBLIC).apply {
-                    addAnnotation(PrimaryKey::class.java)
-                }.build()
+            addProperty(
+                XPropertySpec.builder(
+                    language = CodeLanguage.JAVA,
+                    name = "id",
+                    typeName = XTypeName.PRIMITIVE_INT,
+                    visibility = VisibilityModifier.PUBLIC,
+                    isMutable = true
+                ).addAnnotation(
+                    XAnnotationSpec.builder(
+                        CodeLanguage.JAVA,
+                        PrimaryKey::class.asClassName()
+                    ).build()
+                ).build()
             )
             if (hasDao) {
-                addMethod(
-                    MethodSpec.methodBuilder("getDao").apply {
-                        addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
+                addFunction(
+                    XFunSpec.builder(
+                        language = CodeLanguage.JAVA,
+                        "getDao",
+                        VisibilityModifier.PUBLIC
+                    ).apply {
+                        addAbstractModifier()
                         returns(DAO)
                     }.build()
                 )
             }
             addAnnotation(
-                AnnotationSpec.builder(Database::class.java).apply {
-                    addMember("entities", "{$T.class}", ENTITY)
-                    addMember("version", "42")
+                XAnnotationSpec.builder(
+                    CodeLanguage.JAVA,
+                    Database::class.asClassName()
+                ).apply {
+                    addMember(
+                        "entities",
+                        XCodeBlock.of(
+                            language,
+                            "{%T.class}",
+                            ENTITY
+                        )
+                    )
+                    addMember(
+                        "version",
+                        XCodeBlock.of(
+                            language,
+                            "42"
+                        )
+                    )
+                    addMember(
+                        "exportSchema",
+                        XCodeBlock.of(
+                            language,
+                            "false"
+                        )
+                    )
                 }.build()
             )
         }.build()
@@ -352,7 +403,7 @@
         hasMethodConverters: Boolean = false,
         hasParameterConverters: Boolean = false,
         useCollection: Boolean = false
-    ): TypeSpec {
+    ): XTypeSpec {
         val annotationCount = listOf(hasMethodConverters, hasConverters, hasParameterConverters)
             .map { if (it) 1 else 0 }.sum()
         if (annotationCount > 1) {
@@ -361,25 +412,39 @@
         if (hasParameterConverters && !hasQueryWithCustomParam) {
             throw IllegalArgumentException("inconsistent")
         }
-        return TypeSpec.classBuilder(DAO).apply {
-            addAnnotation(Dao::class.java)
-            addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
+        return XTypeSpec.classBuilder(
+            CodeLanguage.JAVA,
+            DAO,
+            isOpen = true
+        ).apply {
+            addAbstractModifier()
+            addAnnotation(XAnnotationSpec.builder(
+                CodeLanguage.JAVA,
+                Dao::class.asClassName()
+            ).build())
+            setVisibility(VisibilityModifier.PUBLIC)
             if (hasConverters) {
                 addAnnotation(createConvertersAnnotation(useCollection = useCollection))
             }
             if (hasQueryReturningEntity) {
-                addMethod(
-                    MethodSpec.methodBuilder("loadAll").apply {
-                        addAnnotation(
-                            AnnotationSpec.builder(Query::class.java).apply {
-                                addMember(
-                                    "value",
-                                    S,
-                                    "SELECT * FROM ${ENTITY.simpleName()} LIMIT 1"
-                                )
-                            }.build()
-                        )
-                        addModifiers(Modifier.ABSTRACT)
+                addFunction(
+                    XFunSpec.builder(
+                        CodeLanguage.JAVA,
+                        "loadAll",
+                        VisibilityModifier.PUBLIC
+                    ).apply {
+                        addAbstractModifier()
+                        addAnnotation(XAnnotationSpec.builder(
+                            CodeLanguage.JAVA,
+                            Query::class.asClassName()
+                        ).addMember(
+                            "value",
+                            XCodeBlock.of(
+                                CodeLanguage.JAVA,
+                                "%S",
+                                "SELECT * FROM ${ENTITY.simpleNames.first()} LIMIT 1"
+                            )
+                        ).build())
                         returns(ENTITY)
                     }.build()
                 )
@@ -390,44 +455,52 @@
                 CUSTOM_TYPE
             }
             if (hasQueryWithCustomParam) {
-                addMethod(
-                    MethodSpec.methodBuilder("queryWithCustom").apply {
-                        addAnnotation(
-                            AnnotationSpec.builder(Query::class.java).apply {
-                                addMember(
-                                    "value", S,
-                                    "SELECT COUNT(*) FROM ${ENTITY.simpleName()} where" +
-                                        " id = :custom"
-                                )
-                            }.build()
-                        )
+                addFunction(
+                    XFunSpec.builder(
+                        CodeLanguage.JAVA,
+                        "queryWithCustom",
+                        VisibilityModifier.PUBLIC
+                    ).apply {
+                        addAbstractModifier()
+                        addAnnotation(XAnnotationSpec.builder(
+                            CodeLanguage.JAVA,
+                            Query::class.asClassName()
+                        ).addMember(
+                            "value",
+                            XCodeBlock.of(
+                                CodeLanguage.JAVA,
+                                "%S",
+                                "SELECT COUNT(*) FROM ${ENTITY.simpleNames.first()} where" +
+                                    " id = :custom"
+                            )
+                        ).build())
                         if (hasMethodConverters) {
                             addAnnotation(createConvertersAnnotation(useCollection = useCollection))
                         }
                         addParameter(
-                            ParameterSpec.builder(customType, "custom").apply {
-                                if (hasParameterConverters) {
-                                    addAnnotation(
-                                        createConvertersAnnotation(useCollection = useCollection)
-                                    )
-                                }
-                            }.build()
-                        )
-                        addModifiers(Modifier.ABSTRACT)
-                        returns(TypeName.INT)
+                            customType,
+                            "custom"
+                        ).apply {
+                            if (hasParameterConverters) {
+                                addAnnotation(
+                                    createConvertersAnnotation(useCollection = useCollection)
+                                )
+                            }
+                        }.build()
+                        returns(XTypeName.PRIMITIVE_INT)
                     }.build()
                 )
             }
         }.build()
     }
 
-    private fun createConvertersAnnotation(useCollection: Boolean = false): AnnotationSpec {
+    private fun createConvertersAnnotation(useCollection: Boolean = false): XAnnotationSpec {
         val converter = if (useCollection) {
             CUSTOM_TYPE_SET_CONVERTER
         } else {
             CUSTOM_TYPE_CONVERTER
         }
-        return AnnotationSpec.builder(TypeConverters::class.java)
-            .addMember("value", "$T.class", converter).build()
+        return XAnnotationSpec.builder(CodeLanguage.JAVA, TypeConverters::class.asClassName())
+            .addMember("value", XCodeBlock.of(CodeLanguage.JAVA, "%T.class", converter)).build()
     }
 }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
index 52fae72..009d64c 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/TypeAdapterStoreTest.kt
@@ -22,7 +22,6 @@
 import androidx.room.Dao
 import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XTypeName
-import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.compiler.processing.XProcessingEnv
 import androidx.room.compiler.processing.XRawType
 import androidx.room.compiler.processing.isTypeElement
@@ -1216,7 +1215,7 @@
                 ).first()
             check(dao.isTypeElement())
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val parser = DaoProcessor(
                 invocation.context,
                 dao, dbType, null,
@@ -1269,7 +1268,7 @@
                 ).first()
             check(dao.isTypeElement())
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val parser = DaoProcessor(
                 invocation.context,
                 dao, dbType, null,
@@ -1321,7 +1320,7 @@
                 ).first()
             check(dao.isTypeElement())
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val parser = DaoProcessor(
                 invocation.context,
                 dao, dbType, null,
@@ -1369,7 +1368,7 @@
                 ).first()
             check(dao.isTypeElement())
             val dbType = invocation.context.processingEnv
-                .requireType(ROOM_DB.toJavaPoet())
+                .requireType(ROOM_DB)
             val parser = DaoProcessor(
                 invocation.context,
                 dao, dbType, null,
@@ -1722,7 +1721,7 @@
                 return XCodeBlock.of(
                     scope.language,
                     "%T.joinIntoString(%L)",
-                    STRING_UTIL.toJavaPoet(),
+                    STRING_UTIL,
                     inputVarName
                 )
             }
@@ -1735,7 +1734,7 @@
                 return XCodeBlock.of(
                     scope.language,
                     "%T.splitToIntList(%L)",
-                    STRING_UTIL.toJavaPoet(),
+                    STRING_UTIL,
                     inputVarName
                 )
             }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
index aa5618a..5279228 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/query/QueryWriterTest.kt
@@ -18,7 +18,7 @@
 
 import androidx.room.Dao
 import androidx.room.Query
-import androidx.room.compiler.codegen.toJavaPoet
+import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.runProcessorTest
@@ -45,7 +45,7 @@
                 abstract class MyClass {
                 """
         const val DAO_SUFFIX = "}"
-        val QUERY = ROOM_SQL_QUERY.toJavaPoet().toString()
+        val QUERY = ROOM_SQL_QUERY.toString(CodeLanguage.JAVA)
     }
 
     @Test
@@ -136,10 +136,10 @@
             writer.prepareReadAndBind("_sql", "_stmt", scope)
             assertThat(scope.builder().build().toString().trim()).isEqualTo(
                 """
-                final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.toJavaPoet()}.newStringBuilder();
+                final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.canonicalName}.newStringBuilder();
                 _stringBuilder.append("SELECT id FROM users WHERE id IN(");
                 final int _inputSize = ids == null ? 1 : ids.length;
-                ${STRING_UTIL.toJavaPoet()}.appendPlaceholders(_stringBuilder, _inputSize);
+                ${STRING_UTIL.canonicalName}.appendPlaceholders(_stringBuilder, _inputSize);
                 _stringBuilder.append(") AND age > ");
                 _stringBuilder.append("?");
                 final java.lang.String _sql = _stringBuilder.toString();
@@ -162,10 +162,10 @@
     }
 
     val collectionOut = """
-        final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.toJavaPoet()}.newStringBuilder();
+        final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.canonicalName}.newStringBuilder();
         _stringBuilder.append("SELECT id FROM users WHERE id IN(");
         final int _inputSize = ids == null ? 1 : ids.size();
-        ${STRING_UTIL.toJavaPoet()}.appendPlaceholders(_stringBuilder, _inputSize);
+        ${STRING_UTIL.canonicalName}.appendPlaceholders(_stringBuilder, _inputSize);
         _stringBuilder.append(") AND age > ");
         _stringBuilder.append("?");
         final java.lang.String _sql = _stringBuilder.toString();
@@ -265,14 +265,14 @@
             writer.prepareReadAndBind("_sql", "_stmt", scope)
             assertThat(scope.builder().build().toString().trim()).isEqualTo(
                 """
-                final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.toJavaPoet()}.newStringBuilder();
+                final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.canonicalName}.newStringBuilder();
                 _stringBuilder.append("SELECT id FROM users WHERE age > ");
                 _stringBuilder.append("?");
                 _stringBuilder.append(" OR bage > ");
                 _stringBuilder.append("?");
                 _stringBuilder.append(" OR fage IN(");
                 final int _inputSize = ages == null ? 1 : ages.length;
-                ${STRING_UTIL.toJavaPoet()}.appendPlaceholders(_stringBuilder, _inputSize);
+                ${STRING_UTIL.canonicalName}.appendPlaceholders(_stringBuilder, _inputSize);
                 _stringBuilder.append(")");
                 final java.lang.String _sql = _stringBuilder.toString();
                 final int _argCount = 2 + _inputSize;
@@ -307,15 +307,15 @@
             writer.prepareReadAndBind("_sql", "_stmt", scope)
             assertThat(scope.builder().build().toString().trim()).isEqualTo(
                 """
-                final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.toJavaPoet()}.newStringBuilder();
+                final java.lang.StringBuilder _stringBuilder = ${STRING_UTIL.canonicalName}.newStringBuilder();
                 _stringBuilder.append("SELECT id FROM users WHERE age IN (");
                 final int _inputSize = ages == null ? 1 : ages.length;
-                ${STRING_UTIL.toJavaPoet()}.appendPlaceholders(_stringBuilder, _inputSize);
+                ${STRING_UTIL.canonicalName}.appendPlaceholders(_stringBuilder, _inputSize);
                 _stringBuilder.append(") OR bage > ");
                 _stringBuilder.append("?");
                 _stringBuilder.append(" OR fage IN(");
                 final int _inputSize_1 = ages == null ? 1 : ages.length;
-                ${STRING_UTIL.toJavaPoet()}.appendPlaceholders(_stringBuilder, _inputSize_1);
+                ${STRING_UTIL.canonicalName}.appendPlaceholders(_stringBuilder, _inputSize_1);
                 _stringBuilder.append(")");
                 final java.lang.String _sql = _stringBuilder.toString();
                 final int _argCount = 1 + _inputSize + _inputSize_1;
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
index 45e244d..de81792 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoWriterTest.kt
@@ -18,7 +18,6 @@
 
 import COMMON
 import androidx.room.compiler.codegen.CodeLanguage
-import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
@@ -176,7 +175,7 @@
                         androidx.room.Database::class.qualifiedName!!
                     ).filterIsInstance<XTypeElement>().firstOrNull()
                     ?: invocation.context.processingEnv
-                        .requireTypeElement(ROOM_DB.toJavaPoet())
+                        .requireTypeElement(ROOM_DB)
                 val dbType = db.type
                 val dbVerifier = createVerifierFromEntitiesAndViews(invocation)
                 invocation.context.attachDatabaseVerifier(dbVerifier)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt
index 4a7cc1d..7d67afd 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DefaultsInDaoTest.kt
@@ -18,7 +18,6 @@
 
 import COMMON
 import androidx.room.compiler.codegen.CodeLanguage
-import androidx.room.compiler.codegen.toJavaPoet
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.runKaptTest
@@ -157,7 +156,7 @@
                 ).filterIsInstance<XTypeElement>()
                 .forEach { dao ->
                     val db = invocation.context.processingEnv
-                        .requireTypeElement(ROOM_DB.toJavaPoet())
+                        .requireTypeElement(ROOM_DB)
                     val dbType = db.type
                     val parser = DaoProcessor(
                         baseContext = invocation.context,
@@ -170,7 +169,7 @@
                         .write(invocation.processingEnv)
                     invocation.assertCompilationResult {
                         val relativePath =
-                            parsedDao.implTypeName.toJavaPoet().simpleName() + ".java"
+                            parsedDao.implTypeName.canonicalName + ".java"
                         handler(generatedSourceFileWithPath(relativePath))
                     }
                 }
diff --git a/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt b/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt
index aaefe4c..89fb70a 100644
--- a/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt
+++ b/room/room-runtime/src/main/java/androidx/room/EntityUpsertionAdapter.kt
@@ -208,7 +208,11 @@
     private fun checkUniquenessException(ex: SQLiteConstraintException) {
         val message = ex.message ?: throw ex
         if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
-            if (!message.contains(ErrorMsg, ignoreCase = true)) {
+            if (!message.contains(ErrorMsg, ignoreCase = true) && !message.contains(
+                    ErrorCode,
+                    ignoreCase = true
+                )
+            ) {
                 throw ex
             }
         } else {