Generate Java lambda syntax when jvmTarget > 8

This CL introduces the utility function InvokeWithLambdaParameter() that generate a code block to invoke a function whose last parameter is a functional type. The utility will correctly generate the right code in Java (with an anonymous class if targeting older than Java 8 or with lambda syntax if targeting Java 8 or greater) and Kotlin.

Bug: 322387497
Test: DaoWriterTest
Change-Id: Ib9f5ea310fc550a04262b35d2ff1103420e05cb8
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt b/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt
index 2e69a12..5a051fd 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/DatabaseProcessingStep.kt
@@ -94,15 +94,20 @@
             prepareDaosForWriting(databases, it.keys.toList())
             it.forEach { (daoMethod, db) ->
                 DaoWriter(
-                    daoMethod.dao,
-                    db.element,
-                    context.codeLanguage
+                    dao = daoMethod.dao,
+                    dbElement = db.element,
+                    codeLanguage = context.codeLanguage,
+                    javaLambdaSyntaxAvailable = context.javaLambdaSyntaxAvailable
                 ).write(context.processingEnv)
             }
         }
 
         databases?.forEach { db ->
-            DatabaseWriter(db, context.codeLanguage).write(context.processingEnv)
+            DatabaseWriter(
+                database = db,
+                codeLanguage = context.codeLanguage,
+                javaLambdaSyntaxAvailable = context.javaLambdaSyntaxAvailable
+            ).write(context.processingEnv)
             if (db.exportSchema) {
                 val qName = db.element.qualifiedName
                 val filename = "${db.version}.json"
@@ -131,8 +136,12 @@
                 }
             }
             db.autoMigrations.forEach { autoMigration ->
-                AutoMigrationWriter(db.element, autoMigration, context.codeLanguage)
-                    .write(context.processingEnv)
+                AutoMigrationWriter(
+                    autoMigration = autoMigration,
+                    dbElement = db.element,
+                    codeLanguage = context.codeLanguage,
+                    javaLambdaSyntaxAvailable = context.javaLambdaSyntaxAvailable
+                ).write(context.processingEnv)
             }
 
             if (context.codeLanguage == CodeLanguage.KOTLIN) {
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 7b40165..f14ebe9 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
@@ -22,12 +22,14 @@
 import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XFunSpec
 import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.apply
+import androidx.room.compiler.codegen.XMemberName
 import androidx.room.compiler.codegen.XMemberName.Companion.companionMember
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.XTypeSpec
 import androidx.room.compiler.codegen.asClassName
 import androidx.room.compiler.codegen.asMutableClassName
+import androidx.room.solver.CodeGenScope
 import com.squareup.kotlinpoet.javapoet.JTypeName
 import java.util.concurrent.Callable
 
@@ -405,6 +407,126 @@
 }.build()
 
 /**
+ * Generates a code block that invokes a function with a functional type as last parameter.
+ *
+ * For Java (jvmTarget >= 8) it will generate:
+ * ```
+ * <functionName>(<args>, (<lambdaSpec.paramName>) -> <lambdaSpec.body>);
+ * ```
+ * For Java (jvmTarget < 8) it will generate:
+ * ```
+ * <functionName>(<args>, new Function1<>() { <lambdaSpec.body> });
+ * ```
+ * For Kotlin it will generate:
+ * ```
+ * <functionName>(<args>) { <lambdaSpec.body> }
+ * ```
+ *
+ * The ideal usage of this utility function is to generate code that invokes the various
+ * `DBUtil.perform*()` APIs for interacting with the database connection in DAOs.
+ */
+fun InvokeWithLambdaParameter(
+    scope: CodeGenScope,
+    functionName: XMemberName,
+    argFormat: List<String>,
+    args: List<Any>,
+    continuationParamName: String? = null,
+    lambdaSpec: LambdaSpec
+): XCodeBlock = XCodeBlock.builder(scope.language).apply {
+    check(argFormat.size == args.size)
+    when (language) {
+        CodeLanguage.JAVA -> {
+            if (lambdaSpec.javaLambdaSyntaxAvailable) {
+                val argsFormatString = argFormat.joinToString(separator = ", ")
+                add(
+                    "%M($argsFormatString, (%L) -> {\n",
+                    functionName,
+                    *args.toTypedArray(),
+                    lambdaSpec.parameterName
+                )
+                indent()
+                val bodyScope = scope.fork()
+                with(lambdaSpec) { bodyScope.builder.body(bodyScope) }
+                add(bodyScope.generate())
+                unindent()
+                add("}")
+                if (continuationParamName != null) {
+                    add(", %L", continuationParamName)
+                }
+                add(");\n")
+            } else {
+                val adjustedArgsFormatString = buildList {
+                    addAll(argFormat)
+                    add("%L") // the anonymous function
+                    if (continuationParamName != null) {
+                        add("%L")
+                    }
+                }.joinToString(separator = ", ")
+                val adjustedArgs = buildList {
+                    addAll(args)
+                    add(
+                        Function1TypeSpec(
+                            language = language,
+                            parameterTypeName = lambdaSpec.parameterTypeName,
+                            parameterName = lambdaSpec.parameterName,
+                            returnTypeName = lambdaSpec.returnTypeName,
+                            callBody = {
+                                val bodyScope = scope.fork()
+                                with(lambdaSpec) { bodyScope.builder.body(bodyScope) }
+                                addCode(bodyScope.generate())
+                            }
+                        )
+                    )
+                    if (continuationParamName != null) {
+                        add(continuationParamName)
+                    }
+                }
+                add(
+                    "%M($adjustedArgsFormatString);\n",
+                    functionName,
+                    *adjustedArgs.toTypedArray(),
+                )
+            }
+        }
+        CodeLanguage.KOTLIN -> {
+            val argsFormatString = argFormat.joinToString(separator = ", ")
+            if (lambdaSpec.parameterTypeName.rawTypeName != KotlinTypeNames.CONTINUATION) {
+                add(
+                    "%M($argsFormatString) { %L ->\n",
+                    functionName,
+                    *args.toTypedArray(),
+                    lambdaSpec.parameterName
+                )
+            } else {
+                add(
+                    "%M($argsFormatString) {\n",
+                    functionName,
+                    *args.toTypedArray(),
+                )
+            }
+            indent()
+            val bodyScope = scope.fork()
+            with(lambdaSpec) { bodyScope.builder.body(bodyScope) }
+            add(bodyScope.generate())
+            unindent()
+            add("}\n")
+        }
+    }
+}.build()
+
+/**
+ * Describes the lambda to be generated with [InvokeWithLambdaParameter].
+ */
+abstract class LambdaSpec(
+    val parameterTypeName: XTypeName,
+    val parameterName: String,
+    val returnTypeName: XTypeName,
+    val javaLambdaSyntaxAvailable: Boolean
+) {
+    abstract fun XCodeBlock.Builder.body(scope: CodeGenScope)
+}
+
+/**
  * Generates an array literal with the given [values]
  *
  * Example: `ArrayLiteral(XTypeName.PRIMITIVE_INT, 1, 2, 3)`
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
index 1e6377a..add440f 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/Context.kt
@@ -99,6 +99,11 @@
         }
     }
 
+    // Whether Java 8's lambda syntax is available to be emitted or not.
+    val javaLambdaSyntaxAvailable by lazy {
+        processingEnv.jvmVersion >= 8
+    }
+
     companion object {
         val ARG_OPTIONS by lazy {
             ProcessorOptions.values().map { it.argName } +
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
index da3bba1..31ea22f 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/MethodProcessorDelegate.kt
@@ -187,7 +187,6 @@
                 jvmMethodName = executableElement.jvmName,
                 callType = callType
             ),
-            javaLambdaSyntaxAvailable = context.processingEnv.jvmVersion >= 8
         )
 }
 
@@ -270,8 +269,7 @@
                 jvmMethodName = executableElement.jvmName,
                 callType = callType
             ),
-            continuationParamName = continuationParam.name,
-            javaLambdaSyntaxAvailable = context.processingEnv.jvmVersion >= 8
+            continuationParamName = continuationParam.name
         )
 
     private fun XCodeBlock.Builder.addCoroutineExecuteStatement(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/CodeGenScope.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/CodeGenScope.kt
index e552cd7..a11d2dc 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/CodeGenScope.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/CodeGenScope.kt
@@ -16,7 +16,6 @@
 
 package androidx.room.solver
 
-import androidx.annotation.VisibleForTesting
 import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.writer.TypeWriter
 
@@ -29,6 +28,7 @@
     val useDriverApi: Boolean = false
 ) {
     val language = writer.codeLanguage
+    val javaLambdaSyntaxAvailable = writer.javaLambdaSyntaxAvailable
     val builder by lazy { XCodeBlock.builder(language) }
     private val tmpVarIndices = mutableMapOf<String, Int>()
 
@@ -36,8 +36,7 @@
         const val TMP_VAR_DEFAULT_PREFIX = "_tmp"
         const val CLASS_PROPERTY_PREFIX = "__"
 
-        @VisibleForTesting
-        fun getTmpVarString(index: Int) =
+        internal fun getTmpVarString(index: Int) =
             getTmpVarString(TMP_VAR_DEFAULT_PREFIX, index)
 
         private fun getTmpVarString(prefix: String, index: Int) =
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/CoroutinePreparedQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/CoroutinePreparedQueryResultBinder.kt
index 5172cacb..71d890b 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/CoroutinePreparedQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/CoroutinePreparedQueryResultBinder.kt
@@ -16,13 +16,14 @@
 
 package androidx.room.solver.prepared.binder
 
-import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.addLocalVal
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.box
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -54,40 +55,21 @@
         returnTypeName: XTypeName,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> executeAndReturnJava(
-                sqlQueryVar, dbProperty, bindStatement, returnTypeName, scope
-            )
-            CodeLanguage.KOTLIN -> executeAndReturnKotlin(
-                sqlQueryVar, dbProperty, bindStatement, scope
-            )
-        }
-    }
-
-    private fun executeAndReturnJava(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        returnTypeName: XTypeName,
-        scope: CodeGenScope
-    ) {
         val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            // TODO(b/322387497): Generate lambda syntax if possible
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            continuationParamName = continuationParamName,
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = returnTypeName.box()
+                returnTypeName = returnTypeName.box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val statementVar = scope.getTmpVar("_stmt")
                     addLocalVal(
                         statementVar,
                         SQLiteDriverTypeNames.STATEMENT,
@@ -96,49 +78,14 @@
                         sqlQueryVar
                     )
                     beginControlFlow("try")
-                    bindStatement(functionScope, statementVar)
-                    adapter?.executeAndReturn(connectionVar, statementVar, functionScope)
+                    bindStatement(scope, statementVar)
+                    adapter?.executeAndReturn(connectionVar, statementVar, scope)
                     nextControlFlow("finally")
                     addStatement("%L.close()", statementVar)
                     endControlFlow()
-                }.build()
-                this.addCode(functionCode)
-            },
-            continuationParamName
+                }
+            }
         )
-    }
-
-    private fun executeAndReturnKotlin(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        scope: CodeGenScope
-    ) {
-        val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            )
-            addLocalVal(
-                statementVar,
-                SQLiteDriverTypeNames.STATEMENT,
-                "%L.prepare(%L)",
-                connectionVar,
-                sqlQueryVar
-            )
-            beginControlFlow("try")
-            bindStatement(scope, statementVar)
-            adapter?.executeAndReturn(connectionVar, statementVar, scope)
-            nextControlFlow("finally")
-            addStatement("%L.close()", statementVar)
-            endControlFlow()
-            endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/InstantPreparedQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/InstantPreparedQueryResultBinder.kt
index a7a3591..2b40e63 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/InstantPreparedQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/prepared/binder/InstantPreparedQueryResultBinder.kt
@@ -17,12 +17,14 @@
 package androidx.room.solver.prepared.binder
 
 import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.addLocalVal
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.box
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -61,41 +63,20 @@
         returnTypeName: XTypeName,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> executeAndReturnJava(
-                sqlQueryVar, dbProperty, bindStatement, returnTypeName, scope
-            )
-            CodeLanguage.KOTLIN -> executeAndReturnKotlin(
-                sqlQueryVar, dbProperty, bindStatement, scope
-            )
-        }
-    }
-
-    private fun executeAndReturnJava(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        returnTypeName: XTypeName,
-        scope: CodeGenScope
-    ) {
         val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        val returnPrefix = if (returnTypeName == XTypeName.UNIT_VOID) "" else "return "
-        scope.builder.addStatement(
-            "$returnPrefix%M(%N, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            // TODO(b/322387497): Generate lambda syntax if possible
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = returnTypeName.box()
+                returnTypeName = returnTypeName.box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val statementVar = scope.getTmpVar("_stmt")
                     addLocalVal(
                         statementVar,
                         SQLiteDriverTypeNames.STATEMENT,
@@ -104,48 +85,18 @@
                         sqlQueryVar
                     )
                     beginControlFlow("try")
-                    bindStatement(functionScope, statementVar)
-                    adapter?.executeAndReturn(connectionVar, statementVar, functionScope)
+                    bindStatement(scope, statementVar)
+                    adapter?.executeAndReturn(connectionVar, statementVar, scope)
                     nextControlFlow("finally")
                     addStatement("%L.close()", statementVar)
                     endControlFlow()
-                }.build()
-                this.addCode(functionCode)
+                }
             }
         )
-    }
-
-    private fun executeAndReturnKotlin(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        scope: CodeGenScope
-    ) {
-        val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            )
-            addLocalVal(
-                statementVar,
-                SQLiteDriverTypeNames.STATEMENT,
-                "%L.prepare(%L)",
-                connectionVar,
-                sqlQueryVar
-            )
-            beginControlFlow("try")
-            bindStatement(scope, statementVar)
-            adapter?.executeAndReturn(connectionVar, statementVar, scope)
-            nextControlFlow("finally")
-            addStatement("%L.close()", statementVar)
-            endControlFlow()
-            endControlFlow()
+        val returnPrefix = when (scope.language) {
+            CodeLanguage.JAVA -> if (returnTypeName == XTypeName.UNIT_VOID) "" else "return "
+            CodeLanguage.KOTLIN -> "return "
         }
+        scope.builder.add("$returnPrefix%L", performBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
index 2a7ff10..89f6080 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
@@ -22,11 +22,13 @@
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.codegen.box
 import androidx.room.compiler.processing.XType
 import androidx.room.ext.ArrayLiteral
 import androidx.room.ext.CallableTypeSpecBuilder
 import androidx.room.ext.CommonTypeNames
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomCoroutinesTypeNames.COROUTINES_ROOM
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
@@ -99,53 +101,24 @@
             CommonTypeNames.STRING,
             *tableNames.toTypedArray()
         )
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                sqlQueryVar,
-                dbProperty,
-                bindStatement,
-                inTransaction,
-                arrayOfTableNamesLiteral,
-                scope
-            )
-
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                sqlQueryVar,
-                dbProperty,
-                bindStatement,
-                inTransaction,
-                arrayOfTableNamesLiteral,
-                scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        inTransaction: Boolean,
-        arrayOfTableNamesLiteral: XCodeBlock,
-        scope: CodeGenScope
-    ) {
         val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L)",
-            RoomTypeNames.FLOW_UTIL.packageMember("createFlow"),
-            dbProperty,
-            inTransaction,
-            arrayOfTableNamesLiteral,
-            // TODO(b/322387497): Generate lambda syntax if possible
-            Function1TypeSpec(
-                language = scope.language,
+        val createBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.FLOW_UTIL.packageMember("createFlow"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, inTransaction, arrayOfTableNamesLiteral),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = typeArg.asTypeName()
+                returnTypeName = returnTypeName.box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val outVar = functionScope.getTmpVar("_result")
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val returnPrefix = when (language) {
+                        CodeLanguage.JAVA -> "return "
+                        CodeLanguage.KOTLIN -> ""
+                    }
+                    val statementVar = scope.getTmpVar("_stmt")
                     addLocalVal(
                         statementVar,
                         SQLiteDriverTypeNames.STATEMENT,
@@ -154,53 +127,16 @@
                         sqlQueryVar
                     )
                     beginControlFlow("try")
-                    bindStatement(functionScope, statementVar)
-                    adapter?.convert(outVar, statementVar, functionScope)
-                    addStatement("return %L", outVar)
+                    bindStatement(scope, statementVar)
+                    val outVar = scope.getTmpVar("_result")
+                    adapter?.convert(outVar, statementVar, scope)
+                    addStatement("$returnPrefix%L", outVar)
                     nextControlFlow("finally")
                     addStatement("%L.close()", statementVar)
                     endControlFlow()
-                }.build()
-                this.addCode(functionCode)
+                }
             }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        inTransaction: Boolean,
-        arrayOfTableNamesLiteral: XCodeBlock,
-        scope: CodeGenScope
-    ) {
-        val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.FLOW_UTIL.packageMember("createFlow"),
-                dbProperty,
-                inTransaction,
-                arrayOfTableNamesLiteral,
-                connectionVar
-            )
-            addLocalVal(
-                statementVar,
-                SQLiteDriverTypeNames.STATEMENT,
-                "%L.prepare(%L)",
-                connectionVar,
-                sqlQueryVar
-            )
-            beginControlFlow("try")
-            bindStatement(scope, statementVar)
-            val outVar = scope.getTmpVar("_result")
-            adapter?.convert(outVar, statementVar, scope)
-            addStatement("%L", outVar)
-            nextControlFlow("finally")
-            addStatement("%L.close()", statementVar)
-            endControlFlow()
-            endControlFlow()
-        }
+        scope.builder.add("return %L", createBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
index e376b18..8d955de 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
@@ -27,7 +27,8 @@
 import androidx.room.compiler.processing.XType
 import androidx.room.ext.AndroidTypeNames
 import androidx.room.ext.CallableTypeSpecBuilder
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomCoroutinesTypeNames
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
@@ -152,42 +153,25 @@
         inTransaction: Boolean,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                sqlQueryVar, dbProperty, bindStatement, returnTypeName, inTransaction, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                sqlQueryVar, dbProperty, bindStatement, inTransaction, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        returnTypeName: XTypeName,
-        inTransaction: Boolean,
-        scope: CodeGenScope
-    ) {
         val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-            dbProperty,
-            true, // isReadOnly
-            inTransaction,
-            // TODO(b/322387497): Generate lambda syntax if possible
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ true, inTransaction),
+            continuationParamName = continuationParamName,
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = returnTypeName.box()
+                returnTypeName = returnTypeName.box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val outVar = functionScope.getTmpVar("_result")
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val returnPrefix = when (language) {
+                        CodeLanguage.JAVA -> "return "
+                        CodeLanguage.KOTLIN -> ""
+                    }
+                    val statementVar = scope.getTmpVar("_stmt")
                     addLocalVal(
                         statementVar,
                         SQLiteDriverTypeNames.STATEMENT,
@@ -196,53 +180,16 @@
                         sqlQueryVar
                     )
                     beginControlFlow("try")
-                    bindStatement(functionScope, statementVar)
-                    adapter?.convert(outVar, statementVar, functionScope)
-                    addStatement("return %L", outVar)
+                    bindStatement(scope, statementVar)
+                    val outVar = scope.getTmpVar("_result")
+                    adapter?.convert(outVar, statementVar, scope)
+                    addStatement("$returnPrefix%L", outVar)
                     nextControlFlow("finally")
                     addStatement("%L.close()", statementVar)
                     endControlFlow()
-                }.build()
-                this.addCode(functionCode)
-            },
-            continuationParamName
+                }
+            }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        inTransaction: Boolean,
-        scope: CodeGenScope
-    ) {
-        val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-                dbProperty,
-                true, // isReadOnly
-                inTransaction,
-                connectionVar
-            )
-            scope.builder.addLocalVal(
-                statementVar,
-                SQLiteDriverTypeNames.STATEMENT,
-                "%L.prepare(%L)",
-                connectionVar,
-                sqlQueryVar
-            )
-            beginControlFlow("try")
-            bindStatement(scope, statementVar)
-            val outVar = scope.getTmpVar("_result")
-            adapter?.convert(outVar, statementVar, scope)
-            addStatement("%L", outVar)
-            nextControlFlow("finally")
-            addStatement("%L.close()", statementVar)
-            endControlFlow()
-            endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
index d947e00..dc58000 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
@@ -23,7 +23,8 @@
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.box
 import androidx.room.ext.AndroidTypeNames
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -91,42 +92,24 @@
         inTransaction: Boolean,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                sqlQueryVar, dbProperty, bindStatement, returnTypeName, inTransaction, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                sqlQueryVar, dbProperty, bindStatement, inTransaction, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        returnTypeName: XTypeName,
-        inTransaction: Boolean,
-        scope: CodeGenScope
-    ) {
         val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-            dbProperty,
-            true, // isReadOnly
-            inTransaction,
-            // TODO(b/322387497): Generate lambda syntax if possible
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ true, inTransaction),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = returnTypeName.box()
+                returnTypeName = returnTypeName.box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val outVar = functionScope.getTmpVar("_result")
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val returnPrefix = when (language) {
+                        CodeLanguage.JAVA -> "return "
+                        CodeLanguage.KOTLIN -> ""
+                    }
+                    val statementVar = scope.getTmpVar("_stmt")
                     addLocalVal(
                         statementVar,
                         SQLiteDriverTypeNames.STATEMENT,
@@ -135,52 +118,16 @@
                         sqlQueryVar
                     )
                     beginControlFlow("try")
-                    bindStatement(functionScope, statementVar)
-                    adapter?.convert(outVar, statementVar, functionScope)
-                    addStatement("return %L", outVar)
+                    bindStatement(scope, statementVar)
+                    val outVar = scope.getTmpVar("_result")
+                    adapter?.convert(outVar, statementVar, scope)
+                    addStatement("$returnPrefix%L", outVar)
                     nextControlFlow("finally")
                     addStatement("%L.close()", statementVar)
                     endControlFlow()
-                }.build()
-                this.addCode(functionCode)
+                }
             }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        sqlQueryVar: String,
-        dbProperty: XPropertySpec,
-        bindStatement: CodeGenScope.(String) -> Unit,
-        inTransaction: Boolean,
-        scope: CodeGenScope
-    ) {
-        val connectionVar = scope.getTmpVar("_connection")
-        val statementVar = scope.getTmpVar("_stmt")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-                dbProperty,
-                true, // isReadOnly
-                inTransaction,
-                connectionVar
-            )
-            addLocalVal(
-                statementVar,
-                SQLiteDriverTypeNames.STATEMENT,
-                "%L.prepare(%L)",
-                connectionVar,
-                sqlQueryVar
-            )
-            beginControlFlow("try")
-            bindStatement(scope, statementVar)
-            val outVar = scope.getTmpVar("_result")
-            adapter?.convert(outVar, statementVar, scope)
-            addStatement("%L", outVar)
-            nextControlFlow("finally")
-            addStatement("%L.close()", statementVar)
-            endControlFlow()
-            endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineDeleteOrUpdateMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineDeleteOrUpdateMethodBinder.kt
index 6fd03bf..57a3081 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineDeleteOrUpdateMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineDeleteOrUpdateMethodBinder.kt
@@ -16,13 +16,14 @@
 
 package androidx.room.solver.shortcut.binder
 
-import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeSpec
 import androidx.room.compiler.codegen.box
 import androidx.room.compiler.processing.XType
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -44,80 +45,33 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                parameters, adapters, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                parameters, adapters, dbProperty, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         if (adapter == null) {
             return
         }
         val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            continuationParamName = continuationParamName,
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = adapter.returnType.asTypeName().box()
+                returnTypeName = adapter.returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
                     adapter.generateMethodBody(
-                        scope = functionScope,
+                        scope = scope,
                         parameters = parameters,
                         adapters = adapters,
                         connectionVar = connectionVar
                     )
-                }.build()
-                this.addCode(functionCode)
-            },
-            continuationParamName
+                }
+            }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        if (adapter == null) {
-            return
-        }
-        val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            ).apply {
-                adapter.generateMethodBody(
-                    scope = scope,
-                    parameters = parameters,
-                    adapters = adapters,
-                    connectionVar = connectionVar
-                )
-            }.endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 
     override fun convertAndReturnCompat(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineInsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineInsertMethodBinder.kt
index f1c92ca..aa711af2 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineInsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineInsertMethodBinder.kt
@@ -16,12 +16,13 @@
 
 package androidx.room.solver.shortcut.binder
 
-import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.box
 import androidx.room.compiler.processing.XType
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -43,80 +44,33 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                parameters, adapters, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                parameters, adapters, dbProperty, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         if (adapter == null) {
             return
         }
         val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            continuationParamName = continuationParamName,
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = adapter.returnType.asTypeName().box()
+                returnTypeName = adapter.returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
                     adapter.generateMethodBody(
-                        scope = functionScope,
-                        connectionVar = connectionVar,
+                        scope = scope,
                         parameters = parameters,
-                        adapters = adapters
+                        adapters = adapters,
+                        connectionVar = connectionVar
                     )
-                }.build()
-                this.addCode(functionCode)
-            },
-            continuationParamName
+                }
+            }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        if (adapter == null) {
-            return
-        }
-        val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            ).apply {
-                adapter.generateMethodBody(
-                    scope = scope,
-                    connectionVar = connectionVar,
-                    parameters = parameters,
-                    adapters = adapters
-                )
-            }.endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 
     override fun convertAndReturnCompat(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineUpsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineUpsertMethodBinder.kt
index d820e4d..e572b89e 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineUpsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/CoroutineUpsertMethodBinder.kt
@@ -16,12 +16,13 @@
 
 package androidx.room.solver.shortcut.binder
 
-import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.box
 import androidx.room.compiler.processing.XType
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -43,81 +44,33 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                parameters, adapters, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                parameters, adapters, dbProperty, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         if (adapter == null) {
             return
         }
         val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            continuationParamName = continuationParamName,
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = adapter.returnType.asTypeName().box()
+                returnTypeName = adapter.returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
                     adapter.generateMethodBody(
-                        scope = functionScope,
-                        connectionVar = connectionVar,
+                        scope = scope,
                         parameters = parameters,
-                        adapters = adapters
+                        adapters = adapters,
+                        connectionVar = connectionVar
                     )
-                }.build()
-                this.addCode(functionCode)
-            },
-            continuationParamName
+                }
+            }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        if (adapter == null) {
-            return
-        }
-        val connectionVar = scope.getTmpVar("_connection")
-
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performSuspending"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            ).apply {
-                adapter.generateMethodBody(
-                    scope = scope,
-                    connectionVar = connectionVar,
-                    parameters = parameters,
-                    adapters = adapters
-                )
-            }.endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 
     override fun convertAndReturnCompat(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantDeleteOrUpdateMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantDeleteOrUpdateMethodBinder.kt
index 7ce2c3d..19b8ede 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantDeleteOrUpdateMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantDeleteOrUpdateMethodBinder.kt
@@ -17,11 +17,13 @@
 package androidx.room.solver.shortcut.binder
 
 import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeSpec
 import androidx.room.compiler.codegen.box
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.ext.isNotVoid
@@ -42,81 +44,36 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                parameters, adapters, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                parameters, adapters, dbProperty, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         if (adapter == null) {
             return
         }
-
-        val returnPrefix = if (adapter.returnType.isNotVoid()) { "return " } else { "" }
         val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.addStatement(
-            "$returnPrefix%M(%N, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = adapter.returnType.asTypeName().box()
+                returnTypeName = adapter.returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
                     adapter.generateMethodBody(
-                        scope = functionScope,
+                        scope = scope,
                         parameters = parameters,
                         adapters = adapters,
                         connectionVar = connectionVar
                     )
-                }.build()
-                this.addCode(functionCode)
+                }
             }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        if (adapter == null) {
-            return
+        val returnPrefix = when (scope.language) {
+            CodeLanguage.JAVA -> if (adapter.returnType.isNotVoid()) { "return " } else { "" }
+            CodeLanguage.KOTLIN -> "return "
         }
-        val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            ).apply {
-                adapter.generateMethodBody(
-                    scope = scope,
-                    parameters = parameters,
-                    adapters = adapters,
-                    connectionVar = connectionVar
-                )
-            }.endControlFlow()
-        }
+        scope.builder.add("$returnPrefix%L", performBlock)
     }
 
     override fun convertAndReturnCompat(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt
index ca27b5f..e1a4c9a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantInsertMethodBinder.kt
@@ -17,10 +17,12 @@
 package androidx.room.solver.shortcut.binder
 
 import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.box
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.ext.isNotVoid
@@ -40,81 +42,36 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                parameters, adapters, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                parameters, adapters, dbProperty, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         if (adapter == null) {
             return
         }
-        val returnPrefix = if (adapter.returnType.isNotVoid()) { "return " } else { "" }
-
         val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.addStatement(
-            "$returnPrefix%M(%N, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = adapter.returnType.asTypeName().box()
+                returnTypeName = adapter.returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
                     adapter.generateMethodBody(
-                        scope = functionScope,
-                        connectionVar = connectionVar,
+                        scope = scope,
                         parameters = parameters,
-                        adapters = adapters
+                        adapters = adapters,
+                        connectionVar = connectionVar
                     )
-                }.build()
-                this.addCode(functionCode)
+                }
             }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        if (adapter == null) {
-            return
+        val returnPrefix = when (scope.language) {
+            CodeLanguage.JAVA -> if (adapter.returnType.isNotVoid()) { "return " } else { "" }
+            CodeLanguage.KOTLIN -> "return "
         }
-        val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            ).apply {
-                adapter.generateMethodBody(
-                    scope = scope,
-                    connectionVar = connectionVar,
-                    parameters = parameters,
-                    adapters = adapters
-                )
-            }.endControlFlow()
-        }
+        scope.builder.add("$returnPrefix%L", performBlock)
     }
 
     override fun convertAndReturnCompat(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt
index 244e6c7..4d8be411 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/shortcut/binder/InstantUpsertMethodBinder.kt
@@ -17,10 +17,12 @@
 package androidx.room.solver.shortcut.binder
 
 import androidx.room.compiler.codegen.CodeLanguage
+import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.box
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.ext.isNotVoid
@@ -40,80 +42,36 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> convertAndReturnJava(
-                parameters, adapters, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> convertAndReturnKotlin(
-                parameters, adapters, dbProperty, scope
-            )
-        }
-    }
-
-    private fun convertAndReturnJava(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         if (adapter == null) {
             return
         }
         val connectionVar = scope.getTmpVar("_connection")
-        val returnPrefix = if (adapter.returnType.isNotVoid()) { "return " } else { "" }
-        scope.builder.addStatement(
-            "$returnPrefix%M(%N, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
                 parameterName = connectionVar,
-                returnTypeName = adapter.returnType.asTypeName().box()
+                returnTypeName = adapter.returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                val functionScope = scope.fork()
-                val functionCode = functionScope.builder.apply {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
                     adapter.generateMethodBody(
-                        scope = functionScope,
-                        connectionVar = connectionVar,
+                        scope = scope,
                         parameters = parameters,
-                        adapters = adapters
+                        adapters = adapters,
+                        connectionVar = connectionVar
                     )
-                }.build()
-                this.addCode(functionCode)
+                }
             }
         )
-    }
-
-    private fun convertAndReturnKotlin(
-        parameters: List<ShortcutQueryParameter>,
-        adapters: Map<String, Pair<XPropertySpec, Any>>,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        if (adapter == null) {
-            return
+        val returnPrefix = when (scope.language) {
+            CodeLanguage.JAVA -> if (adapter.returnType.isNotVoid()) { "return " } else { "" }
+            CodeLanguage.KOTLIN -> "return "
         }
-        val connectionVar = scope.getTmpVar("_connection")
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) { %L ->",
-                RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-                connectionVar
-            ).apply {
-                adapter.generateMethodBody(
-                    scope = scope,
-                    connectionVar = connectionVar,
-                    parameters = parameters,
-                    adapters = adapters
-                )
-            }.endControlFlow()
-        }
+        scope.builder.add("$returnPrefix%L", performBlock)
     }
 
     override fun convertAndReturnCompat(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/CoroutineTransactionMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/CoroutineTransactionMethodBinder.kt
index bcaf3e3..62ce592 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/CoroutineTransactionMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/CoroutineTransactionMethodBinder.kt
@@ -19,13 +19,13 @@
 import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.codegen.XCodeBlock
-import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.addStatement
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.processing.XType
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
 import androidx.room.ext.KotlinTypeNames
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.solver.CodeGenScope
 import androidx.room.solver.transaction.result.TransactionMethodAdapter
@@ -36,8 +36,7 @@
 class CoroutineTransactionMethodBinder(
     private val returnType: XType,
     adapter: TransactionMethodAdapter,
-    private val continuationParamName: String,
-    private val javaLambdaSyntaxAvailable: Boolean
+    private val continuationParamName: String
 ) : TransactionMethodBinder(adapter) {
     override fun executeAndReturn(
         parameterNames: List<String>,
@@ -46,81 +45,40 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> executeAndReturnJava(
-                parameterNames, daoName, daoImplName, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> executeAndReturnKotlin(
-                parameterNames, daoName, daoImplName, dbProperty, scope
-            )
-        }
-    }
-
-    private fun executeAndReturnJava(
-        parameterNames: List<String>,
-        daoName: XClassName,
-        daoImplName: XClassName,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
         val innerContinuationParamName = scope.getTmpVar("_cont")
-        val adapterScope = scope.fork()
-        adapter.createDelegateToSuperCode(
-            parameterNames = parameterNames + innerContinuationParamName,
-            daoName = daoName,
-            daoImplName = daoImplName,
-            scope = adapterScope
-        )
-        val functionImpl: Any = if (javaLambdaSyntaxAvailable) {
-            XCodeBlock.of(
-                scope.language,
-                "(%L) -> %L",
-                innerContinuationParamName, adapterScope.generate()
-            )
-        } else {
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performInTransactionSuspending"),
+            argFormat = listOf("%N"),
+            args = listOf(dbProperty),
+            continuationParamName = continuationParamName,
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = KotlinTypeNames.CONTINUATION.parametrizedBy(
                     XTypeName.getConsumerSuperName(returnType.asTypeName())
                 ),
                 parameterName = innerContinuationParamName,
-                returnTypeName = KotlinTypeNames.ANY
+                returnTypeName = KotlinTypeNames.ANY,
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                addStatement("return %L", adapterScope.generate())
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val adapterScope = scope.fork()
+                    adapter.createDelegateToSuperCode(
+                        parameterNames = when (scope.language) {
+                            CodeLanguage.JAVA -> parameterNames + innerContinuationParamName
+                            CodeLanguage.KOTLIN -> parameterNames
+                        },
+                        daoName = daoName,
+                        daoImplName = daoImplName,
+                        scope = adapterScope
+                    )
+                    val returnPrefix = when (scope.language) {
+                        CodeLanguage.JAVA -> "return "
+                        CodeLanguage.KOTLIN -> ""
+                    }
+                    addStatement("$returnPrefix%L", adapterScope.generate())
+                }
             }
-        }
-
-        scope.builder.addStatement(
-            "return %M(%N, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performInTransactionSuspending"),
-            dbProperty,
-            functionImpl,
-            continuationParamName
         )
-    }
-
-    private fun executeAndReturnKotlin(
-        parameterNames: List<String>,
-        daoName: XClassName,
-        daoImplName: XClassName,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N) {",
-                RoomTypeNames.DB_UTIL.packageMember("performInTransactionSuspending"),
-                dbProperty,
-            )
-            val adapterScope = scope.fork()
-            adapter.createDelegateToSuperCode(
-                parameterNames = parameterNames,
-                daoName = daoName,
-                daoImplName = daoImplName,
-                scope = adapterScope
-            )
-            addStatement("%L", adapterScope.generate())
-            endControlFlow()
-        }
+        scope.builder.add("return %L", performBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/InstantTransactionMethodBinder.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/InstantTransactionMethodBinder.kt
index ad1e9b3..c458972 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/InstantTransactionMethodBinder.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/transaction/binder/InstantTransactionMethodBinder.kt
@@ -19,15 +19,15 @@
 import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.codegen.XCodeBlock
-import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.addStatement
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XPropertySpec
 import androidx.room.compiler.codegen.box
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.isKotlinUnit
 import androidx.room.compiler.processing.isVoid
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
 import androidx.room.ext.KotlinTypeNames
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.SQLiteDriverTypeNames
 import androidx.room.solver.CodeGenScope
@@ -39,7 +39,6 @@
 class InstantTransactionMethodBinder(
     private val returnType: XType,
     adapter: TransactionMethodAdapter,
-    private val javaLambdaSyntaxAvailable: Boolean
 ) : TransactionMethodBinder(adapter) {
     override fun executeAndReturn(
         parameterNames: List<String>,
@@ -48,88 +47,47 @@
         dbProperty: XPropertySpec,
         scope: CodeGenScope
     ) {
-        when (scope.language) {
-            CodeLanguage.JAVA -> executeAndReturnJava(
-                parameterNames, daoName, daoImplName, dbProperty, scope
-            )
-            CodeLanguage.KOTLIN -> executeAndReturnKotlin(
-                parameterNames, daoName, daoImplName, dbProperty, scope
-            )
+        val returnPrefix = when (scope.language) {
+            CodeLanguage.JAVA ->
+                if (returnType.isVoid() || returnType.isKotlinUnit()) "" else "return "
+            CodeLanguage.KOTLIN -> "return "
         }
-    }
-
-    private fun executeAndReturnJava(
-        parameterNames: List<String>,
-        daoName: XClassName,
-        daoImplName: XClassName,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        val adapterScope = scope.fork()
-        val returnPrefix = if (returnType.isVoid() || returnType.isKotlinUnit()) "" else "return "
-        adapter.createDelegateToSuperCode(
-            parameterNames = parameterNames,
-            daoName = daoName,
-            daoImplName = daoImplName,
-            scope = adapterScope
-        )
-        val connectionVar = scope.getTmpVar("_connection")
-        val functionImpl: Any = if (javaLambdaSyntaxAvailable) {
-            XCodeBlock.builder(scope.language).apply {
-                add("(%L) -> {\n", connectionVar)
-                add("%>$returnPrefix%L;\n", adapterScope.generate())
-                if (returnPrefix.isEmpty()) {
-                    add("return %T.INSTANCE;\n", KotlinTypeNames.UNIT)
-                }
-                add("%<}")
-            }.build()
-        } else {
-            Function1TypeSpec(
-                language = scope.language,
+        val performBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
+            argFormat = listOf("%N", "%L", "%L"),
+            args = listOf(dbProperty, /* isReadOnly = */ false, /* inTransaction = */ true),
+            lambdaSpec = object : LambdaSpec(
                 parameterTypeName = SQLiteDriverTypeNames.CONNECTION,
-                parameterName = connectionVar,
-                returnTypeName = returnType.asTypeName().box()
+                parameterName = when (scope.language) {
+                    CodeLanguage.JAVA -> scope.getTmpVar("_connection")
+                    CodeLanguage.KOTLIN -> "_"
+                },
+                returnTypeName = returnType.asTypeName().box(),
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
             ) {
-                this.addStatement("$returnPrefix%L", adapterScope.generate())
-                if (returnPrefix.isEmpty()) {
-                    addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT)
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val adapterScope = scope.fork()
+                    adapter.createDelegateToSuperCode(
+                        parameterNames = parameterNames,
+                        daoName = daoName,
+                        daoImplName = daoImplName,
+                        scope = adapterScope
+                    )
+                    when (scope.language) {
+                        CodeLanguage.JAVA -> {
+                            addStatement("$returnPrefix%L", adapterScope.generate())
+                            if (returnPrefix.isEmpty()) {
+                                addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT)
+                            }
+                        }
+                        CodeLanguage.KOTLIN -> {
+                            addStatement("%L", adapterScope.generate())
+                        }
+                    }
                 }
             }
