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