Conditionally error due to missing getter/setter based on binding scope.
When processing a POJO with binding scope to bind to query only, then
it is OK if the POJO has no setter or constructor. Likewise if a POJO
with binding scope to read from cursor, then it is OK to have no
getter. When the binding scope is two-way, then both getters and
setters are needed (or getter and matching constructor).
Bug: 138664463
Test: PojoProcessorTest
Change-Id: I1324f2e55174aa9999498666000b86591d05e970
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index efebfac..653ae86 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -707,7 +707,9 @@
context.logger.e(field.element,
ProcessorErrors.tooManyMatchingGetters(field, matching))
})
- context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD)
+ context.checker.check(
+ success || bindingScope == FieldProcessor.BindingScope.READ_FROM_CURSOR,
+ field.element, CANNOT_FIND_GETTER_FOR_FIELD)
}
private fun assignSetters(
@@ -756,7 +758,9 @@
context.logger.e(field.element,
ProcessorErrors.tooManyMatchingSetter(field, matching))
})
- context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD)
+ context.checker.check(
+ success || bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT,
+ field.element, CANNOT_FIND_SETTER_FOR_FIELD)
}
/**
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
index 4dd648a..106c34f 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
@@ -1482,6 +1482,132 @@
ProcessorErrors.missingIgnoredColumns(listOf("no_such_column")))
}
+ @Test
+ fun noSetter_scopeBindStmt() {
+ simpleRun(
+ """
+ package foo.bar;
+ import androidx.room.*;
+ public class ${MY_POJO.simpleName()} {
+ private String foo;
+ private String bar;
+
+ public String getFoo() { return foo; }
+ public String getBar() { return bar; }
+ }
+ """.toJFO(MY_POJO.toString())) { invocation ->
+ PojoProcessor.createFor(context = invocation.context,
+ element = invocation.typeElement(MY_POJO.toString()),
+ bindingScope = FieldProcessor.BindingScope.BIND_TO_STMT,
+ parent = null).process()
+ }.compilesWithoutError()
+ }
+
+ @Test
+ fun noSetter_scopeTwoWay() {
+ simpleRun(
+ """
+ package foo.bar;
+ import androidx.room.*;
+ public class ${MY_POJO.simpleName()} {
+ private String foo;
+ private String bar;
+
+ public String getFoo() { return foo; }
+ public String getBar() { return bar; }
+ }
+ """.toJFO(MY_POJO.toString())) { invocation ->
+ PojoProcessor.createFor(context = invocation.context,
+ element = invocation.typeElement(MY_POJO.toString()),
+ bindingScope = FieldProcessor.BindingScope.TWO_WAY,
+ parent = null).process()
+ }.failsToCompile().withErrorContaining("Cannot find setter for field.")
+ }
+
+ @Test
+ fun noSetter_scopeReadFromCursor() {
+ simpleRun(
+ """
+ package foo.bar;
+ import androidx.room.*;
+ public class ${MY_POJO.simpleName()} {
+ private String foo;
+ private String bar;
+
+ public String getFoo() { return foo; }
+ public String getBar() { return bar; }
+ }
+ """.toJFO(MY_POJO.toString())) { invocation ->
+ PojoProcessor.createFor(context = invocation.context,
+ element = invocation.typeElement(MY_POJO.toString()),
+ bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
+ parent = null).process()
+ }.failsToCompile().withErrorContaining("Cannot find setter for field.")
+ }
+
+ @Test
+ fun noGetter_scopeBindStmt() {
+ simpleRun(
+ """
+ package foo.bar;
+ import androidx.room.*;
+ public class ${MY_POJO.simpleName()} {
+ private String foo;
+ private String bar;
+
+ public void setFoo(String foo) { this.foo = foo; }
+ public void setBar(String bar) { this.bar = bar; }
+ }
+ """.toJFO(MY_POJO.toString())) { invocation ->
+ PojoProcessor.createFor(context = invocation.context,
+ element = invocation.typeElement(MY_POJO.toString()),
+ bindingScope = FieldProcessor.BindingScope.BIND_TO_STMT,
+ parent = null).process()
+ }.failsToCompile().withErrorContaining("Cannot find getter for field.")
+ }
+
+ @Test
+ fun noGetter_scopeTwoWay() {
+ simpleRun(
+ """
+ package foo.bar;
+ import androidx.room.*;
+ public class ${MY_POJO.simpleName()} {
+ private String foo;
+ private String bar;
+
+ public void setFoo(String foo) { this.foo = foo; }
+ public void setBar(String bar) { this.bar = bar; }
+ }
+ """.toJFO(MY_POJO.toString())) { invocation ->
+ PojoProcessor.createFor(context = invocation.context,
+ element = invocation.typeElement(MY_POJO.toString()),
+ bindingScope = FieldProcessor.BindingScope.TWO_WAY,
+ parent = null).process()
+ }.failsToCompile().withErrorContaining("Cannot find getter for field.")
+ }
+
+ @Test
+ fun noGetter_scopeReadCursor() {
+ simpleRun(
+ """
+ package foo.bar;
+ import androidx.room.*;
+ public class ${MY_POJO.simpleName()} {
+ private String foo;
+ private String bar;
+
+ public void setFoo(String foo) { this.foo = foo; }
+ public void setBar(String bar) { this.bar = bar; }
+ }
+ """.toJFO(MY_POJO.toString())) { invocation ->
+ PojoProcessor.createFor(context = invocation.context,
+ element = invocation.typeElement(MY_POJO.toString()),
+ bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
+ parent = null).process()
+ }.compilesWithoutError()
+ }
+
private fun singleRun(
code: String,
vararg jfos: JavaFileObject,
@@ -1523,7 +1649,7 @@
handler.invoke(
PojoProcessor.createFor(context = invocation.context,
element = invocation.typeElement(MY_POJO.toString()),
- bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
+ bindingScope = FieldProcessor.BindingScope.TWO_WAY,
parent = null).process(),
invocation
)
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt
index 6cadb2f..8dae07b0 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt
@@ -33,6 +33,7 @@
import androidx.room.integration.kotlintestapp.vo.BookWithPublisher
import androidx.room.integration.kotlintestapp.vo.DateConverter
import androidx.room.integration.kotlintestapp.vo.Lang
+import androidx.room.integration.kotlintestapp.vo.MiniBook
import androidx.room.integration.kotlintestapp.vo.Publisher
import androidx.room.integration.kotlintestapp.vo.PublisherWithBookSales
import androidx.room.integration.kotlintestapp.vo.PublisherWithBooks
@@ -116,6 +117,9 @@
@Insert
fun addBooks(vararg books: Book)
+ @Insert(entity = Book::class)
+ fun addMiniBook(miniBook: MiniBook)
+
@Insert
fun addBookAuthors(vararg bookAuthors: BookAuthor)
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt
index 6d7b7a7..21292d5 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt
@@ -16,6 +16,7 @@
package androidx.room.integration.kotlintestapp.vo
+import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@@ -30,7 +31,9 @@
@PrimaryKey val bookId: String,
val title: String,
val bookPublisherId: String,
+ @ColumnInfo(defaultValue = "0")
@field:TypeConverters(Lang::class)
val languages: Set<Lang>,
+ @ColumnInfo(defaultValue = "0")
val salesCnt: Int
)
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/MiniBook.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/MiniBook.kt
new file mode 100644
index 0000000..42d013a
--- /dev/null
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/MiniBook.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.integration.kotlintestapp.vo
+
+import androidx.room.PrimaryKey
+
+data class MiniBook(
+ @PrimaryKey val bookId: String,
+ val title: String,
+ val bookPublisherId: String
+)
\ No newline at end of file