-        }
-        scope.builder.addStatement(
-            "$returnPrefix%M(%N, %L, %L, %L)",
-            RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-            dbProperty,
-            false, // isReadOnly
-            true, // inTransaction
-            functionImpl
         )
-    }
-
-    private fun executeAndReturnKotlin(
-        parameterNames: List<String>,
-        daoName: XClassName,
-        daoImplName: XClassName,
-        dbProperty: XPropertySpec,
-        scope: CodeGenScope
-    ) {
-        scope.builder.apply {
-            beginControlFlow(
-                "return %M(%N, %L, %L) {",
-                RoomTypeNames.DB_UTIL.packageMember("performBlocking"),
-                dbProperty,
-                false, // isReadOnly
-                true, // inTransaction
-            )
-            val adapterScope = scope.fork()
-            adapter.createDelegateToSuperCode(
-                parameterNames = parameterNames,
-                daoName = daoName,
-                daoImplName = daoImplName,
-                scope = adapterScope
-            )
-            addStatement("%L", adapterScope.generate())
-            endControlFlow()
-        }
+        scope.builder.add("$returnPrefix%L", performBlock)
     }
 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
index e005bed..ba77eb5 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
@@ -77,8 +77,7 @@
     // parsed relating entity query
     val loadAllQuery: ParsedQuery,
     // true if `relationTypeName` is a Collection, when it is `relationTypeName` is always non null.
