1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.room.processor
18 
19 import androidx.room.Delete
20 import androidx.room.Insert
21 import androidx.room.Query
22 import androidx.room.RawQuery
23 import androidx.room.Update
24 import androidx.room.ext.RoomTypeNames
25 import androidx.room.ext.SupportDbTypeNames
26 import androidx.room.parser.SQLTypeAffinity
27 import androidx.room.vo.CustomTypeConverter
28 import androidx.room.vo.Field
29 import com.squareup.javapoet.TypeName
30 
31 object ProcessorErrors {
trimnull32     private fun String.trim(): String {
33         return this.trimIndent().replace("\n", " ")
34     }
35     val MISSING_QUERY_ANNOTATION = "Query methods must be annotated with ${Query::class.java}"
36     val MISSING_INSERT_ANNOTATION = "Insertion methods must be annotated with ${Insert::class.java}"
37     val MISSING_DELETE_ANNOTATION = "Deletion methods must be annotated with ${Delete::class.java}"
38     val MISSING_UPDATE_ANNOTATION = "Update methods must be annotated with ${Update::class.java}"
39     val MISSING_RAWQUERY_ANNOTATION = "RawQuery methods must be annotated with" +
40             " ${RawQuery::class.java}"
41     val INVALID_ON_CONFLICT_VALUE = "On conflict value must be one of @OnConflictStrategy values."
42     val INVALID_INSERTION_METHOD_RETURN_TYPE = "Methods annotated with @Insert can return either" +
43             " void, long, Long, long[], Long[] or List<Long>."
44     val TRANSACTION_REFERENCE_DOCS = "https://developer.android.com/reference/android/arch/" +
45             "persistence/room/Transaction.html"
46 
insertionMethodReturnTypeMismatchnull47     fun insertionMethodReturnTypeMismatch(definedReturn: TypeName,
48                                           expectedReturnTypes: List<TypeName>): String {
49         return "Method returns $definedReturn but it should return one of the following: `" +
50                 expectedReturnTypes.joinToString(", ") + "`. If you want to return the list of" +
51                 " row ids from the query, your insertion method can receive only 1 parameter."
52     }
53 
54     val ABSTRACT_METHOD_IN_DAO_MISSING_ANY_ANNOTATION = "Abstract method in DAO must be annotated" +
55             " with ${Query::class.java} AND ${Insert::class.java}"
56     val INVALID_ANNOTATION_COUNT_IN_DAO_METHOD = "An abstract DAO method must be" +
57             " annotated with one and only one of the following annotations: " +
<lambda>null58             DaoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") {
59         it.java.simpleName
60     }
61     val CANNOT_RESOLVE_RETURN_TYPE = "Cannot resolve return type for %s"
62     val CANNOT_USE_UNBOUND_GENERICS_IN_QUERY_METHODS = "Cannot use unbound generics in query" +
63             " methods. It must be bound to a type through base Dao class."
64     val CANNOT_USE_UNBOUND_GENERICS_IN_INSERTION_METHODS = "Cannot use unbound generics in" +
65             " insertion methods. It must be bound to a type through base Dao class."
66     val CANNOT_USE_UNBOUND_GENERICS_IN_ENTITY_FIELDS = "Cannot use unbound fields in entities."
67     val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." +
68             " If you are trying to create a base DAO, create a normal class, extend it with type" +
69             " params then mark the subclass with @Dao."
70     val CANNOT_FIND_GETTER_FOR_FIELD = "Cannot find getter for field."
71     val CANNOT_FIND_SETTER_FOR_FIELD = "Cannot find setter for field."
72     val MISSING_PRIMARY_KEY = "An entity must have at least 1 field annotated with @PrimaryKey"
73     val AUTO_INCREMENTED_PRIMARY_KEY_IS_NOT_INT = "If a primary key is annotated with" +
74             " autoGenerate, its type must be int, Integer, long or Long."
75     val AUTO_INCREMENT_EMBEDDED_HAS_MULTIPLE_FIELDS = "When @PrimaryKey annotation is used on a" +
76             " field annotated with @Embedded, the embedded class should have only 1 field."
77 
multiplePrimaryKeyAnnotationsnull78     fun multiplePrimaryKeyAnnotations(primaryKeys: List<String>): String {
79         return """
80                 You cannot have multiple primary keys defined in an Entity. If you
81                 want to declare a composite primary key, you should use @Entity#primaryKeys and
82                 not use @PrimaryKey. Defined Primary Keys:
83                 ${primaryKeys.joinToString(", ")}""".trim()
84     }
85 
primaryKeyColumnDoesNotExistnull86     fun primaryKeyColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
87         return "$columnName referenced in the primary key does not exists in the Entity." +
88                 " Available column names:${allColumns.joinToString(", ")}"
89     }
90 
91     val DAO_MUST_BE_AN_ABSTRACT_CLASS_OR_AN_INTERFACE = "Dao class must be an abstract class or" +
92             " an interface"
93     val DATABASE_MUST_BE_ANNOTATED_WITH_DATABASE = "Database must be annotated with @Database"
94     val DAO_MUST_BE_ANNOTATED_WITH_DAO = "Dao class must be annotated with @Dao"
95 
daoMustHaveMatchingConstructornull96     fun daoMustHaveMatchingConstructor(daoName: String, dbName: String): String {
97         return """
98                 $daoName needs to have either an empty constructor or a constructor that takes
99                 $dbName as its only parameter.
100                 """.trim()
101     }
102 
103     val ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY = "Entity class must be annotated with @Entity"
104     val DATABASE_ANNOTATION_MUST_HAVE_LIST_OF_ENTITIES = "@Database annotation must specify list" +
105             " of entities"
106     val COLUMN_NAME_CANNOT_BE_EMPTY = "Column name cannot be blank. If you don't want to set it" +
107             ", just remove the @ColumnInfo annotation or use @ColumnInfo.INHERIT_FIELD_NAME."
108 
109     val ENTITY_TABLE_NAME_CANNOT_BE_EMPTY = "Entity table name cannot be blank. If you don't want" +
110             " to set it, just remove the tableName property."
111 
112     val CANNOT_BIND_QUERY_PARAMETER_INTO_STMT = "Query method parameters should either be a" +
113             " type that can be converted into a database column or a List / Array that contains" +
114             " such type. You can consider adding a Type Adapter for this."
115 
116     val QUERY_PARAMETERS_CANNOT_START_WITH_UNDERSCORE = "Query/Insert method parameters cannot " +
117             "start with underscore (_)."
118 
119     val CANNOT_FIND_QUERY_RESULT_ADAPTER = "Not sure how to convert a Cursor to this method's " +
120             "return type"
121 
122     val INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT = "Method annotated with" +
123             " @Insert but does not have any parameters to insert."
124 
125     val DELETION_MISSING_PARAMS = "Method annotated with" +
126             " @Delete but does not have any parameters to delete."
127 
128     val UPDATE_MISSING_PARAMS = "Method annotated with" +
129             " @Update but does not have any parameters to update."
130 
131     val TRANSACTION_METHOD_MODIFIERS = "Method annotated with @Transaction must not be " +
132             "private, final, or abstract. It can be abstract only if the method is also" +
133             " annotated with @Query."
134 
135     val TRANSACTION_MISSING_ON_RELATION = "The return value includes a Pojo with a @Relation." +
136             " It is usually desired to annotate this method with @Transaction to avoid" +
137             " possibility of inconsistent results between the Pojo and its relations. See " +
138             TRANSACTION_REFERENCE_DOCS + " for details."
139 
140     val CANNOT_FIND_ENTITY_FOR_SHORTCUT_QUERY_PARAMETER = "Type of the parameter must be a class " +
141             "annotated with @Entity or a collection/array of it."
142 
143     val DB_MUST_EXTEND_ROOM_DB = "Classes annotated with @Database should extend " +
144             RoomTypeNames.ROOM_DB
145 
146     val LIVE_DATA_QUERY_WITHOUT_SELECT = "LiveData return type can only be used with SELECT" +
147             " queries."
148 
149     val OBSERVABLE_QUERY_NOTHING_TO_OBSERVE = "Observable query return type (LiveData, Flowable" +
150             ", DataSource, DataSourceFactory etc) can only be used with SELECT queries that" +
151             " directly or indirectly (via @Relation, for example) access at least one table. For" +
152             " @RawQuery, you should specify the list of tables to be observed via the" +
153             " observedEntities field."
154 
155     val RECURSIVE_REFERENCE_DETECTED = "Recursive referencing through @Embedded and/or @Relation " +
156             "detected: %s"
157 
158     private val TOO_MANY_MATCHING_GETTERS = "Ambiguous getter for %s. All of the following " +
159             "match: %s. You can @Ignore the ones that you don't want to match."
160 
tooManyMatchingGettersnull161     fun tooManyMatchingGetters(field: Field, methodNames: List<String>): String {
162         return TOO_MANY_MATCHING_GETTERS.format(field, methodNames.joinToString(", "))
163     }
164 
165     private val TOO_MANY_MATCHING_SETTERS = "Ambiguous setter for %s. All of the following " +
166             "match: %s. You can @Ignore the ones that you don't want to match."
167 
tooManyMatchingSetternull168     fun tooManyMatchingSetter(field: Field, methodNames: List<String>): String {
169         return TOO_MANY_MATCHING_SETTERS.format(field, methodNames.joinToString(", "))
170     }
171 
172     val CANNOT_FIND_COLUMN_TYPE_ADAPTER = "Cannot figure out how to save this field into" +
173             " database. You can consider adding a type converter for it."
174 
175     val CANNOT_FIND_STMT_BINDER = "Cannot figure out how to bind this field into a statement."
176 
177     val CANNOT_FIND_CURSOR_READER = "Cannot figure out how to read this field from a cursor."
178 
179     private val MISSING_PARAMETER_FOR_BIND = "Each bind variable in the query must have a" +
180             " matching method parameter. Cannot find method parameters for %s."
181 
missingParameterForBindVariablenull182     fun missingParameterForBindVariable(bindVarName: List<String>): String {
183         return MISSING_PARAMETER_FOR_BIND.format(bindVarName.joinToString(", "))
184     }
185 
186     private val UNUSED_QUERY_METHOD_PARAMETER = "Unused parameter%s: %s"
unusedQueryMethodParameternull187     fun unusedQueryMethodParameter(unusedParams: List<String>): String {
188         return UNUSED_QUERY_METHOD_PARAMETER.format(
189                 if (unusedParams.size > 1) "s" else "",
190                 unusedParams.joinToString(","))
191     }
192 
193     private val DUPLICATE_TABLES = "Table name \"%s\" is used by multiple entities: %s"
duplicateTableNamesnull194     fun duplicateTableNames(tableName: String, entityNames: List<String>): String {
195         return DUPLICATE_TABLES.format(tableName, entityNames.joinToString(", "))
196     }
197 
198     val DELETION_METHODS_MUST_RETURN_VOID_OR_INT = "Deletion methods must either return void or" +
199             " return int (the number of deleted rows)."
200 
201     val UPDATE_METHODS_MUST_RETURN_VOID_OR_INT = "Update methods must either return void or" +
202             " return int (the number of updated rows)."
203 
204     val DAO_METHOD_CONFLICTS_WITH_OTHERS = "Dao method has conflicts."
205 
duplicateDaonull206     fun duplicateDao(dao: TypeName, methodNames: List<String>): String {
207         return """
208                 All of these functions [${methodNames.joinToString(", ")}] return the same DAO
209                 class [$dao].
210                 A database can use a DAO only once so you should remove ${methodNames.size - 1} of
211                 these conflicting DAO methods. If you are implementing any of these to fulfill an
212                 interface, don't make it abstract, instead, implement the code that calls the
213                 other one.
214                 """.trim()
215     }
216 
pojoMissingNonNullnull217     fun pojoMissingNonNull(pojoTypeName: TypeName, missingPojoFields: List<String>,
218                            allQueryColumns: List<String>): String {
219         return """
220         The columns returned by the query does not have the fields
221         [${missingPojoFields.joinToString(",")}] in $pojoTypeName even though they are
222         annotated as non-null or primitive.
223         Columns returned by the query: [${allQueryColumns.joinToString(",")}]
224         """.trim()
225     }
226 
cursorPojoMismatchnull227     fun cursorPojoMismatch(pojoTypeName: TypeName,
228                            unusedColumns: List<String>, allColumns: List<String>,
229                            unusedFields: List<Field>, allFields: List<Field>): String {
230         val unusedColumnsWarning = if (unusedColumns.isNotEmpty()) {
231             """
232                 The query returns some columns [${unusedColumns.joinToString(", ")}] which are not
233                 use by $pojoTypeName. You can use @ColumnInfo annotation on the fields to specify
234                 the mapping.
235             """.trim()
236         } else {
237             ""
238         }
239         val unusedFieldsWarning = if (unusedFields.isNotEmpty()) {
240             """
241                 $pojoTypeName has some fields
242                 [${unusedFields.joinToString(", ") { it.columnName }}] which are not returned by the
243                 query. If they are not supposed to be read from the result, you can mark them with
244                 @Ignore annotation.
245             """.trim()
246         } else {
247             ""
248         }
249         return """
250             $unusedColumnsWarning
251             $unusedFieldsWarning
252             You can suppress this warning by annotating the method with
253             @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH).
254             Columns returned by the query: ${allColumns.joinToString(", ")}.
255             Fields in $pojoTypeName: ${allFields.joinToString(", ") { it.columnName }}.
256             """.trim()
257     }
258 
259     val TYPE_CONVERTER_UNBOUND_GENERIC = "Cannot use unbound generics in Type Converters."
260     val TYPE_CONVERTER_BAD_RETURN_TYPE = "Invalid return type for a type converter."
261     val TYPE_CONVERTER_MUST_RECEIVE_1_PARAM = "Type converters must receive 1 parameter."
262     val TYPE_CONVERTER_EMPTY_CLASS = "Class is referenced as a converter but it does not have any" +
263             " converter methods."
264     val TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR = "Classes that are used as TypeConverters must" +
265             " have no-argument public constructors."
266     val TYPE_CONVERTER_MUST_BE_PUBLIC = "Type converters must be public."
267 
duplicateTypeConvertersnull268     fun duplicateTypeConverters(converters: List<CustomTypeConverter>): String {
269         return "Multiple methods define the same conversion. Conflicts with these:" +
270                 " ${converters.joinToString(", ") { it.toString() }}"
271     }
272 
273     // TODO must print field paths.
274     val POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME = "Field has non-unique column name."
275 
pojoDuplicateFieldNamesnull276     fun pojoDuplicateFieldNames(columnName: String, fieldPaths: List<String>): String {
277         return "Multiple fields have the same columnName: $columnName." +
278                 " Field names: ${fieldPaths.joinToString(", ")}."
279     }
280 
embeddedPrimaryKeyIsDroppednull281     fun embeddedPrimaryKeyIsDropped(entityQName: String, fieldName: String): String {
282         return "Primary key constraint on $fieldName is ignored when being merged into " +
283                 entityQName
284     }
285 
286     val INDEX_COLUMNS_CANNOT_BE_EMPTY = "List of columns in an index cannot be empty"
287 
indexColumnDoesNotExistnull288     fun indexColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
289         return "$columnName referenced in the index does not exists in the Entity." +
290                 " Available column names:${allColumns.joinToString(", ")}"
291     }
292 
duplicateIndexInEntitynull293     fun duplicateIndexInEntity(indexName: String): String {
294         return "There are multiple indices with name $indexName. This happen if you've declared" +
295                 " the same index multiple times or different indices have the same name. See" +
296                 " @Index documentation for details."
297     }
298 
duplicateIndexInDatabasenull299     fun duplicateIndexInDatabase(indexName: String, indexPaths: List<String>): String {
300         return "There are multiple indices with name $indexName. You should rename " +
301                 "${indexPaths.size - 1} of these to avoid the conflict:" +
302                 "${indexPaths.joinToString(", ")}."
303     }
304 
droppedEmbeddedFieldIndexnull305     fun droppedEmbeddedFieldIndex(fieldPath: String, grandParent: String): String {
306         return "The index will be dropped when being merged into $grandParent" +
307                 "($fieldPath). You must re-declare it in $grandParent if you want to index this" +
308                 " field in $grandParent."
309     }
310 
droppedEmbeddedIndexnull311     fun droppedEmbeddedIndex(entityName: String, fieldPath: String, grandParent: String): String {
312         return "Indices defined in $entityName will be dropped when it is merged into" +
313                 " $grandParent ($fieldPath). You can re-declare them in $grandParent."
314     }
315 
droppedSuperClassIndexnull316     fun droppedSuperClassIndex(childEntity: String, superEntity: String): String {
317         return "Indices defined in $superEntity will NOT be re-used in $childEntity. If you want" +
318                 " to inherit them, you must re-declare them in $childEntity." +
319                 " Alternatively, you can set inheritSuperIndices to true in the @Entity annotation."
320     }
321 
droppedSuperClassFieldIndexnull322     fun droppedSuperClassFieldIndex(fieldName: String, childEntity: String,
323                                     superEntity: String): String {
324         return "Index defined on field `$fieldName` in $superEntity will NOT be re-used in" +
325                 " $childEntity. " +
326                 "If you want to inherit it, you must re-declare it in $childEntity." +
327                 " Alternatively, you can set inheritSuperIndices to true in the @Entity annotation."
328     }
329 
330     val RELATION_NOT_COLLECTION = "Fields annotated with @Relation must be a List or Set."
331 
relationCannotFindEntityFieldnull332     fun relationCannotFindEntityField(entityName: String, columnName: String,
333                                       availableColumns: List<String>): String {
334         return "Cannot find the child entity column `$columnName` in $entityName." +
335                 " Options: ${availableColumns.joinToString(", ")}"
336     }
337 
relationCannotFindParentEntityFieldnull338     fun relationCannotFindParentEntityField(entityName: String, columnName: String,
339                                             availableColumns: List<String>): String {
340         return "Cannot find the parent entity column `$columnName` in $entityName." +
341                 " Options: ${availableColumns.joinToString(", ")}"
342     }
343 
344     val RELATION_IN_ENTITY = "Entities cannot have relations."
345 
346     val CANNOT_FIND_TYPE = "Cannot find type."
347 
relationAffinityMismatchnull348     fun relationAffinityMismatch(parentColumn: String, childColumn: String,
349                                  parentAffinity: SQLTypeAffinity?,
350                                  childAffinity: SQLTypeAffinity?): String {
351         return """
352         The affinity of parent column ($parentColumn : $parentAffinity) does not match the type
353         affinity of the child column ($childColumn : $childAffinity).
354         """.trim()
355     }
356 
357     val CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION = "A field can be annotated with only" +
<lambda>null358             " one of the following:" + PojoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") {
359         it.java.simpleName
360     }
361 
relationBadProjectnull362     fun relationBadProject(entityQName: String, missingColumnNames: List<String>,
363                            availableColumnNames: List<String>): String {
364         return """
365         $entityQName does not have the following columns: ${missingColumnNames.joinToString(",")}.
366         Available columns are: ${availableColumnNames.joinToString(",")}
367         """.trim()
368     }
369 
370     val MISSING_SCHEMA_EXPORT_DIRECTORY = "Schema export directory is not provided to the" +
371             " annotation processor so we cannot export the schema. You can either provide" +
372             " `room.schemaLocation` annotation processor argument OR set exportSchema to false."
373 
374     val INVALID_FOREIGN_KEY_ACTION = "Invalid foreign key action. It must be one of the constants" +
375             " defined in ForeignKey.Action"
376 
foreignKeyNotAnEntitynull377     fun foreignKeyNotAnEntity(className: String): String {
378         return """
379         Classes referenced in Foreign Key annotations must be @Entity classes. $className is not
380         an entity
381         """.trim()
382     }
383 
384     val FOREIGN_KEY_CANNOT_FIND_PARENT = "Cannot find parent entity class."
385 
foreignKeyChildColumnDoesNotExistnull386     fun foreignKeyChildColumnDoesNotExist(columnName: String, allColumns: List<String>): String {
387         return "($columnName) referenced in the foreign key does not exists in the Entity." +
388                 " Available column names:${allColumns.joinToString(", ")}"
389     }
390 
foreignKeyParentColumnDoesNotExistnull391     fun foreignKeyParentColumnDoesNotExist(parentEntity: String,
392                                            missingColumn: String,
393                                            allColumns: List<String>): String {
394         return "($missingColumn) does not exist in $parentEntity. Available columns are" +
395                 " ${allColumns.joinToString(",")}"
396     }
397 
398     val FOREIGN_KEY_EMPTY_CHILD_COLUMN_LIST = "Must specify at least 1 column name for the child"
399 
400     val FOREIGN_KEY_EMPTY_PARENT_COLUMN_LIST = "Must specify at least 1 column name for the parent"
401 
foreignKeyColumnNumberMismatchnull402     fun foreignKeyColumnNumberMismatch(
403             childColumns: List<String>, parentColumns: List<String>): String {
404         return """
405                 Number of child columns in foreign key must match number of parent columns.
406                 Child reference has ${childColumns.joinToString(",")} and parent reference has
407                 ${parentColumns.joinToString(",")}
408                """.trim()
409     }
410 
foreignKeyMissingParentEntityInDatabasenull411     fun foreignKeyMissingParentEntityInDatabase(parentTable: String, childEntity: String): String {
412         return """
413                 $parentTable table referenced in the foreign keys of $childEntity does not exist in
414                 the database. Maybe you forgot to add the referenced entity in the entities list of
415                 the @Database annotation?""".trim()
416     }
417 
foreignKeyMissingIndexInParentnull418     fun foreignKeyMissingIndexInParent(parentEntity: String, parentColumns: List<String>,
419                                        childEntity: String, childColumns: List<String>): String {
420         return """
421                 $childEntity has a foreign key (${childColumns.joinToString(",")}) that references
422                 $parentEntity (${parentColumns.joinToString(",")}) but $parentEntity does not have
423                 a unique index on those columns nor the columns are its primary key.
424                 SQLite requires having a unique constraint on referenced parent columns so you must
425                 add a unique index to $parentEntity that has
426                 (${parentColumns.joinToString(",")}) column(s).
427                """.trim()
428     }
429 
foreignKeyMissingIndexInChildColumnsnull430     fun foreignKeyMissingIndexInChildColumns(childColumns: List<String>): String {
431         return """
432                 (${childColumns.joinToString(",")}) column(s) reference a foreign key but
433                 they are not part of an index. This may trigger full table scans whenever parent
434                 table is modified so you are highly advised to create an index that covers these
435                 columns.
436                """.trim()
437     }
438 
foreignKeyMissingIndexInChildColumnnull439     fun foreignKeyMissingIndexInChildColumn(childColumn: String): String {
440         return """
441                 $childColumn column references a foreign key but it is not part of an index. This
442                 may trigger full table scans whenever parent table is modified so you are highly
443                 advised to create an index that covers this column.
444                """.trim()
445     }
446 
shortcutEntityIsNotInDatabasenull447     fun shortcutEntityIsNotInDatabase(database: String, dao: String, entity: String): String {
448         return """
449                 $dao is part of $database but this entity is not in the database. Maybe you forgot
450                 to add $entity to the entities section of the @Database?
451                 """.trim()
452     }
453 
454     val MISSING_ROOM_GUAVA_ARTIFACT = "To use Guava features, you must add `guava`" +
455             " artifact from Room as a dependency. androidx.room:guava:<version>"
456 
457     val MISSING_ROOM_RXJAVA2_ARTIFACT = "To use RxJava2 features, you must add `rxjava2`" +
458             " artifact from Room as a dependency. androidx.room:rxjava2:<version>"
459 
ambigiousConstructornull460     fun ambigiousConstructor(
461             pojo: String, paramName: String, matchingFields: List<String>): String {
462         return """
463             Ambiguous constructor. The parameter ($paramName) in $pojo matches multiple fields:
464             [${matchingFields.joinToString(",")}]. If you don't want to use this constructor,
465             you can annotate it with @Ignore. If you want Room to use this constructor, you can
466             rename the parameters to exactly match the field name to fix the ambiguity.
467             """.trim()
468     }
469 
470     val MISSING_POJO_CONSTRUCTOR = """
471             Entities and Pojos must have a usable public constructor. You can have an empty
472             constructor or a constructor whose parameters match the fields (by name and type).
473             """.trim()
474 
475     val TOO_MANY_POJO_CONSTRUCTORS = """
476             Room cannot pick a constructor since multiple constructors are suitable. Try to annotate
477             unwanted constructors with @Ignore.
478             """.trim()
479 
480     val TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG = """
481             There are multiple good constructors and Room will pick the no-arg constructor.
482             You can use the @Ignore annotation to eliminate unwanted constructors.
483             """.trim()
484 
485     val RELATION_CANNOT_BE_CONSTRUCTOR_PARAMETER = """
486             Fields annotated with @Relation cannot be constructor parameters. These values are
487             fetched after the object is constructed.
488             """.trim()
489 
490     val PAGING_SPECIFY_DATA_SOURCE_TYPE = "For now, Room only supports PositionalDataSource class."
491 
primaryKeyNullnull492     fun primaryKeyNull(field: String): String {
493         return "You must annotate primary keys with @NonNull. \"$field\" is nullable. SQLite " +
494                 "considers this a " +
495                 "bug and Room does not allow it. See SQLite docs for details: " +
496                 "https://www.sqlite.org/lang_createtable.html"
497     }
498 
499     val INVALID_COLUMN_NAME = "Invalid column name. Room does not allow using ` or \" in column" +
500             " names"
501 
502     val INVALID_TABLE_NAME = "Invalid table name. Room does not allow using ` or \" in table names"
503 
504     val RAW_QUERY_BAD_PARAMS = "RawQuery methods should have 1 and only 1 parameter with type" +
505             " String or SupportSQLiteQuery"
506 
507     val RAW_QUERY_BAD_RETURN_TYPE = "RawQuery methods must return a non-void type."
508 
rawQueryBadEntitynull509     fun rawQueryBadEntity(typeName: TypeName): String {
510         return """
511             observedEntities field in RawQuery must either reference a class that is annotated
512             with @Entity or it should reference a Pojo that either contains @Embedded fields that
513             are annotated with @Entity or @Relation fields.
514             $typeName does not have these properties, did you mean another class?
515             """.trim()
516     }
517 
518     val RAW_QUERY_STRING_PARAMETER_REMOVED = "RawQuery does not allow passing a string anymore." +
519             " Please use ${SupportDbTypeNames.QUERY}."
520 }
521