-    val relationTypeIsCollection: Boolean,
-    val javaLambdaSyntaxAvailable: Boolean
+    val relationTypeIsCollection: Boolean
 ) {
     // TODO(b/319660042): Remove once migration to driver API is done.
     fun isMigratedToDriver(): Boolean = rowAdapter.isMigratedToDriver()
@@ -492,8 +491,7 @@
                         entityKeyColumnReader = entityKeyColumnReader,
                         rowAdapter = rowAdapter,
                         loadAllQuery = parsedQuery,
-                        relationTypeIsCollection = isRelationCollection,
-                        javaLambdaSyntaxAvailable = context.processingEnv.jvmVersion >= 8
+                        relationTypeIsCollection = isRelationCollection
                     )
                 }
             }.filterNotNull()
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
index ab93879..1ddb717 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
@@ -38,10 +38,11 @@
  * Writes the implementation of migrations that were annotated with @AutoMigration.
  */
 class AutoMigrationWriter(
+    private val autoMigration: AutoMigration,
     private val dbElement: XTypeElement,
-    val autoMigration: AutoMigration,
-    codeLanguage: CodeLanguage
-) : TypeWriter(codeLanguage) {
+    codeLanguage: CodeLanguage,
+    javaLambdaSyntaxAvailable: Boolean
+) : TypeWriter(codeLanguage, javaLambdaSyntaxAvailable) {
     private val addedColumns = autoMigration.schemaDiff.addedColumns
     private val addedTables = autoMigration.schemaDiff.addedTables
     private val renamedTables = autoMigration.schemaDiff.renamedTables
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index 7a610ad..352ab40 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -65,8 +65,9 @@
 class DaoWriter(
     val dao: Dao,
     private val dbElement: XElement,
-    codeLanguage: CodeLanguage
-) : TypeWriter(codeLanguage) {
+    codeLanguage: CodeLanguage,
+    javaLambdaSyntaxAvailable: Boolean
+) : TypeWriter(codeLanguage, javaLambdaSyntaxAvailable) {
     private val declaredDao = dao.element.type
 
     // TODO nothing prevents this from conflicting, we should fix.
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
index 82bd6f6..44206f5 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
@@ -44,8 +44,9 @@
  */
 class DatabaseWriter(
     val database: Database,
-    codeLanguage: CodeLanguage
-) : TypeWriter(codeLanguage) {
+    codeLanguage: CodeLanguage,
+    javaLambdaSyntaxAvailable: Boolean
+) : TypeWriter(codeLanguage, javaLambdaSyntaxAvailable) {
     override fun createTypeSpecBuilder(): XTypeSpec.Builder {
         return XTypeSpec.classBuilder(codeLanguage, database.implTypeName).apply {
             addOriginatingElement(database.element)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt
index 3c63ece..eb0d29c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/RelationCollectorFunctionWriter.kt
@@ -20,15 +20,15 @@
 import androidx.room.compiler.codegen.XCodeBlock
 import androidx.room.compiler.codegen.XCodeBlock.Builder.Companion.addLocalVal
 import androidx.room.compiler.codegen.XFunSpec
-import androidx.room.compiler.codegen.XFunSpec.Builder.Companion.addStatement
 import androidx.room.compiler.codegen.XMemberName.Companion.packageMember
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.ext.AndroidTypeNames
 import androidx.room.ext.CollectionTypeNames
 import androidx.room.ext.CollectionsSizeExprCode
 import androidx.room.ext.CommonTypeNames
-import androidx.room.ext.Function1TypeSpec
+import androidx.room.ext.InvokeWithLambdaParameter
 import androidx.room.ext.KotlinTypeNames
+import androidx.room.ext.LambdaSpec
 import androidx.room.ext.MapKeySetExprCode
 import androidx.room.ext.RoomMemberNames
 import androidx.room.ext.RoomTypeNames
@@ -101,7 +101,7 @@
                     )
                 }
             ).apply {
-                addRecursiveFetchCall(methodName)
+                addRecursiveFetchCall(scope, methodName)
                 addStatement("return")
             }.endControlFlow()
 
@@ -258,21 +258,10 @@
         endControlFlow()
     }
 
-    private fun XCodeBlock.Builder.addRecursiveFetchCall(methodName: String) {
-        fun getRecursiveCall(itVarName: String) =
-            if (useDriverApi) {
-                XCodeBlock.of(
-                    language,
-                    "%L(%L, %L)",
-                    methodName, PARAM_CONNECTION_VARIABLE, itVarName
-                )
-            } else {
-                XCodeBlock.of(
-                    language,
-                    "%L(%L)",
-                    methodName, itVarName
-                )
-            }
+    private fun XCodeBlock.Builder.addRecursiveFetchCall(
+        scope: CodeGenScope,
+        methodName: String,
+    ) {
         val utilFunction =
             RELATION_UTIL.let {
                 when {
@@ -280,54 +269,45 @@
                         it.packageMember("recursiveFetchLongSparseArray")
                     usingArrayMap ->
                         it.packageMember("recursiveFetchArrayMap")
-                    language == CodeLanguage.JAVA ->
-                        it.packageMember("recursiveFetchHashMap")
-                    language == CodeLanguage.JAVA ->
-                        it.packageMember("recursiveFetchHashMap")
                     else -> when (language) {
                         CodeLanguage.JAVA -> it.packageMember("recursiveFetchHashMap")
                         CodeLanguage.KOTLIN -> it.packageMember("recursiveFetchMap")
                     }
                 }
             }
-        when (language) {
-            CodeLanguage.JAVA -> {
-                val paramName = "map"
-                if (collector.javaLambdaSyntaxAvailable) {
-                    add("%M(%L, %L, (%L) -> {\n",
-                        utilFunction, PARAM_MAP_VARIABLE, collector.relationTypeIsCollection,
-                        paramName
-                    )
-                    indent()
-                    addStatement("%L", getRecursiveCall(paramName))
-                    addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT)
-                    unindent()
-                    addStatement("})")
-                } else {
-                    val functionImpl = Function1TypeSpec(
-                        language = language,
-                        parameterTypeName = collector.mapTypeName,
-                        parameterName = paramName,
-                        returnTypeName = KotlinTypeNames.UNIT,
-                    ) {
-                        addStatement("%L", getRecursiveCall(paramName))
+        val paramName = scope.getTmpVar("_tmpMap")
+        val recursiveFetchBlock = InvokeWithLambdaParameter(
+            scope = scope,
+            functionName = utilFunction,
+            argFormat = listOf("%L", "%L"),
+            args = listOf(PARAM_MAP_VARIABLE, collector.relationTypeIsCollection),
+            lambdaSpec = object : LambdaSpec(
+                parameterTypeName = collector.mapTypeName,
+                parameterName = paramName,
+                returnTypeName = KotlinTypeNames.UNIT,
+                javaLambdaSyntaxAvailable = scope.javaLambdaSyntaxAvailable
+            ) {
+                override fun XCodeBlock.Builder.body(scope: CodeGenScope) {
+                    val recursiveCall = if (useDriverApi) {
+                        XCodeBlock.of(
+                            language,
+                            "%L(%L, %L)",
+                            methodName, PARAM_CONNECTION_VARIABLE, paramName
+                        )
+                    } else {
+                        XCodeBlock.of(
+                            language,
+                            "%L(%L)",
+                            methodName, paramName
+                        )
+                    }
+                    addStatement("%L", recursiveCall)
+                    if (language == CodeLanguage.JAVA) {
                         addStatement("return %T.INSTANCE", KotlinTypeNames.UNIT)
                     }
-                    addStatement(
-                        "%M(%L, %L, %L)",
-                        utilFunction, PARAM_MAP_VARIABLE, collector.relationTypeIsCollection,
-                        functionImpl
-                    )
                 }
             }
-            CodeLanguage.KOTLIN -> {
-                beginControlFlow(
-                    "%M(%L, %L)",
-                    utilFunction, PARAM_MAP_VARIABLE, collector.relationTypeIsCollection
-                )
-                addStatement("%L", getRecursiveCall("it"))
-                endControlFlow()
-            }
-        }
+        )
+        add("%L", recursiveFetchBlock)
     }
 }
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 96c64dc..1700a64 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
@@ -36,7 +36,10 @@
 /**
  * Base class for all writers that can produce a class.
  */
-abstract class TypeWriter(val codeLanguage: CodeLanguage) {
+abstract class TypeWriter(
+    val codeLanguage: CodeLanguage,
+    val javaLambdaSyntaxAvailable: Boolean,
+) {
     private val sharedFieldSpecs = mutableMapOf<String, XPropertySpec>()
     private val sharedMethodSpecs = mutableMapOf<String, XFunSpec>()
     private val sharedFieldNames = mutableSetOf<String>()
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseDaoTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseDaoTest.kt
index 2f432e3..a680f2d 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseDaoTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/BaseDaoTest.kt
@@ -219,7 +219,7 @@
                 val processed = DaoProcessor(
                     invocation.context, dao, dbType, null
                 ).process()
-                DaoWriter(processed, dbElm, CodeLanguage.JAVA)
+                DaoWriter(processed, dbElm, CodeLanguage.JAVA, false)
                     .write(invocation.processingEnv)
             }
         }
@@ -270,7 +270,8 @@
                 invocation.context, daoElm, dbType, null
             ).process()
             handler(processedDao)
-            DaoWriter(processedDao, dbElm, CodeLanguage.JAVA).write(invocation.processingEnv)
+            DaoWriter(processedDao, dbElm, CodeLanguage.JAVA, false)
+                .write(invocation.processingEnv)
         }
     }
 }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/solver/NullabilityAwareTypeConverterStoreTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/solver/NullabilityAwareTypeConverterStoreTest.kt
index 997f6d3..d8a127c 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/solver/NullabilityAwareTypeConverterStoreTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/solver/NullabilityAwareTypeConverterStoreTest.kt
@@ -402,7 +402,8 @@
                 dao = daoProcessor.process(),
                 dbElement = invocation.processingEnv
                     .requireTypeElement("androidx.room.RoomDatabase"),
-                codeLanguage = CodeLanguage.JAVA
+                codeLanguage = CodeLanguage.JAVA,
+                javaLambdaSyntaxAvailable = false
             ).write(invocation.processingEnv)
             invocation.assertCompilationResult {
                 generatedSourceFileWithPath("MyDao_Impl.java").let {
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt b/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
index 5c4d981..2a63f03 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
@@ -332,7 +332,7 @@
 
 fun testCodeGenScope(): CodeGenScope {
     return CodeGenScope(
-        object : TypeWriter(CodeLanguage.JAVA) {
+        object : TypeWriter(CodeLanguage.JAVA, true) {
             override fun createTypeSpecBuilder(): XTypeSpec.Builder {
                 return XTypeSpec.classBuilder(codeLanguage, XClassName.get("test", "Foo"))
             }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
index e541095..298b09e 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
@@ -111,9 +111,11 @@
                 isSpecProvided = false
             )
             AutoMigrationWriter(
-                invocation.processingEnv.requireTypeElement("foo.bar.MyDatabase"),
-                autoMigrationResultWithNewAddedColumn,
-                codeLanguage
+                autoMigration = autoMigrationResultWithNewAddedColumn,
+                dbElement =
+                    invocation.processingEnv.requireTypeElement("foo.bar.MyDatabase"),
+                codeLanguage = codeLanguage,
+                javaLambdaSyntaxAvailable = false
             ).write(invocation.processingEnv)
 
             val expectedFile = when (codeLanguage) {
@@ -185,9 +187,11 @@
                 isSpecProvided = false
             )
             AutoMigrationWriter(
-                invocation.processingEnv.requireTypeElement("foo.bar.MyDatabase"),
-                autoMigrationResultWithNewAddedColumn,
-                codeLanguage
+                autoMigration = autoMigrationResultWithNewAddedColumn,
+                dbElement =
+                    invocation.processingEnv.requireTypeElement("foo.bar.MyDatabase"),
+                codeLanguage = codeLanguage,
+                javaLambdaSyntaxAvailable = false
             ).write(invocation.processingEnv)
 
             val expectedFile = when (codeLanguage) {
@@ -267,9 +271,11 @@
                 isSpecProvided = true
             )
             AutoMigrationWriter(
-                invocation.processingEnv.requireTypeElement("foo.bar.MyDatabase"),
-                autoMigrationResultWithNewAddedColumn,
-                codeLanguage
+                autoMigration = autoMigrationResultWithNewAddedColumn,
+                dbElement =
+                    invocation.processingEnv.requireTypeElement("foo.bar.MyDatabase"),
+                codeLanguage = codeLanguage,
+                javaLambdaSyntaxAvailable = false
             ).write(invocation.processingEnv)
 
             val expectedFile = when (codeLanguage) {
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 ca06c0c..7643c91 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
@@ -25,18 +25,19 @@
 import androidx.room.ext.RoomTypeNames.ROOM_DB
 import androidx.room.processor.DaoProcessor
 import androidx.room.testing.context
+import com.google.testing.junit.testparameterinjector.TestParameter
+import com.google.testing.junit.testparameterinjector.TestParameterInjector
 import createVerifierFromEntitiesAndViews
 import java.util.Locale
 import loadTestSource
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import writeTestSource
 
-@RunWith(JUnit4::class)
+@RunWith(TestParameterInjector::class)
 class DaoWriterTest {
     @Test
-    fun complexDao() {
+    fun complexDao(@TestParameter javaLambdaSyntaxAvailable: Boolean) {
         singleDao(
             loadTestSource(
                 fileName = "databasewriter/input/ComplexDatabase.java",
@@ -46,6 +47,7 @@
                 fileName = "daoWriter/input/ComplexDao.java",
                 qName = "foo.bar.ComplexDao"
             ),
+            javaLambdaSyntaxAvailable = javaLambdaSyntaxAvailable,
             outputFileName = "ComplexDao.java"
         )
     }
@@ -55,58 +57,63 @@
         val originalLocale = Locale.getDefault()
         try {
             Locale.setDefault(Locale("tr")) // Turkish has special upper/lowercase i chars
-            complexDao()
+            complexDao(false)
         } finally {
             Locale.setDefault(originalLocale)
         }
     }
 
     @Test
-    fun writerDao() {
+    fun writerDao(@TestParameter javaLambdaSyntaxAvailable: Boolean) {
         singleDao(
             loadTestSource(
                 fileName = "daoWriter/input/WriterDao.java",
                 qName = "foo.bar.WriterDao"
             ),
+            javaLambdaSyntaxAvailable = javaLambdaSyntaxAvailable,
             outputFileName = "WriterDao.java"
         )
     }
 
     @Test
-    fun deletionDao() {
+    fun deletionDao(@TestParameter javaLambdaSyntaxAvailable: Boolean) {
         singleDao(
             loadTestSource(
                 fileName = "daoWriter/input/DeletionDao.java",
                 qName = "foo.bar.DeletionDao"
             ),
+            javaLambdaSyntaxAvailable = javaLambdaSyntaxAvailable,
             outputFileName = "DeletionDao.java"
         )
     }
 
     @Test
-    fun updateDao() {
+    fun updateDao(@TestParameter javaLambdaSyntaxAvailable: Boolean) {
         singleDao(
             loadTestSource(
                 fileName = "daoWriter/input/UpdateDao.java",
                 qName = "foo.bar.UpdateDao"
             ),
+            javaLambdaSyntaxAvailable = javaLambdaSyntaxAvailable,
             outputFileName = "UpdateDao.java"
         )
     }
 
     @Test
-    fun upsertDao() {
+    fun upsertDao(@TestParameter javaLambdaSyntaxAvailable: Boolean) {
         singleDao(
             loadTestSource(
                 fileName = "daoWriter/input/UpsertDao.java",
                 qName = "foo.bar.UpsertDao"
             ),
+            javaLambdaSyntaxAvailable = javaLambdaSyntaxAvailable,
             outputFileName = "UpsertDao.java"
         )
     }
 
     private fun singleDao(
         vararg inputs: Source,
+        javaLambdaSyntaxAvailable: Boolean = false,
         outputFileName: String,
         handler: (XTestInvocation) -> Unit = { }
     ) {
@@ -122,6 +129,10 @@
         runProcessorTest(
             sources = sources
         ) { invocation ->
+            if (invocation.isKsp && !javaLambdaSyntaxAvailable) {
+                // Skip KSP backend without lambda syntax, it is a nonsensical combination.
+                return@runProcessorTest
+            }
             val dao = invocation.roundEnv
                 .getElementsAnnotatedWith(
                     androidx.room.Dao::class.qualifiedName!!
@@ -143,9 +154,9 @@
                     dbVerifier = dbVerifier
                 )
                 val parsedDao = parser.process()
-                DaoWriter(parsedDao, db, CodeLanguage.JAVA)
+                DaoWriter(parsedDao, db, CodeLanguage.JAVA, javaLambdaSyntaxAvailable)
                     .write(invocation.processingEnv)
-                val outputSubFolder = outputFolder(invocation)
+                val outputSubFolder = outputFolder(invocation, javaLambdaSyntaxAvailable)
                 invocation.assertCompilationResult {
                     val expectedFilePath = "daoWriter/output/$outputSubFolder/$outputFileName"
                     val expectedSrc = loadTestSource(
@@ -171,7 +182,14 @@
 
     private fun outputFolder(
         invocation: XTestInvocation,
+        javaLambdaSyntaxAvailable: Boolean
     ): String {
-        return invocation.processingEnv.backend.name.lowercase()
+        val backendFolder = invocation.processingEnv.backend.name.lowercase()
+        val lambdaFolder = if (javaLambdaSyntaxAvailable) "withLambda" else "withoutLambda"
+        if (invocation.isKsp) {
+            return backendFolder
+        } else {
+            return "$backendFolder/$lambdaFolder"
+        }
     }
 }
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 1ca847b..5600862 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
@@ -195,7 +195,7 @@
                         dbVerifier = createVerifierFromEntitiesAndViews(invocation)
                     )
                     val parsedDao = parser.process()
-                    DaoWriter(parsedDao, db, CodeLanguage.JAVA)
+                    DaoWriter(parsedDao, db, CodeLanguage.JAVA, true)
                         .write(invocation.processingEnv)
                     invocation.assertCompilationResult {
                         val relativePath =
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/EntityCursorConverterWriterTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/EntityCursorConverterWriterTest.kt
index b0e8158..76d5b76 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/EntityCursorConverterWriterTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/EntityCursorConverterWriterTest.kt
@@ -122,7 +122,7 @@
     ) {
         singleEntity(input) { entity, invocation ->
             val className = XClassName.get("foo.bar", "MyContainerClass")
-            val writer = object : TypeWriter(CodeLanguage.JAVA) {
+            val writer = object : TypeWriter(CodeLanguage.JAVA, true) {
                 override fun createTypeSpecBuilder(): XTypeSpec.Builder {
                     getOrCreateFunction(EntityCursorConverterWriter(entity))
                     return XTypeSpec.classBuilder(codeLanguage, className)
diff --git a/room/room-compiler/src/test/test-data/daoWriter/input/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/input/UpdateDao.java
index 226dcccc..317c7cc 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/input/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/input/UpdateDao.java
@@ -69,10 +69,4 @@
 
     @Query("UPDATE User SET ageColumn = ageColumn + 1")
     Maybe<Integer> ageUserAllMaybe();
-
-    @Transaction
-    default void updateAndAge(User user) {
-        updateUser(user);
-        ageUserByUid(String.valueOf(user.uid));
-    }
 }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/ComplexDao.java
new file mode 100644
index 0000000..064c6a6
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/ComplexDao.java
@@ -0,0 +1,713 @@
+package foo.bar;
+
+import android.database.Cursor;
+import android.os.CancellationSignal;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LiveData;
+import androidx.room.RoomDatabase;
+import androidx.room.RoomSQLiteQuery;
+import androidx.room.guava.GuavaRoom;
+import androidx.room.util.CursorUtil;
+import androidx.room.util.DBUtil;
+import androidx.room.util.SQLiteStatementUtil;
+import androidx.room.util.StringUtil;
+import androidx.sqlite.SQLiteStatement;
+import androidx.sqlite.db.SupportSQLiteQuery;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.Class;
+import java.lang.Exception;
+import java.lang.Integer;
+import java.lang.Override;
+import java.lang.String;
+import java.lang.StringBuilder;
+import java.lang.SuppressWarnings;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation", "removal"})
+public final class ComplexDao_Impl extends ComplexDao {
+  private final RoomDatabase __db;
+
+  public ComplexDao_Impl(final ComplexDatabase __db) {
+    super(__db);
+    this.__db = __db;
+  }
+
+  @Override
+  public boolean transactionMethod(final int i, final String s, final long l) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      return ComplexDao_Impl.super.transactionMethod(i, s, l);
+    });
+  }
+
+  @Override
+  public List<ComplexDao.FullName> fullNames(final int id) {
+    final String _sql = "SELECT name || lastName as fullName, uid as id FROM user where uid = ?";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, id);
+        final int _cursorIndexOfFullName = 0;
+        final int _cursorIndexOfId = 1;
+        final List<ComplexDao.FullName> _result = new ArrayList<ComplexDao.FullName>();
+        while (_stmt.step()) {
+          final ComplexDao.FullName _item;
+          _item = new ComplexDao.FullName();
+          if (_stmt.isNull(_cursorIndexOfFullName)) {
+            _item.fullName = null;
+          } else {
+            _item.fullName = _stmt.getText(_cursorIndexOfFullName);
+          }
+          _item.id = (int) (_stmt.getLong(_cursorIndexOfId));
+          _result.add(_item);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public User getById(final int id) {
+    final String _sql = "SELECT * FROM user where uid = ?";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, id);
+        final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
+        final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
+        final User _result;
+        if (_stmt.step()) {
+          _result = new User();
+          _result.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          if (_stmt.isNull(_cursorIndexOfName)) {
+            _result.name = null;
+          } else {
+            _result.name = _stmt.getText(_cursorIndexOfName);
+          }
+          final String _tmpLastName;
+          if (_stmt.isNull(_cursorIndexOfLastName)) {
+            _tmpLastName = null;
+          } else {
+            _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
+          }
+          _result.setLastName(_tmpLastName);
+          _result.age = (int) (_stmt.getLong(_cursorIndexOfAge));
+        } else {
+          _result = null;
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public User findByName(final String name, final String lastName) {
+    final String _sql = "SELECT * FROM user where name LIKE ? AND lastName LIKE ?";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (name == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          _stmt.bindText(_argIndex, name);
+        }
+        _argIndex = 2;
+        if (lastName == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          _stmt.bindText(_argIndex, lastName);
+        }
+        final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
+        final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
+        final User _result;
+        if (_stmt.step()) {
+          _result = new User();
+          _result.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          if (_stmt.isNull(_cursorIndexOfName)) {
+            _result.name = null;
+          } else {
+            _result.name = _stmt.getText(_cursorIndexOfName);
+          }
+          final String _tmpLastName;
+          if (_stmt.isNull(_cursorIndexOfLastName)) {
+            _tmpLastName = null;
+          } else {
+            _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
+          }
+          _result.setLastName(_tmpLastName);
+          _result.age = (int) (_stmt.getLong(_cursorIndexOfAge));
+        } else {
+          _result = null;
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public List<User> loadAllByIds(final int... ids) {
+    final StringBuilder _stringBuilder = new StringBuilder();
+    _stringBuilder.append("SELECT * FROM user where uid IN (");
+    final int _inputSize = ids == null ? 1 : ids.length;
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
+    _stringBuilder.append(")");
+    final String _sql = _stringBuilder.toString();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item : ids) {
+            _stmt.bindLong(_argIndex, _item);
+            _argIndex++;
+          }
+        }
+        final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
+        final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
+        final List<User> _result = new ArrayList<User>();
+        while (_stmt.step()) {
+          final User _item_1;
+          _item_1 = new User();
+          _item_1.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          if (_stmt.isNull(_cursorIndexOfName)) {
+            _item_1.name = null;
+          } else {
+            _item_1.name = _stmt.getText(_cursorIndexOfName);
+          }
+          final String _tmpLastName;
+          if (_stmt.isNull(_cursorIndexOfLastName)) {
+            _tmpLastName = null;
+          } else {
+            _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
+          }
+          _item_1.setLastName(_tmpLastName);
+          _item_1.age = (int) (_stmt.getLong(_cursorIndexOfAge));
+          _result.add(_item_1);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  int getAge(final int id) {
+    final String _sql = "SELECT ageColumn FROM user where uid = ?";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, id);
+        final int _result;
+        if (_stmt.step()) {
+          _result = (int) (_stmt.getLong(0));
+        } else {
+          _result = 0;
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public int[] getAllAges(final int... ids) {
+    final StringBuilder _stringBuilder = new StringBuilder();
+    _stringBuilder.append("SELECT ageColumn FROM user where uid IN(");
+    final int _inputSize = ids == null ? 1 : ids.length;
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
+    _stringBuilder.append(")");
+    final String _sql = _stringBuilder.toString();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item : ids) {
+            _stmt.bindLong(_argIndex, _item);
+            _argIndex++;
+          }
+        }
+        final List<Integer> _listResult = new ArrayList<Integer>();
+        while (_stmt.step()) {
+          final Integer _item_1;
+          if (_stmt.isNull(0)) {
+            _item_1 = null;
+          } else {
+            _item_1 = (int) (_stmt.getLong(0));
+          }
+          _listResult.add(_item_1);
+        }
+        final int[] _tmpArrayResult = new int[_listResult.size()];
+        int _index = 0;
+        for (int _listItem : _listResult) {
+          _tmpArrayResult[_index] = _listItem;
+          _index++;
+        }
+        final int[] _result = _tmpArrayResult;
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public List<Integer> getAllAgesAsList(final List<Integer> ids) {
+    final StringBuilder _stringBuilder = new StringBuilder();
+    _stringBuilder.append("SELECT ageColumn FROM user where uid IN(");
+    final int _inputSize = ids == null ? 1 : ids.size();
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
+    _stringBuilder.append(")");
+    final String _sql = _stringBuilder.toString();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (Integer _item : ids) {
+            if (_item == null) {
+              _stmt.bindNull(_argIndex);
+            } else {
+              _stmt.bindLong(_argIndex, _item);
+            }
+            _argIndex++;
+          }
+        }
+        final List<Integer> _result = new ArrayList<Integer>();
+        while (_stmt.step()) {
+          final Integer _item_1;
+          if (_stmt.isNull(0)) {
+            _item_1 = null;
+          } else {
+            _item_1 = (int) (_stmt.getLong(0));
+          }
+          _result.add(_item_1);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public List<Integer> getAllAgesAsList(final List<Integer> ids1, final int[] ids2,
+      final int... ids3) {
+    final StringBuilder _stringBuilder = new StringBuilder();
+    _stringBuilder.append("SELECT ageColumn FROM user where uid IN(");
+    final int _inputSize = ids1 == null ? 1 : ids1.size();
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
+    _stringBuilder.append(") OR uid IN (");
+    final int _inputSize_1 = ids2 == null ? 1 : ids2.length;
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize_1);
+    _stringBuilder.append(") OR uid IN (");
+    final int _inputSize_2 = ids3 == null ? 1 : ids3.length;
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize_2);
+    _stringBuilder.append(")");
+    final String _sql = _stringBuilder.toString();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids1 == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (Integer _item : ids1) {
+            if (_item == null) {
+              _stmt.bindNull(_argIndex);
+            } else {
+              _stmt.bindLong(_argIndex, _item);
+            }
+            _argIndex++;
+          }
+        }
+        _argIndex = 1 + _inputSize;
+        if (ids2 == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item_1 : ids2) {
+            _stmt.bindLong(_argIndex, _item_1);
+            _argIndex++;
+          }
+        }
+        _argIndex = 1 + _inputSize + _inputSize_1;
+        if (ids3 == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item_2 : ids3) {
+            _stmt.bindLong(_argIndex, _item_2);
+            _argIndex++;
+          }
+        }
+        final List<Integer> _result = new ArrayList<Integer>();
+        while (_stmt.step()) {
+          final Integer _item_3;
+          if (_stmt.isNull(0)) {
+            _item_3 = null;
+          } else {
+            _item_3 = (int) (_stmt.getLong(0));
+          }
+          _result.add(_item_3);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public LiveData<User> getByIdLive(final int id) {
+    final String _sql = "SELECT * FROM user where uid = ?";
+    final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
+    int _argIndex = 1;
+    _statement.bindLong(_argIndex, id);
+    return __db.getInvalidationTracker().createLiveData(new String[] {"user"}, false, new Callable<User>() {
+      @Override
+      @Nullable
+      public User call() throws Exception {
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
+        try {
+          final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
+          final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
+          final int _cursorIndexOfLastName = CursorUtil.getColumnIndexOrThrow(_cursor, "lastName");
+          final int _cursorIndexOfAge = CursorUtil.getColumnIndexOrThrow(_cursor, "ageColumn");
+          final User _result;
+          if (_cursor.moveToFirst()) {
+            _result = new User();
+            _result.uid = _cursor.getInt(_cursorIndexOfUid);
+            if (_cursor.isNull(_cursorIndexOfName)) {
+              _result.name = null;
+            } else {
+              _result.name = _cursor.getString(_cursorIndexOfName);
+            }
+            final String _tmpLastName;
+            if (_cursor.isNull(_cursorIndexOfLastName)) {
+              _tmpLastName = null;
+            } else {
+              _tmpLastName = _cursor.getString(_cursorIndexOfLastName);
+            }
+            _result.setLastName(_tmpLastName);
+            _result.age = _cursor.getInt(_cursorIndexOfAge);
+          } else {
+            _result = null;
+          }
+          return _result;
+        } finally {
+          _cursor.close();
+        }
+      }
+
+      @Override
+      protected void finalize() {
+        _statement.release();
+      }
+    });
+  }
+
+  @Override
+  public LiveData<List<User>> loadUsersByIdsLive(final int... ids) {
+    final StringBuilder _stringBuilder = new StringBuilder();
+    _stringBuilder.append("SELECT * FROM user where uid IN (");
+    final int _inputSize = ids == null ? 1 : ids.length;
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
+    _stringBuilder.append(")");
+    final String _sql = _stringBuilder.toString();
+    final int _argCount = 0 + _inputSize;
+    final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, _argCount);
+    int _argIndex = 1;
+    if (ids == null) {
+      _statement.bindNull(_argIndex);
+    } else {
+      for (int _item : ids) {
+        _statement.bindLong(_argIndex, _item);
+        _argIndex++;
+      }
+    }
+    return __db.getInvalidationTracker().createLiveData(new String[] {"user"}, false, new Callable<List<User>>() {
+      @Override
+      @Nullable
+      public List<User> call() throws Exception {
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
+        try {
+          final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
+          final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
+          final int _cursorIndexOfLastName = CursorUtil.getColumnIndexOrThrow(_cursor, "lastName");
+          final int _cursorIndexOfAge = CursorUtil.getColumnIndexOrThrow(_cursor, "ageColumn");
+          final List<User> _result = new ArrayList<User>();
+          while (_cursor.moveToNext()) {
+            final User _item_1;
+            _item_1 = new User();
+            _item_1.uid = _cursor.getInt(_cursorIndexOfUid);
+            if (_cursor.isNull(_cursorIndexOfName)) {
+              _item_1.name = null;
+            } else {
+              _item_1.name = _cursor.getString(_cursorIndexOfName);
+            }
+            final String _tmpLastName;
+            if (_cursor.isNull(_cursorIndexOfLastName)) {
+              _tmpLastName = null;
+            } else {
+              _tmpLastName = _cursor.getString(_cursorIndexOfLastName);
+            }
+            _item_1.setLastName(_tmpLastName);
+            _item_1.age = _cursor.getInt(_cursorIndexOfAge);
+            _result.add(_item_1);
+          }
+          return _result;
+        } finally {
+          _cursor.close();
+        }
+      }
+
+      @Override
+      protected void finalize() {
+        _statement.release();
+      }
+    });
+  }
+
+  @Override
+  public List<Child1> getChild1List() {
+    final String _sql = "SELECT * FROM Child1";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        final int _cursorIndexOfId = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "id");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfSerial = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "serial");
+        final int _cursorIndexOfCode = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "code");
+        final List<Child1> _result = new ArrayList<Child1>();
+        while (_stmt.step()) {
+          final Child1 _item;
+          final int _tmpId;
+          _tmpId = (int) (_stmt.getLong(_cursorIndexOfId));
+          final String _tmpName;
+          if (_stmt.isNull(_cursorIndexOfName)) {
+            _tmpName = null;
+          } else {
+            _tmpName = _stmt.getText(_cursorIndexOfName);
+          }
+          final Info _tmpInfo;
+          if (!(_stmt.isNull(_cursorIndexOfSerial) && _stmt.isNull(_cursorIndexOfCode))) {
+            _tmpInfo = new Info();
+            _tmpInfo.serial = (int) (_stmt.getLong(_cursorIndexOfSerial));
+            if (_stmt.isNull(_cursorIndexOfCode)) {
+              _tmpInfo.code = null;
+            } else {
+              _tmpInfo.code = _stmt.getText(_cursorIndexOfCode);
+            }
+          } else {
+            _tmpInfo = null;
+          }
+          _item = new Child1(_tmpId,_tmpName,_tmpInfo);
+          _result.add(_item);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public List<Child2> getChild2List() {
+    final String _sql = "SELECT * FROM Child2";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        final int _cursorIndexOfId = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "id");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfSerial = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "serial");
+        final int _cursorIndexOfCode = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "code");
+        final List<Child2> _result = new ArrayList<Child2>();
+        while (_stmt.step()) {
+          final Child2 _item;
+          final int _tmpId;
+          _tmpId = (int) (_stmt.getLong(_cursorIndexOfId));
+          final String _tmpName;
+          if (_stmt.isNull(_cursorIndexOfName)) {
+            _tmpName = null;
+          } else {
+            _tmpName = _stmt.getText(_cursorIndexOfName);
+          }
+          final Info _tmpInfo;
+          if (!(_stmt.isNull(_cursorIndexOfSerial) && _stmt.isNull(_cursorIndexOfCode))) {
+            _tmpInfo = new Info();
+            _tmpInfo.serial = (int) (_stmt.getLong(_cursorIndexOfSerial));
+            if (_stmt.isNull(_cursorIndexOfCode)) {
+              _tmpInfo.code = null;
+            } else {
+              _tmpInfo.code = _stmt.getText(_cursorIndexOfCode);
+            }
+          } else {
+            _tmpInfo = null;
+          }
+          _item = new Child2(_tmpId,_tmpName,_tmpInfo);
+          _result.add(_item);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public ListenableFuture<List<Child1>> getChild1ListListenableFuture() {
+    final String _sql = "SELECT * FROM Child1";
+    final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
+    final CancellationSignal _cancellationSignal = new CancellationSignal();
+    return GuavaRoom.createListenableFuture(__db, false, new Callable<List<Child1>>() {
+      @Override
+      public List<Child1> call() throws Exception {
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, _cancellationSignal);
+        try {
+          final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
+          final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
+          final int _cursorIndexOfSerial = CursorUtil.getColumnIndexOrThrow(_cursor, "serial");
+          final int _cursorIndexOfCode = CursorUtil.getColumnIndexOrThrow(_cursor, "code");
+          final List<Child1> _result = new ArrayList<Child1>();
+          while (_cursor.moveToNext()) {
+            final Child1 _item;
+            final int _tmpId;
+            _tmpId = _cursor.getInt(_cursorIndexOfId);
+            final String _tmpName;
+            if (_cursor.isNull(_cursorIndexOfName)) {
+              _tmpName = null;
+            } else {
+              _tmpName = _cursor.getString(_cursorIndexOfName);
+            }
+            final Info _tmpInfo;
+            if (!(_cursor.isNull(_cursorIndexOfSerial) && _cursor.isNull(_cursorIndexOfCode))) {
+              _tmpInfo = new Info();
+              _tmpInfo.serial = _cursor.getInt(_cursorIndexOfSerial);
+              if (_cursor.isNull(_cursorIndexOfCode)) {
+                _tmpInfo.code = null;
+              } else {
+                _tmpInfo.code = _cursor.getString(_cursorIndexOfCode);
+              }
+            } else {
+              _tmpInfo = null;
+            }
+            _item = new Child1(_tmpId,_tmpName,_tmpInfo);
+            _result.add(_item);
+          }
+          return _result;
+        } finally {
+          _cursor.close();
+        }
+      }
+    }, _statement, true, _cancellationSignal);
+  }
+
+  @Override
+  public List<UserSummary> getUserNames() {
+    final String _sql = "SELECT `uid`, `name` FROM (SELECT * FROM User)";
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        final int _cursorIndexOfUid = 0;
+        final int _cursorIndexOfName = 1;
+        final List<UserSummary> _result = new ArrayList<UserSummary>();
+        while (_stmt.step()) {
+          final UserSummary _item;
+          _item = new UserSummary();
+          _item.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          if (_stmt.isNull(_cursorIndexOfName)) {
+            _item.name = null;
+          } else {
+            _item.name = _stmt.getText(_cursorIndexOfName);
+          }
+          _result.add(_item);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public User getUserViaRawQuery(final SupportSQLiteQuery rawQuery) {
+    __db.assertNotSuspendingTransaction();
+    final Cursor _cursor = DBUtil.query(__db, rawQuery, false, null);
+    try {
+      final User _result;
+      if (_cursor.moveToFirst()) {
+        _result = __entityCursorConverter_fooBarUser(_cursor);
+      } else {
+        _result = null;
+      }
+      return _result;
+    } finally {
+      _cursor.close();
+    }
+  }
+
+  @NonNull
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
+
+  private User __entityCursorConverter_fooBarUser(@NonNull final Cursor cursor) {
+    final User _entity;
+    final int _cursorIndexOfUid = CursorUtil.getColumnIndex(cursor, "uid");
+    final int _cursorIndexOfName = CursorUtil.getColumnIndex(cursor, "name");
+    final int _cursorIndexOfLastName = CursorUtil.getColumnIndex(cursor, "lastName");
+    final int _cursorIndexOfAge = CursorUtil.getColumnIndex(cursor, "ageColumn");
+    _entity = new User();
+    if (_cursorIndexOfUid != -1) {
+      _entity.uid = cursor.getInt(_cursorIndexOfUid);
+    }
+    if (_cursorIndexOfName != -1) {
+      if (cursor.isNull(_cursorIndexOfName)) {
+        _entity.name = null;
+      } else {
+        _entity.name = cursor.getString(_cursorIndexOfName);
+      }
+    }
+    if (_cursorIndexOfLastName != -1) {
+      final String _tmpLastName;
+      if (cursor.isNull(_cursorIndexOfLastName)) {
+        _tmpLastName = null;
+      } else {
+        _tmpLastName = cursor.getString(_cursorIndexOfLastName);
+      }
+      _entity.setLastName(_tmpLastName);
+    }
+    if (_cursorIndexOfAge != -1) {
+      _entity.age = cursor.getInt(_cursorIndexOfAge);
+    }
+    return _entity;
+  }
+}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/DeletionDao.java
new file mode 100644
index 0000000..996eaf5
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/DeletionDao.java
@@ -0,0 +1,367 @@
+package foo.bar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.room.EntityDeleteOrUpdateAdapter;
+import androidx.room.EntityDeletionOrUpdateAdapter;
+import androidx.room.RoomDatabase;
+import androidx.room.util.DBUtil;
+import androidx.room.util.SQLiteConnectionUtil;
+import androidx.room.util.StringUtil;
+import androidx.sqlite.SQLiteStatement;
+import androidx.sqlite.db.SupportSQLiteStatement;
+import io.reactivex.Completable;
+import io.reactivex.Maybe;
+import io.reactivex.Single;
+import java.lang.Class;
+import java.lang.Exception;
+import java.lang.Integer;
+import java.lang.Override;
+import java.lang.String;
+import java.lang.StringBuilder;
+import java.lang.SuppressWarnings;
+import java.lang.Void;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation", "removal"})
+public final class DeletionDao_Impl implements DeletionDao {
+  private final RoomDatabase __db;
+
+  private final EntityDeleteOrUpdateAdapter<User> __deleteAdapterOfUser;
+
+  private final EntityDeletionOrUpdateAdapter<User> __deleteCompatAdapterOfUser;
+
+  private final EntityDeleteOrUpdateAdapter<MultiPKeyEntity> __deleteAdapterOfMultiPKeyEntity;
+
+  private final EntityDeleteOrUpdateAdapter<Book> __deleteAdapterOfBook;
+
+  public DeletionDao_Impl(@NonNull final RoomDatabase __db) {
+    this.__db = __db;
+    this.__deleteAdapterOfUser = new EntityDeleteOrUpdateAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "DELETE FROM `User` WHERE `uid` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+      }
+    };
+    this.__deleteCompatAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "DELETE FROM `User` WHERE `uid` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+      }
+    };
+    this.__deleteAdapterOfMultiPKeyEntity = new EntityDeleteOrUpdateAdapter<MultiPKeyEntity>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "DELETE FROM `MultiPKeyEntity` WHERE `name` = ? AND `lastName` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final MultiPKeyEntity entity) {
+        if (entity.name == null) {
+          statement.bindNull(1);
+        } else {
+          statement.bindText(1, entity.name);
+        }
+        if (entity.lastName == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.lastName);
+        }
+      }
+    };
+    this.__deleteAdapterOfBook = new EntityDeleteOrUpdateAdapter<Book>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "DELETE FROM `Book` WHERE `bookId` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final Book entity) {
+        statement.bindLong(1, entity.bookId);
+      }
+    };
+  }
+
+  @Override
+  public void deleteUser(final User user) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handle(_connection, user);
+      return null;
+    });
+  }
+
+  @Override
+  public void deleteUsers(final User user1, final List<User> others) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handle(_connection, user1);
+      __deleteAdapterOfUser.handleMultiple(_connection, others);
+      return null;
+    });
+  }
+
+  @Override
+  public void deleteArrayOfUsers(final User[] users) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handleMultiple(_connection, users);
+      return null;
+    });
+  }
+
+  @Override
+  public Integer deleteUserAndReturnCountObject(final User user) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handle(_connection, user);
+      return _result;
+    });
+  }
+
+  @Override
+  public int deleteUserAndReturnCount(final User user) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handle(_connection, user);
+      return _result;
+    });
+  }
+
+  @Override
+  public int deleteUserAndReturnCount(final User user1, final List<User> others) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handle(_connection, user1);
+      _result += __deleteAdapterOfUser.handleMultiple(_connection, others);
+      return _result;
+    });
+  }
+
+  @Override
+  public int deleteUserAndReturnCount(final User[] users) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handleMultiple(_connection, users);
+      return _result;
+    });
+  }
+
+  @Override
+  public Completable deleteUserCompletable(final User user) {
+    return Completable.fromCallable(new Callable<Void>() {
+      @Override
+      @Nullable
+      public Void call() throws Exception {
+        __db.beginTransaction();
+        try {
+          __deleteCompatAdapterOfUser.handle(user);
+          __db.setTransactionSuccessful();
+          return null;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Single<Integer> deleteUserSingle(final User user) {
+    return Single.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        int _total = 0;
+        __db.beginTransaction();
+        try {
+          _total += __deleteCompatAdapterOfUser.handle(user);
+          __db.setTransactionSuccessful();
+          return _total;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Maybe<Integer> deleteUserMaybe(final User user) {
+    return Maybe.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        int _total = 0;
+        __db.beginTransaction();
+        try {
+          _total += __deleteCompatAdapterOfUser.handle(user);
+          __db.setTransactionSuccessful();
+          return _total;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public int multiPKey(final MultiPKeyEntity entity) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfMultiPKeyEntity.handle(_connection, entity);
+      return _result;
+    });
+  }
+
+  @Override
+  public void deleteUserAndBook(final User user, final Book book) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handle(_connection, user);
+      __deleteAdapterOfBook.handle(_connection, book);
+      return null;
+    });
+  }
+
+  @Override
+  public int deleteByUid(final int uid) {
+    final String _sql = "DELETE FROM user where uid = ?";
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, uid);
+        _stmt.step();
+        return SQLiteConnectionUtil.getTotalChangedRows(_connection);
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public Completable deleteByUidCompletable(final int uid) {
+    return Completable.fromCallable(new Callable<Void>() {
+      @Override
+      @Nullable
+      public Void call() throws Exception {
+        final String _sql = "DELETE FROM user where uid = ?";
+        final SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, uid);
+        __db.beginTransaction();
+        try {
+          _stmt.executeUpdateDelete();
+          __db.setTransactionSuccessful();
+          return null;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Single<Integer> deleteByUidSingle(final int uid) {
+    return Single.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        final String _sql = "DELETE FROM user where uid = ?";
+        final SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, uid);
+        __db.beginTransaction();
+        try {
+          final Integer _result = _stmt.executeUpdateDelete();
+          __db.setTransactionSuccessful();
+          return _result;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Maybe<Integer> deleteByUidMaybe(final int uid) {
+    return Maybe.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        final String _sql = "DELETE FROM user where uid = ?";
+        final SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, uid);
+        __db.beginTransaction();
+        try {
+          final Integer _result = _stmt.executeUpdateDelete();
+          __db.setTransactionSuccessful();
+          return _result;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public int deleteByUidList(final int... uid) {
+    final StringBuilder _stringBuilder = new StringBuilder();
+    _stringBuilder.append("DELETE FROM user where uid IN(");
+    final int _inputSize = uid == null ? 1 : uid.length;
+    StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
+    _stringBuilder.append(")");
+    final String _sql = _stringBuilder.toString();
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (uid == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item : uid) {
+            _stmt.bindLong(_argIndex, _item);
+            _argIndex++;
+          }
+        }
+        _stmt.step();
+        return SQLiteConnectionUtil.getTotalChangedRows(_connection);
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public int deleteEverything() {
+    final String _sql = "DELETE FROM user";
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        _stmt.step();
+        return SQLiteConnectionUtil.getTotalChangedRows(_connection);
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @NonNull
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
+}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/UpdateDao.java
new file mode 100644
index 0000000..6214715
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/UpdateDao.java
@@ -0,0 +1,405 @@
+package foo.bar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.room.EntityDeleteOrUpdateAdapter;
+import androidx.room.EntityDeletionOrUpdateAdapter;
+import androidx.room.RoomDatabase;
+import androidx.room.util.DBUtil;
+import androidx.sqlite.SQLiteStatement;
+import androidx.sqlite.db.SupportSQLiteStatement;
+import io.reactivex.Completable;
+import io.reactivex.Maybe;
+import io.reactivex.Single;
+import java.lang.Class;
+import java.lang.Exception;
+import java.lang.Integer;
+import java.lang.Override;
+import java.lang.String;
+import java.lang.SuppressWarnings;
+import java.lang.Void;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation", "removal"})
+public final class UpdateDao_Impl implements UpdateDao {
+  private final RoomDatabase __db;
+
+  private final EntityDeleteOrUpdateAdapter<User> __updateAdapterOfUser;
+
+  private final EntityDeleteOrUpdateAdapter<User> __updateAdapterOfUser_1;
+
+  private final EntityDeletionOrUpdateAdapter<User> __updateCompatAdapterOfUser;
+
+  private final EntityDeleteOrUpdateAdapter<MultiPKeyEntity> __updateAdapterOfMultiPKeyEntity;
+
+  private final EntityDeleteOrUpdateAdapter<Book> __updateAdapterOfBook;
+
+  public UpdateDao_Impl(@NonNull final RoomDatabase __db) {
+    this.__db = __db;
+    this.__updateAdapterOfUser = new EntityDeleteOrUpdateAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE OR ABORT `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+        statement.bindLong(5, entity.uid);
+      }
+    };
+    this.__updateAdapterOfUser_1 = new EntityDeleteOrUpdateAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+        statement.bindLong(5, entity.uid);
+      }
+    };
+    this.__updateCompatAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE OR ABORT `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindString(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindString(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+        statement.bindLong(5, entity.uid);
+      }
+    };
+    this.__updateAdapterOfMultiPKeyEntity = new EntityDeleteOrUpdateAdapter<MultiPKeyEntity>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE OR ABORT `MultiPKeyEntity` SET `name` = ?,`lastName` = ? WHERE `name` = ? AND `lastName` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final MultiPKeyEntity entity) {
+        if (entity.name == null) {
+          statement.bindNull(1);
+        } else {
+          statement.bindText(1, entity.name);
+        }
+        if (entity.lastName == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.lastName);
+        }
+        if (entity.name == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.name);
+        }
+        if (entity.lastName == null) {
+          statement.bindNull(4);
+        } else {
+          statement.bindText(4, entity.lastName);
+        }
+      }
+    };
+    this.__updateAdapterOfBook = new EntityDeleteOrUpdateAdapter<Book>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE OR ABORT `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final Book entity) {
+        statement.bindLong(1, entity.bookId);
+        statement.bindLong(2, entity.uid);
+        statement.bindLong(3, entity.bookId);
+      }
+    };
+  }
+
+  @Override
+  public void updateUser(final User user) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handle(_connection, user);
+      return null;
+    });
+  }
+
+  @Override
+  public void updateUsers(final User user1, final List<User> others) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handle(_connection, user1);
+      __updateAdapterOfUser.handleMultiple(_connection, others);
+      return null;
+    });
+  }
+
+  @Override
+  public void updateArrayOfUsers(final User[] users) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handleMultiple(_connection, users);
+      return null;
+    });
+  }
+
+  @Override
+  public void updateTwoUsers(final User userOne, final User userTwo) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser_1.handle(_connection, userOne);
+      __updateAdapterOfUser_1.handle(_connection, userTwo);
+      return null;
+    });
+  }
+
+  @Override
+  public int updateUserAndReturnCount(final User user) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handle(_connection, user);
+      return _result;
+    });
+  }
+
+  @Override
+  public int updateUserAndReturnCount(final User user1, final List<User> others) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handle(_connection, user1);
+      _result += __updateAdapterOfUser.handleMultiple(_connection, others);
+      return _result;
+    });
+  }
+
+  @Override
+  public int updateUserAndReturnCount(final User[] users) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handleMultiple(_connection, users);
+      return _result;
+    });
+  }
+
+  @Override
+  public Integer updateUserAndReturnCountObject(final User user) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handle(_connection, user);
+      return _result;
+    });
+  }
+
+  @Override
+  public Completable updateUserAndReturnCountCompletable(final User user) {
+    return Completable.fromCallable(new Callable<Void>() {
+      @Override
+      @Nullable
+      public Void call() throws Exception {
+        __db.beginTransaction();
+        try {
+          __updateCompatAdapterOfUser.handle(user);
+          __db.setTransactionSuccessful();
+          return null;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Single<Integer> updateUserAndReturnCountSingle(final User user) {
+    return Single.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        int _total = 0;
+        __db.beginTransaction();
+        try {
+          _total += __updateCompatAdapterOfUser.handle(user);
+          __db.setTransactionSuccessful();
+          return _total;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Maybe<Integer> updateUserAndReturnCountMaybe(final User user) {
+    return Maybe.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        int _total = 0;
+        __db.beginTransaction();
+        try {
+          _total += __updateCompatAdapterOfUser.handle(user);
+          __db.setTransactionSuccessful();
+          return _total;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public int multiPKey(final MultiPKeyEntity entity) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfMultiPKeyEntity.handle(_connection, entity);
+      return _result;
+    });
+  }
+
+  @Override
+  public void updateUserAndBook(final User user, final Book book) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handle(_connection, user);
+      __updateAdapterOfBook.handle(_connection, book);
+      return null;
+    });
+  }
+
+  @Override
+  public void ageUserByUid(final String uid) {
+    final String _sql = "UPDATE User SET ageColumn = ageColumn + 1 WHERE uid = ?";
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (uid == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          _stmt.bindText(_argIndex, uid);
+        }
+        _stmt.step();
+        return null;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public void ageUserAll() {
+    final String _sql = "UPDATE User SET ageColumn = ageColumn + 1";
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        _stmt.step();
+        return null;
+      } finally {
+        _stmt.close();
+      }
+    });
+  }
+
+  @Override
+  public Completable ageUserAllCompletable() {
+    return Completable.fromCallable(new Callable<Void>() {
+      @Override
+      @Nullable
+      public Void call() throws Exception {
+        final String _sql = "UPDATE User SET ageColumn = ageColumn + 1";
+        final SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
+        __db.beginTransaction();
+        try {
+          _stmt.executeUpdateDelete();
+          __db.setTransactionSuccessful();
+          return null;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Single<Integer> ageUserAllSingle() {
+    return Single.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        final String _sql = "UPDATE User SET ageColumn = ageColumn + 1";
+        final SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
+        __db.beginTransaction();
+        try {
+          final Integer _result = _stmt.executeUpdateDelete();
+          __db.setTransactionSuccessful();
+          return _result;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @Override
+  public Maybe<Integer> ageUserAllMaybe() {
+    return Maybe.fromCallable(new Callable<Integer>() {
+      @Override
+      @Nullable
+      public Integer call() throws Exception {
+        final String _sql = "UPDATE User SET ageColumn = ageColumn + 1";
+        final SupportSQLiteStatement _stmt = __db.compileStatement(_sql);
+        __db.beginTransaction();
+        try {
+          final Integer _result = _stmt.executeUpdateDelete();
+          __db.setTransactionSuccessful();
+          return _result;
+        } finally {
+          __db.endTransaction();
+        }
+      }
+    });
+  }
+
+  @NonNull
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
+}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/UpsertDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/UpsertDao.java
new file mode 100644
index 0000000..5cacce2
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/UpsertDao.java
@@ -0,0 +1,164 @@
+package foo.bar;
+
+import androidx.annotation.NonNull;
+import androidx.room.EntityDeleteOrUpdateAdapter;
+import androidx.room.EntityInsertAdapter;
+import androidx.room.EntityUpsertAdapter;
+import androidx.room.RoomDatabase;
+import androidx.room.util.DBUtil;
+import androidx.sqlite.SQLiteStatement;
+import java.lang.Class;
+import java.lang.Override;
+import java.lang.String;
+import java.lang.SuppressWarnings;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation", "removal"})
+public final class UpsertDao_Impl implements UpsertDao {
+  private final RoomDatabase __db;
+
+  private final EntityUpsertAdapter<User> __upsertAdapterOfUser;
+
+  private final EntityUpsertAdapter<Book> __upsertAdapterOfBook;
+
+  public UpsertDao_Impl(@NonNull final RoomDatabase __db) {
+    this.__db = __db;
+    this.__upsertAdapterOfUser = new EntityUpsertAdapter<User>(new EntityInsertAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+      }
+    }, new EntityDeleteOrUpdateAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+        statement.bindLong(5, entity.uid);
+      }
+    });
+    this.__upsertAdapterOfBook = new EntityUpsertAdapter<Book>(new EntityInsertAdapter<Book>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "INSERT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final Book entity) {
+        statement.bindLong(1, entity.bookId);
+        statement.bindLong(2, entity.uid);
+      }
+    }, new EntityDeleteOrUpdateAdapter<Book>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "UPDATE `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final Book entity) {
+        statement.bindLong(1, entity.bookId);
+        statement.bindLong(2, entity.uid);
+        statement.bindLong(3, entity.bookId);
+      }
+    });
+  }
+
+  @Override
+  public void upsertUser(final User user) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, user);
+      return null;
+    });
+  }
+
+  @Override
+  public void upsertUsers(final User user1, final List<User> others) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, user1);
+      __upsertAdapterOfUser.upsert(_connection, others);
+      return null;
+    });
+  }
+
+  @Override
+  public void upsertUsers(final User[] users) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, users);
+      return null;
+    });
+  }
+
+  @Override
+  public void upsertTwoUsers(final User userOne, final User userTwo) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, userOne);
+      __upsertAdapterOfUser.upsert(_connection, userTwo);
+      return null;
+    });
+  }
+
+  @Override
+  public void upsertUserAndBook(final User user, final Book book) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, user);
+      __upsertAdapterOfBook.upsert(_connection, book);
+      return null;
+    });
+  }
+
+  @Override
+  public long upsertAndReturnId(final User user) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      return __upsertAdapterOfUser.upsertAndReturnId(_connection, user);
+    });
+  }
+
+  @Override
+  public long[] upsertAndReturnIdsArray(final User[] users) {
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      return __upsertAdapterOfUser.upsertAndReturnIdsArray(_connection, users);
+    });
+  }
+
+  @NonNull
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
+}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/WriterDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/WriterDao.java
new file mode 100644
index 0000000..2f679db7
--- /dev/null
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withLambda/WriterDao.java
@@ -0,0 +1,162 @@
+package foo.bar;
+
+import androidx.annotation.NonNull;
+import androidx.room.EntityInsertAdapter;
+import androidx.room.RoomDatabase;
+import androidx.room.util.DBUtil;
+import androidx.sqlite.SQLiteStatement;
+import java.lang.Class;
+import java.lang.Override;
+import java.lang.String;
+import java.lang.SuppressWarnings;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation", "removal"})
+public final class WriterDao_Impl implements WriterDao {
+  private final RoomDatabase __db;
+
+  private final EntityInsertAdapter<User> __insertAdapterOfUser;
+
+  private final EntityInsertAdapter<User> __insertAdapterOfUser_1;
+
+  private final EntityInsertAdapter<User> __insertAdapterOfUser_2;
+
+  private final EntityInsertAdapter<Book> __insertAdapterOfBook;
+
+  public WriterDao_Impl(@NonNull final RoomDatabase __db) {
+    this.__db = __db;
+    this.__insertAdapterOfUser = new EntityInsertAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "INSERT OR ABORT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+      }
+    };
+    this.__insertAdapterOfUser_1 = new EntityInsertAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "INSERT OR REPLACE INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+      }
+    };
+    this.__insertAdapterOfUser_2 = new EntityInsertAdapter<User>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final User entity) {
+        statement.bindLong(1, entity.uid);
+        if (entity.name == null) {
+          statement.bindNull(2);
+        } else {
+          statement.bindText(2, entity.name);
+        }
+        if (entity.getLastName() == null) {
+          statement.bindNull(3);
+        } else {
+          statement.bindText(3, entity.getLastName());
+        }
+        statement.bindLong(4, entity.age);
+      }
+    };
+    this.__insertAdapterOfBook = new EntityInsertAdapter<Book>() {
+      @Override
+      @NonNull
+      protected String createQuery() {
+        return "INSERT OR ABORT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
+      }
+
+      @Override
+      protected void bind(@NonNull final SQLiteStatement statement, final Book entity) {
+        statement.bindLong(1, entity.bookId);
+        statement.bindLong(2, entity.uid);
+      }
+    };
+  }
+
+  @Override
+  public void insertUser(final User user) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser.insert(_connection, user);
+      return null;
+    });
+  }
+
+  @Override
+  public void insertUsers(final User user1, final List<User> others) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser.insert(_connection, user1);
+      __insertAdapterOfUser.insert(_connection, others);
+      return null;
+    });
+  }
+
+  @Override
+  public void insertUsers(final User[] users) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser_1.insert(_connection, users);
+      return null;
+    });
+  }
+
+  @Override
+  public void insertTwoUsers(final User userOne, final User userTwo) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser_2.insert(_connection, userOne);
+      __insertAdapterOfUser_2.insert(_connection, userTwo);
+      return null;
+    });
+  }
+
+  @Override
+  public void insertUserAndBook(final User user, final Book book) {
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser.insert(_connection, user);
+      __insertAdapterOfBook.insert(_connection, book);
+      return null;
+    });
+  }
+
+  @NonNull
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
+}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/ComplexDao.java
index 4190e31..c750934 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/ComplexDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/ComplexDao.java
@@ -16,6 +16,7 @@
 import androidx.sqlite.SQLiteStatement;
 import androidx.sqlite.db.SupportSQLiteQuery;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.Boolean;
 import java.lang.Class;
 import java.lang.Exception;
 import java.lang.Integer;
@@ -42,9 +43,13 @@
 
   @Override
   public boolean transactionMethod(final int i, final String s, final long l) {
-    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
-          return ComplexDao_Impl.super.transactionMethod(i, s, l);
-        });
+    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Boolean>() {
+      @Override
+      @NonNull
+      public Boolean invoke(@NonNull final SQLiteConnection _connection) {
+        return ComplexDao_Impl.super.transactionMethod(i, s, l);
+      }
+    });
   }
 
   @Override
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/UpdateDao.java
index bdb28be..f3ca3df 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/withoutLambda/UpdateDao.java
@@ -23,7 +23,6 @@
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
-import kotlin.Unit;
 import kotlin.jvm.functions.Function1;
 
 @Generated("androidx.room.RoomProcessor")
@@ -348,14 +347,6 @@
   }
 
   @Override
-  public void updateAndAge(final User user) {
-    DBUtil.performBlocking(__db, false, true, (_connection) -> {
-          UpdateDao.super.updateAndAge(user);
-          return Unit.INSTANCE;
-        });
-  }
-
-  @Override
   public void ageUserByUid(final String uid) {
     final String _sql = "UPDATE User SET ageColumn = ageColumn + 1 WHERE uid = ?";
     DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
index 0119011..a9c2362 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/ComplexDao.java
@@ -12,7 +12,6 @@
 import androidx.room.util.DBUtil;
 import androidx.room.util.SQLiteStatementUtil;
 import androidx.room.util.StringUtil;
-import androidx.sqlite.SQLiteConnection;
 import androidx.sqlite.SQLiteStatement;
 import androidx.sqlite.db.SupportSQLiteQuery;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -28,7 +27,6 @@
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
-import kotlin.jvm.functions.Function1;
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation", "removal"})
@@ -43,35 +41,31 @@
   @Override
   public boolean transactionMethod(final int i, final String s, final long l) {
     return DBUtil.performBlocking(__db, false, true, (_connection) -> {
-          return ComplexDao_Impl.super.transactionMethod(i, s, l);
-        });
+      return ComplexDao_Impl.super.transactionMethod(i, s, l);
+    });
   }
 
   @Override
   public List<ComplexDao.FullName> fullNames(final int id) {
     final String _sql = "SELECT name || lastName as fullName, uid as id FROM user where uid = ?";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<ComplexDao.FullName>>() {
-      @Override
-      @NonNull
-      public List<ComplexDao.FullName> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          _stmt.bindLong(_argIndex, id);
-          final int _cursorIndexOfFullName = 0;
-          final int _cursorIndexOfId = 1;
-          final List<ComplexDao.FullName> _result = new ArrayList<ComplexDao.FullName>();
-          while (_stmt.step()) {
-            final ComplexDao.FullName _item;
-            _item = new ComplexDao.FullName();
-            _item.fullName = _stmt.getText(_cursorIndexOfFullName);
-            _item.id = (int) (_stmt.getLong(_cursorIndexOfId));
-            _result.add(_item);
-          }
-          return _result;
-        } finally {
-          _stmt.close();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, id);
+        final int _cursorIndexOfFullName = 0;
+        final int _cursorIndexOfId = 1;
+        final List<ComplexDao.FullName> _result = new ArrayList<ComplexDao.FullName>();
+        while (_stmt.step()) {
+          final ComplexDao.FullName _item;
+          _item = new ComplexDao.FullName();
+          _item.fullName = _stmt.getText(_cursorIndexOfFullName);
+          _item.id = (int) (_stmt.getLong(_cursorIndexOfId));
+          _result.add(_item);
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -79,34 +73,30 @@
   @Override
   public User getById(final int id) {
     final String _sql = "SELECT * FROM user where uid = ?";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, User>() {
-      @Override
-      @NonNull
-      public User invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          _stmt.bindLong(_argIndex, id);
-          final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
-          final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
-          final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
-          final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
-          final User _result;
-          if (_stmt.step()) {
-            _result = new User();
-            _result.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
-            _result.name = _stmt.getText(_cursorIndexOfName);
-            final String _tmpLastName;
-            _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
-            _result.setLastName(_tmpLastName);
-            _result.age = (int) (_stmt.getLong(_cursorIndexOfAge));
-          } else {
-            _result = null;
-          }
-          return _result;
-        } finally {
-          _stmt.close();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, id);
+        final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
+        final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
+        final User _result;
+        if (_stmt.step()) {
+          _result = new User();
+          _result.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          _result.name = _stmt.getText(_cursorIndexOfName);
+          final String _tmpLastName;
+          _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
+          _result.setLastName(_tmpLastName);
+          _result.age = (int) (_stmt.getLong(_cursorIndexOfAge));
+        } else {
+          _result = null;
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -114,36 +104,32 @@
   @Override
   public User findByName(final String name, final String lastName) {
     final String _sql = "SELECT * FROM user where name LIKE ? AND lastName LIKE ?";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, User>() {
-      @Override
-      @NonNull
-      public User invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          _stmt.bindText(_argIndex, name);
-          _argIndex = 2;
-          _stmt.bindText(_argIndex, lastName);
-          final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
-          final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
-          final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
-          final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
-          final User _result;
-          if (_stmt.step()) {
-            _result = new User();
-            _result.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
-            _result.name = _stmt.getText(_cursorIndexOfName);
-            final String _tmpLastName;
-            _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
-            _result.setLastName(_tmpLastName);
-            _result.age = (int) (_stmt.getLong(_cursorIndexOfAge));
-          } else {
-            _result = null;
-          }
-          return _result;
-        } finally {
-          _stmt.close();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindText(_argIndex, name);
+        _argIndex = 2;
+        _stmt.bindText(_argIndex, lastName);
+        final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
+        final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
+        final User _result;
+        if (_stmt.step()) {
+          _result = new User();
+          _result.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          _result.name = _stmt.getText(_cursorIndexOfName);
+          final String _tmpLastName;
+          _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
+          _result.setLastName(_tmpLastName);
+          _result.age = (int) (_stmt.getLong(_cursorIndexOfAge));
+        } else {
+          _result = null;
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -156,41 +142,37 @@
     StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
     _stringBuilder.append(")");
     final String _sql = _stringBuilder.toString();
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<User>>() {
-      @Override
-      @NonNull
-      public List<User> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          if (ids == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (int _item : ids) {
-              _stmt.bindLong(_argIndex, _item);
-              _argIndex++;
-            }
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item : ids) {
+            _stmt.bindLong(_argIndex, _item);
+            _argIndex++;
           }
-          final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
-          final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
-          final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
-          final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
-          final List<User> _result = new ArrayList<User>();
-          while (_stmt.step()) {
-            final User _item_1;
-            _item_1 = new User();
-            _item_1.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
-            _item_1.name = _stmt.getText(_cursorIndexOfName);
-            final String _tmpLastName;
-            _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
-            _item_1.setLastName(_tmpLastName);
-            _item_1.age = (int) (_stmt.getLong(_cursorIndexOfAge));
-            _result.add(_item_1);
-          }
-          return _result;
-        } finally {
-          _stmt.close();
         }
+        final int _cursorIndexOfUid = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "uid");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfLastName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "lastName");
+        final int _cursorIndexOfAge = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "ageColumn");
+        final List<User> _result = new ArrayList<User>();
+        while (_stmt.step()) {
+          final User _item_1;
+          _item_1 = new User();
+          _item_1.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          _item_1.name = _stmt.getText(_cursorIndexOfName);
+          final String _tmpLastName;
+          _tmpLastName = _stmt.getText(_cursorIndexOfLastName);
+          _item_1.setLastName(_tmpLastName);
+          _item_1.age = (int) (_stmt.getLong(_cursorIndexOfAge));
+          _result.add(_item_1);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -198,24 +180,20 @@
   @Override
   int getAge(final int id) {
     final String _sql = "SELECT ageColumn FROM user where uid = ?";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          _stmt.bindLong(_argIndex, id);
-          final int _result;
-          if (_stmt.step()) {
-            _result = (int) (_stmt.getLong(0));
-          } else {
-            _result = 0;
-          }
-          return _result;
-        } finally {
-          _stmt.close();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, id);
+        final int _result;
+        if (_stmt.step()) {
+          _result = (int) (_stmt.getLong(0));
+        } else {
+          _result = 0;
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -228,38 +206,34 @@
     StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
     _stringBuilder.append(")");
     final String _sql = _stringBuilder.toString();
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, int[]>() {
-      @Override
-      @NonNull
-      public int[] invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          if (ids == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (int _item : ids) {
-              _stmt.bindLong(_argIndex, _item);
-              _argIndex++;
-            }
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item : ids) {
+            _stmt.bindLong(_argIndex, _item);
+            _argIndex++;
           }
-          final List<Integer> _listResult = new ArrayList<Integer>();
-          while (_stmt.step()) {
-            final Integer _item_1;
-            _item_1 = (int) (_stmt.getLong(0));
-            _listResult.add(_item_1);
-          }
-          final int[] _tmpArrayResult = new int[_listResult.size()];
-          int _index = 0;
-          for (int _listItem : _listResult) {
-            _tmpArrayResult[_index] = _listItem;
-            _index++;
-          }
-          final int[] _result = _tmpArrayResult;
-          return _result;
-        } finally {
-          _stmt.close();
         }
+        final List<Integer> _listResult = new ArrayList<Integer>();
+        while (_stmt.step()) {
+          final Integer _item_1;
+          _item_1 = (int) (_stmt.getLong(0));
+          _listResult.add(_item_1);
+        }
+        final int[] _tmpArrayResult = new int[_listResult.size()];
+        int _index = 0;
+        for (int _listItem : _listResult) {
+          _tmpArrayResult[_index] = _listItem;
+          _index++;
+        }
+        final int[] _result = _tmpArrayResult;
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -272,39 +246,35 @@
     StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
     _stringBuilder.append(")");
     final String _sql = _stringBuilder.toString();
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Integer>>() {
-      @Override
-      @NonNull
-      public List<Integer> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          if (ids == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (Integer _item : ids) {
-              if (_item == null) {
-                _stmt.bindNull(_argIndex);
-              } else {
-                _stmt.bindLong(_argIndex, _item);
-              }
-              _argIndex++;
-            }
-          }
-          final List<Integer> _result = new ArrayList<Integer>();
-          while (_stmt.step()) {
-            final Integer _item_1;
-            if (_stmt.isNull(0)) {
-              _item_1 = null;
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (Integer _item : ids) {
+            if (_item == null) {
+              _stmt.bindNull(_argIndex);
             } else {
-              _item_1 = (int) (_stmt.getLong(0));
+              _stmt.bindLong(_argIndex, _item);
             }
-            _result.add(_item_1);
+            _argIndex++;
           }
-          return _result;
-        } finally {
-          _stmt.close();
         }
+        final List<Integer> _result = new ArrayList<Integer>();
+        while (_stmt.step()) {
+          final Integer _item_1;
+          if (_stmt.isNull(0)) {
+            _item_1 = null;
+          } else {
+            _item_1 = (int) (_stmt.getLong(0));
+          }
+          _result.add(_item_1);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -324,57 +294,53 @@
     StringUtil.appendPlaceholders(_stringBuilder, _inputSize_2);
     _stringBuilder.append(")");
     final String _sql = _stringBuilder.toString();
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Integer>>() {
-      @Override
-      @NonNull
-      public List<Integer> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          if (ids1 == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (Integer _item : ids1) {
-              if (_item == null) {
-                _stmt.bindNull(_argIndex);
-              } else {
-                _stmt.bindLong(_argIndex, _item);
-              }
-              _argIndex++;
-            }
-          }
-          _argIndex = 1 + _inputSize;
-          if (ids2 == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (int _item_1 : ids2) {
-              _stmt.bindLong(_argIndex, _item_1);
-              _argIndex++;
-            }
-          }
-          _argIndex = 1 + _inputSize + _inputSize_1;
-          if (ids3 == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (int _item_2 : ids3) {
-              _stmt.bindLong(_argIndex, _item_2);
-              _argIndex++;
-            }
-          }
-          final List<Integer> _result = new ArrayList<Integer>();
-          while (_stmt.step()) {
-            final Integer _item_3;
-            if (_stmt.isNull(0)) {
-              _item_3 = null;
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (ids1 == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (Integer _item : ids1) {
+            if (_item == null) {
+              _stmt.bindNull(_argIndex);
             } else {
-              _item_3 = (int) (_stmt.getLong(0));
+              _stmt.bindLong(_argIndex, _item);
             }
-            _result.add(_item_3);
+            _argIndex++;
           }
-          return _result;
-        } finally {
-          _stmt.close();
         }
+        _argIndex = 1 + _inputSize;
+        if (ids2 == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item_1 : ids2) {
+            _stmt.bindLong(_argIndex, _item_1);
+            _argIndex++;
+          }
+        }
+        _argIndex = 1 + _inputSize + _inputSize_1;
+        if (ids3 == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item_2 : ids3) {
+            _stmt.bindLong(_argIndex, _item_2);
+            _argIndex++;
+          }
+        }
+        final List<Integer> _result = new ArrayList<Integer>();
+        while (_stmt.step()) {
+          final Integer _item_3;
+          if (_stmt.isNull(0)) {
+            _item_3 = null;
+          } else {
+            _item_3 = (int) (_stmt.getLong(0));
+          }
+          _result.add(_item_3);
+        }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -477,38 +443,34 @@
   @Override
   public List<Child1> getChild1List() {
     final String _sql = "SELECT * FROM Child1";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Child1>>() {
-      @Override
-      @NonNull
-      public List<Child1> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          final int _cursorIndexOfId = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "id");
-          final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
-          final int _cursorIndexOfSerial = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "serial");
-          final int _cursorIndexOfCode = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "code");
-          final List<Child1> _result = new ArrayList<Child1>();
-          while (_stmt.step()) {
-            final Child1 _item;
-            final int _tmpId;
-            _tmpId = (int) (_stmt.getLong(_cursorIndexOfId));
-            final String _tmpName;
-            _tmpName = _stmt.getText(_cursorIndexOfName);
-            final Info _tmpInfo;
-            if (!(_stmt.isNull(_cursorIndexOfSerial) && _stmt.isNull(_cursorIndexOfCode))) {
-              _tmpInfo = new Info();
-              _tmpInfo.serial = (int) (_stmt.getLong(_cursorIndexOfSerial));
-              _tmpInfo.code = _stmt.getText(_cursorIndexOfCode);
-            } else {
-              _tmpInfo = null;
-            }
-            _item = new Child1(_tmpId,_tmpName,_tmpInfo);
-            _result.add(_item);
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        final int _cursorIndexOfId = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "id");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfSerial = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "serial");
+        final int _cursorIndexOfCode = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "code");
+        final List<Child1> _result = new ArrayList<Child1>();
+        while (_stmt.step()) {
+          final Child1 _item;
+          final int _tmpId;
+          _tmpId = (int) (_stmt.getLong(_cursorIndexOfId));
+          final String _tmpName;
+          _tmpName = _stmt.getText(_cursorIndexOfName);
+          final Info _tmpInfo;
+          if (!(_stmt.isNull(_cursorIndexOfSerial) && _stmt.isNull(_cursorIndexOfCode))) {
+            _tmpInfo = new Info();
+            _tmpInfo.serial = (int) (_stmt.getLong(_cursorIndexOfSerial));
+            _tmpInfo.code = _stmt.getText(_cursorIndexOfCode);
+          } else {
+            _tmpInfo = null;
           }
-          return _result;
-        } finally {
-          _stmt.close();
+          _item = new Child1(_tmpId,_tmpName,_tmpInfo);
+          _result.add(_item);
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -516,38 +478,34 @@
   @Override
   public List<Child2> getChild2List() {
     final String _sql = "SELECT * FROM Child2";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<Child2>>() {
-      @Override
-      @NonNull
-      public List<Child2> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          final int _cursorIndexOfId = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "id");
-          final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
-          final int _cursorIndexOfSerial = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "serial");
-          final int _cursorIndexOfCode = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "code");
-          final List<Child2> _result = new ArrayList<Child2>();
-          while (_stmt.step()) {
-            final Child2 _item;
-            final int _tmpId;
-            _tmpId = (int) (_stmt.getLong(_cursorIndexOfId));
-            final String _tmpName;
-            _tmpName = _stmt.getText(_cursorIndexOfName);
-            final Info _tmpInfo;
-            if (!(_stmt.isNull(_cursorIndexOfSerial) && _stmt.isNull(_cursorIndexOfCode))) {
-              _tmpInfo = new Info();
-              _tmpInfo.serial = (int) (_stmt.getLong(_cursorIndexOfSerial));
-              _tmpInfo.code = _stmt.getText(_cursorIndexOfCode);
-            } else {
-              _tmpInfo = null;
-            }
-            _item = new Child2(_tmpId,_tmpName,_tmpInfo);
-            _result.add(_item);
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        final int _cursorIndexOfId = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "id");
+        final int _cursorIndexOfName = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "name");
+        final int _cursorIndexOfSerial = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "serial");
+        final int _cursorIndexOfCode = SQLiteStatementUtil.getColumnIndexOrThrow(_stmt, "code");
+        final List<Child2> _result = new ArrayList<Child2>();
+        while (_stmt.step()) {
+          final Child2 _item;
+          final int _tmpId;
+          _tmpId = (int) (_stmt.getLong(_cursorIndexOfId));
+          final String _tmpName;
+          _tmpName = _stmt.getText(_cursorIndexOfName);
+          final Info _tmpInfo;
+          if (!(_stmt.isNull(_cursorIndexOfSerial) && _stmt.isNull(_cursorIndexOfCode))) {
+            _tmpInfo = new Info();
+            _tmpInfo.serial = (int) (_stmt.getLong(_cursorIndexOfSerial));
+            _tmpInfo.code = _stmt.getText(_cursorIndexOfCode);
+          } else {
+            _tmpInfo = null;
           }
-          return _result;
-        } finally {
-          _stmt.close();
+          _item = new Child2(_tmpId,_tmpName,_tmpInfo);
+          _result.add(_item);
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -595,26 +553,22 @@
   @Override
   public List<UserSummary> getUserNames() {
     final String _sql = "SELECT `uid`, `name` FROM (SELECT * FROM User)";
-    return DBUtil.performBlocking(__db, true, false, new Function1<SQLiteConnection, List<UserSummary>>() {
-      @Override
-      @NonNull
-      public List<UserSummary> invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          final int _cursorIndexOfUid = 0;
-          final int _cursorIndexOfName = 1;
-          final List<UserSummary> _result = new ArrayList<UserSummary>();
-          while (_stmt.step()) {
-            final UserSummary _item;
-            _item = new UserSummary();
-            _item.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
-            _item.name = _stmt.getText(_cursorIndexOfName);
-            _result.add(_item);
-          }
-          return _result;
-        } finally {
-          _stmt.close();
+    return DBUtil.performBlocking(__db, true, false, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        final int _cursorIndexOfUid = 0;
+        final int _cursorIndexOfName = 1;
+        final List<UserSummary> _result = new ArrayList<UserSummary>();
+        while (_stmt.step()) {
+          final UserSummary _item;
+          _item = new UserSummary();
+          _item.uid = (int) (_stmt.getLong(_cursorIndexOfUid));
+          _item.name = _stmt.getText(_cursorIndexOfName);
+          _result.add(_item);
         }
+        return _result;
+      } finally {
+        _stmt.close();
       }
     });
   }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
index 30b9808..4d0654d 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
@@ -8,7 +8,6 @@
 import androidx.room.util.DBUtil;
 import androidx.room.util.SQLiteConnectionUtil;
 import androidx.room.util.StringUtil;
-import androidx.sqlite.SQLiteConnection;
 import androidx.sqlite.SQLiteStatement;
 import androidx.sqlite.db.SupportSQLiteStatement;
 import io.reactivex.Completable;
@@ -26,7 +25,6 @@
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
-import kotlin.jvm.functions.Function1;
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation", "removal"})
@@ -98,91 +96,63 @@
 
   @Override
   public void deleteUser(final User user) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __deleteAdapterOfUser.handle(_connection, user);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handle(_connection, user);
+      return null;
     });
   }
 
   @Override
   public void deleteUsers(final User user1, final List<User> others) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __deleteAdapterOfUser.handle(_connection, user1);
-        __deleteAdapterOfUser.handleMultiple(_connection, others);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handle(_connection, user1);
+      __deleteAdapterOfUser.handleMultiple(_connection, others);
+      return null;
     });
   }
 
   @Override
   public void deleteArrayOfUsers(final User[] users) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __deleteAdapterOfUser.handleMultiple(_connection, users);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handleMultiple(_connection, users);
+      return null;
     });
   }
 
   @Override
   public Integer deleteUserAndReturnCountObject(final User user) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __deleteAdapterOfUser.handle(_connection, user);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handle(_connection, user);
+      return _result;
     });
   }
 
   @Override
   public int deleteUserAndReturnCount(final User user) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __deleteAdapterOfUser.handle(_connection, user);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handle(_connection, user);
+      return _result;
     });
   }
 
   @Override
   public int deleteUserAndReturnCount(final User user1, final List<User> others) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __deleteAdapterOfUser.handle(_connection, user1);
-        _result += __deleteAdapterOfUser.handleMultiple(_connection, others);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handle(_connection, user1);
+      _result += __deleteAdapterOfUser.handleMultiple(_connection, others);
+      return _result;
     });
   }
 
   @Override
   public int deleteUserAndReturnCount(final User[] users) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __deleteAdapterOfUser.handleMultiple(_connection, users);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfUser.handleMultiple(_connection, users);
+      return _result;
     });
   }
 
@@ -244,46 +214,34 @@
 
   @Override
   public int multiPKey(final MultiPKeyEntity entity) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __deleteAdapterOfMultiPKeyEntity.handle(_connection, entity);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __deleteAdapterOfMultiPKeyEntity.handle(_connection, entity);
+      return _result;
     });
   }
 
   @Override
   public void deleteUserAndBook(final User user, final Book book) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __deleteAdapterOfUser.handle(_connection, user);
-        __deleteAdapterOfBook.handle(_connection, book);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __deleteAdapterOfUser.handle(_connection, user);
+      __deleteAdapterOfBook.handle(_connection, book);
+      return null;
     });
   }
 
   @Override
   public int deleteByUid(final int uid) {
     final String _sql = "DELETE FROM user where uid = ?";
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          _stmt.bindLong(_argIndex, uid);
-          _stmt.step();
-          return SQLiteConnectionUtil.getTotalChangedRows(_connection);
-        } finally {
-          _stmt.close();
-        }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindLong(_argIndex, uid);
+        _stmt.step();
+        return SQLiteConnectionUtil.getTotalChangedRows(_connection);
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -362,26 +320,22 @@
     StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
     _stringBuilder.append(")");
     final String _sql = _stringBuilder.toString();
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          if (uid == null) {
-            _stmt.bindNull(_argIndex);
-          } else {
-            for (int _item : uid) {
-              _stmt.bindLong(_argIndex, _item);
-              _argIndex++;
-            }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        if (uid == null) {
+          _stmt.bindNull(_argIndex);
+        } else {
+          for (int _item : uid) {
+            _stmt.bindLong(_argIndex, _item);
+            _argIndex++;
           }
-          _stmt.step();
-          return SQLiteConnectionUtil.getTotalChangedRows(_connection);
-        } finally {
-          _stmt.close();
         }
+        _stmt.step();
+        return SQLiteConnectionUtil.getTotalChangedRows(_connection);
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -389,17 +343,13 @@
   @Override
   public int deleteEverything() {
     final String _sql = "DELETE FROM user";
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          _stmt.step();
-          return SQLiteConnectionUtil.getTotalChangedRows(_connection);
-        } finally {
-          _stmt.close();
-        }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        _stmt.step();
+        return SQLiteConnectionUtil.getTotalChangedRows(_connection);
+      } finally {
+        _stmt.close();
       }
     });
   }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
index 484b1e8..49a5436 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
@@ -6,7 +6,6 @@
 import androidx.room.EntityDeletionOrUpdateAdapter;
 import androidx.room.RoomDatabase;
 import androidx.room.util.DBUtil;
-import androidx.sqlite.SQLiteConnection;
 import androidx.sqlite.SQLiteStatement;
 import androidx.sqlite.db.SupportSQLiteStatement;
 import io.reactivex.Completable;
@@ -23,8 +22,6 @@
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
-import kotlin.Unit;
-import kotlin.jvm.functions.Function1;
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation", "removal"})
@@ -126,104 +123,72 @@
 
   @Override
   public void updateUser(final User user) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __updateAdapterOfUser.handle(_connection, user);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handle(_connection, user);
+      return null;
     });
   }
 
   @Override
   public void updateUsers(final User user1, final List<User> others) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __updateAdapterOfUser.handle(_connection, user1);
-        __updateAdapterOfUser.handleMultiple(_connection, others);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handle(_connection, user1);
+      __updateAdapterOfUser.handleMultiple(_connection, others);
+      return null;
     });
   }
 
   @Override
   public void updateArrayOfUsers(final User[] users) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __updateAdapterOfUser.handleMultiple(_connection, users);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser.handleMultiple(_connection, users);
+      return null;
     });
   }
 
   @Override
   public void updateTwoUsers(final User userOne, final User userTwo) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __updateAdapterOfUser_1.handle(_connection, userOne);
-        __updateAdapterOfUser_1.handle(_connection, userTwo);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __updateAdapterOfUser_1.handle(_connection, userOne);
+      __updateAdapterOfUser_1.handle(_connection, userTwo);
+      return null;
     });
   }
 
   @Override
   public int updateUserAndReturnCount(final User user) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __updateAdapterOfUser.handle(_connection, user);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handle(_connection, user);
+      return _result;
     });
   }
 
   @Override
   public int updateUserAndReturnCount(final User user1, final List<User> others) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __updateAdapterOfUser.handle(_connection, user1);
-        _result += __updateAdapterOfUser.handleMultiple(_connection, others);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handle(_connection, user1);
+      _result += __updateAdapterOfUser.handleMultiple(_connection, others);
+      return _result;
     });
   }
 
   @Override
   public int updateUserAndReturnCount(final User[] users) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __updateAdapterOfUser.handleMultiple(_connection, users);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handleMultiple(_connection, users);
+      return _result;
     });
   }
 
   @Override
   public Integer updateUserAndReturnCountObject(final User user) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __updateAdapterOfUser.handle(_connection, user);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfUser.handle(_connection, user);
+      return _result;
     });
   }
 
@@ -285,54 +250,34 @@
 
   @Override
   public int multiPKey(final MultiPKeyEntity entity) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Integer>() {
-      @Override
-      @NonNull
-      public Integer invoke(@NonNull final SQLiteConnection _connection) {
-        int _result = 0;
-        _result += __updateAdapterOfMultiPKeyEntity.handle(_connection, entity);
-        return _result;
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      int _result = 0;
+      _result += __updateAdapterOfMultiPKeyEntity.handle(_connection, entity);
+      return _result;
     });
   }
 
   @Override
   public void updateUserAndBook(final User user, final Book book) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __updateAdapterOfUser.handle(_connection, user);
-        __updateAdapterOfBook.handle(_connection, book);
-        return null;
-      }
-    });
-  }
-
-  @Override
-  public void updateAndAge(final User user) {
     DBUtil.performBlocking(__db, false, true, (_connection) -> {
-          UpdateDao.super.updateAndAge(user);
-          return Unit.INSTANCE;
-        });
+      __updateAdapterOfUser.handle(_connection, user);
+      __updateAdapterOfBook.handle(_connection, book);
+      return null;
+    });
   }
 
   @Override
   public void ageUserByUid(final String uid) {
     final String _sql = "UPDATE User SET ageColumn = ageColumn + 1 WHERE uid = ?";
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          int _argIndex = 1;
-          _stmt.bindText(_argIndex, uid);
-          _stmt.step();
-          return null;
-        } finally {
-          _stmt.close();
-        }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        int _argIndex = 1;
+        _stmt.bindText(_argIndex, uid);
+        _stmt.step();
+        return null;
+      } finally {
+        _stmt.close();
       }
     });
   }
@@ -340,17 +285,13 @@
   @Override
   public void ageUserAll() {
     final String _sql = "UPDATE User SET ageColumn = ageColumn + 1";
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        final SQLiteStatement _stmt = _connection.prepare(_sql);
-        try {
-          _stmt.step();
-          return null;
-        } finally {
-          _stmt.close();
-        }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      final SQLiteStatement _stmt = _connection.prepare(_sql);
+      try {
+        _stmt.step();
+        return null;
+      } finally {
+        _stmt.close();
       }
     });
   }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
index 7e6b603..a3f22bb 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
@@ -6,18 +6,14 @@
 import androidx.room.EntityUpsertAdapter;
 import androidx.room.RoomDatabase;
 import androidx.room.util.DBUtil;
-import androidx.sqlite.SQLiteConnection;
 import androidx.sqlite.SQLiteStatement;
 import java.lang.Class;
-import java.lang.Long;
 import java.lang.Override;
 import java.lang.String;
 import java.lang.SuppressWarnings;
-import java.lang.Void;
 import java.util.Collections;
 import java.util.List;
 import javax.annotation.processing.Generated;
-import kotlin.jvm.functions.Function1;
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation", "removal"})
@@ -90,86 +86,58 @@
 
   @Override
   public void upsertUser(final User user) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __upsertAdapterOfUser.upsert(_connection, user);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, user);
+      return null;
     });
   }
 
   @Override
   public void upsertUsers(final User user1, final List<User> others) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __upsertAdapterOfUser.upsert(_connection, user1);
-        __upsertAdapterOfUser.upsert(_connection, others);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, user1);
+      __upsertAdapterOfUser.upsert(_connection, others);
+      return null;
     });
   }
 
   @Override
   public void upsertUsers(final User[] users) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __upsertAdapterOfUser.upsert(_connection, users);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, users);
+      return null;
     });
   }
 
   @Override
   public void upsertTwoUsers(final User userOne, final User userTwo) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __upsertAdapterOfUser.upsert(_connection, userOne);
-        __upsertAdapterOfUser.upsert(_connection, userTwo);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, userOne);
+      __upsertAdapterOfUser.upsert(_connection, userTwo);
+      return null;
     });
   }
 
   @Override
   public void upsertUserAndBook(final User user, final Book book) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __upsertAdapterOfUser.upsert(_connection, user);
-        __upsertAdapterOfBook.upsert(_connection, book);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __upsertAdapterOfUser.upsert(_connection, user);
+      __upsertAdapterOfBook.upsert(_connection, book);
+      return null;
     });
   }
 
   @Override
   public long upsertAndReturnId(final User user) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Long>() {
-      @Override
-      @NonNull
-      public Long invoke(@NonNull final SQLiteConnection _connection) {
-        return __upsertAdapterOfUser.upsertAndReturnId(_connection, user);
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      return __upsertAdapterOfUser.upsertAndReturnId(_connection, user);
     });
   }
 
   @Override
   public long[] upsertAndReturnIdsArray(final User[] users) {
-    return DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, long[]>() {
-      @Override
-      @NonNull
-      public long[] invoke(@NonNull final SQLiteConnection _connection) {
-        return __upsertAdapterOfUser.upsertAndReturnIdsArray(_connection, users);
-      }
+    return DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      return __upsertAdapterOfUser.upsertAndReturnIdsArray(_connection, users);
     });
   }
 
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
index 2ed9e20..2a4d60d 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
@@ -4,17 +4,14 @@
 import androidx.room.EntityInsertAdapter;
 import androidx.room.RoomDatabase;
 import androidx.room.util.DBUtil;
-import androidx.sqlite.SQLiteConnection;
 import androidx.sqlite.SQLiteStatement;
 import java.lang.Class;
 import java.lang.Override;
 import java.lang.String;
 import java.lang.SuppressWarnings;
-import java.lang.Void;
 import java.util.Collections;
 import java.util.List;
 import javax.annotation.processing.Generated;
-import kotlin.jvm.functions.Function1;
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation", "removal"})
@@ -93,64 +90,44 @@
 
   @Override
   public void insertUser(final User user) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __insertAdapterOfUser.insert(_connection, user);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser.insert(_connection, user);
+      return null;
     });
   }
 
   @Override
   public void insertUsers(final User user1, final List<User> others) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __insertAdapterOfUser.insert(_connection, user1);
-        __insertAdapterOfUser.insert(_connection, others);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser.insert(_connection, user1);
+      __insertAdapterOfUser.insert(_connection, others);
+      return null;
     });
   }
 
   @Override
   public void insertUsers(final User[] users) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __insertAdapterOfUser_1.insert(_connection, users);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser_1.insert(_connection, users);
+      return null;
     });
   }
 
   @Override
   public void insertTwoUsers(final User userOne, final User userTwo) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __insertAdapterOfUser_2.insert(_connection, userOne);
-        __insertAdapterOfUser_2.insert(_connection, userTwo);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser_2.insert(_connection, userOne);
+      __insertAdapterOfUser_2.insert(_connection, userTwo);
+      return null;
     });
   }
 
   @Override
   public void insertUserAndBook(final User user, final Book book) {
-    DBUtil.performBlocking(__db, false, true, new Function1<SQLiteConnection, Void>() {
-      @Override
-      @NonNull
-      public Void invoke(@NonNull final SQLiteConnection _connection) {
-        __insertAdapterOfUser.insert(_connection, user);
-        __insertAdapterOfBook.insert(_connection, book);
-        return null;
-      }
+    DBUtil.performBlocking(__db, false, true, (_connection) -> {
+      __insertAdapterOfUser.insert(_connection, user);
+      __insertAdapterOfBook.insert(_connection, book);
+      return null;
     });
   }
 
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
index 4daf31c..c03a592 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
@@ -152,8 +152,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, false) {
-        __fetchRelationshipArtistAsArtist(_connection, it)
+      recursiveFetchMap(_map, false) { _tmpMap ->
+        __fetchRelationshipArtistAsArtist(_connection, _tmpMap)
       }
       return
     }
@@ -198,8 +198,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, true) {
-        __fetchRelationshipSongAsSong(_connection, it)
+      recursiveFetchMap(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong(_connection, _tmpMap)
       }
       return
     }
@@ -248,8 +248,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, true) {
-        __fetchRelationshipSongAsSong_1(_connection, it)
+      recursiveFetchMap(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong_1(_connection, _tmpMap)
       }
       return
     }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
index 4b43e32..6a397c8 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
@@ -153,8 +153,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchArrayMap(_map, false) {
-        __fetchRelationshipArtistAsArtist(_connection, it)
+      recursiveFetchArrayMap(_map, false) { _tmpMap ->
+        __fetchRelationshipArtistAsArtist(_connection, _tmpMap)
       }
       return
     }
@@ -199,8 +199,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchArrayMap(_map, true) {
-        __fetchRelationshipSongAsSong(_connection, it)
+      recursiveFetchArrayMap(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong(_connection, _tmpMap)
       }
       return
     }
@@ -249,8 +249,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchArrayMap(_map, true) {
-        __fetchRelationshipSongAsSong_1(_connection, it)
+      recursiveFetchArrayMap(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong_1(_connection, _tmpMap)
       }
       return
     }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
index 136a991..c843aef 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
@@ -78,8 +78,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, false) {
-        __fetchRelationshipArtistAsArtist(_connection, it)
+      recursiveFetchMap(_map, false) { _tmpMap ->
+        __fetchRelationshipArtistAsArtist(_connection, _tmpMap)
       }
       return
     }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
index 5760d95..5096b2b 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
@@ -151,8 +151,8 @@
       return
     }
     if (_map.size() > 999) {
-      recursiveFetchLongSparseArray(_map, false) {
-        __fetchRelationshipArtistAsArtist(_connection, it)
+      recursiveFetchLongSparseArray(_map, false) { _tmpMap ->
+        __fetchRelationshipArtistAsArtist(_connection, _tmpMap)
       }
       return
     }
@@ -197,8 +197,8 @@
       return
     }
     if (_map.size() > 999) {
-      recursiveFetchLongSparseArray(_map, true) {
-        __fetchRelationshipSongAsSong(_connection, it)
+      recursiveFetchLongSparseArray(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong(_connection, _tmpMap)
       }
       return
     }
@@ -247,8 +247,8 @@
       return
     }
     if (_map.size() > 999) {
-      recursiveFetchLongSparseArray(_map, true) {
-        __fetchRelationshipSongAsSong_1(_connection, it)
+      recursiveFetchLongSparseArray(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong_1(_connection, _tmpMap)
       }
       return
     }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
index 15d43af..015fc74 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
@@ -167,8 +167,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, false) {
-        __fetchRelationshipArtistAsArtist(_connection, it)
+      recursiveFetchMap(_map, false) { _tmpMap ->
+        __fetchRelationshipArtistAsArtist(_connection, _tmpMap)
       }
       return
     }
@@ -213,8 +213,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, true) {
-        __fetchRelationshipSongAsSong(_connection, it)
+      recursiveFetchMap(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong(_connection, _tmpMap)
       }
       return
     }
@@ -273,8 +273,8 @@
       return
     }
     if (_map.size > 999) {
-      recursiveFetchMap(_map, true) {
-        __fetchRelationshipSongAsSong_1(_connection, it)
+      recursiveFetchMap(_map, true) { _tmpMap ->
+        __fetchRelationshipSongAsSong_1(_connection, _tmpMap)
       }
       return
     }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_abstractClass.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_abstractClass.kt
index 0a7097a..37885f5 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_abstractClass.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_abstractClass.kt
@@ -18,7 +18,7 @@
     this.__db = __db
   }
 
-  public override fun baseConcrete(): Unit = performBlocking(__db, false, true) {
+  public override fun baseConcrete(): Unit = performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.baseConcrete()
   }
 
@@ -26,11 +26,11 @@
     super@MyDao_Impl.baseSuspendConcrete()
   }
 
-  public override fun concrete(): Unit = performBlocking(__db, false, true) {
+  public override fun concrete(): Unit = performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.concrete()
   }
 
-  internal override fun concreteInternal(): Unit = performBlocking(__db, false, true) {
+  internal override fun concreteInternal(): Unit = performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.concreteInternal()
   }
 
@@ -39,7 +39,7 @@
   }
 
   public override fun concreteWithVararg(vararg arr: Long): Unit = performBlocking(__db, false,
-      true) {
+      true) { _ ->
     super@MyDao_Impl.concreteWithVararg(*arr)
   }
 
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_interface.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_interface.kt
index c4590e2..95deee1 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_interface.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/transactionMethodAdapter_interface.kt
@@ -21,7 +21,7 @@
     this.__db = __db
   }
 
-  public override fun baseConcrete(): Unit = performBlocking(__db, false, true) {
+  public override fun baseConcrete(): Unit = performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.baseConcrete()
   }
 
@@ -29,21 +29,21 @@
     super@MyDao_Impl.baseSuspendConcrete()
   }
 
-  public override fun concrete(): Unit = performBlocking(__db, false, true) {
+  public override fun concrete(): Unit = performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.concrete()
   }
 
-  public override fun concreteWithReturn(): String = performBlocking(__db, false, true) {
+  public override fun concreteWithReturn(): String = performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.concreteWithReturn()
   }
 
   public override fun concreteWithParamsAndReturn(text: String, num: Long): String =
-      performBlocking(__db, false, true) {
+      performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.concreteWithParamsAndReturn(text, num)
   }
 
   public override fun concreteWithFunctionalParam(block: Function0<Unit>): Unit =
-      performBlocking(__db, false, true) {
+      performBlocking(__db, false, true) { _ ->
     super@MyDao_Impl.concreteWithFunctionalParam(block)
   }