ProcessorErrors.kt revision 13a2048db98b1cc2dbd1692b73b794527975a446
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
17package com.android.support.room.processor
18
19import com.android.support.room.Delete
20import com.android.support.room.Insert
21import com.android.support.room.Query
22import com.android.support.room.ext.RoomTypeNames
23import com.android.support.room.vo.Field
24import com.android.support.room.vo.Pojo
25import com.squareup.javapoet.TypeName
26import javax.lang.model.type.TypeMirror
27
28object ProcessorErrors {
29    val MISSING_QUERY_ANNOTATION = "Query methods must be annotated with ${Query::class.java}"
30    val MISSING_INSERT_ANNOTATION = "Insertion methods must be annotated with ${Insert::class.java}"
31    val MISSING_DELETE_ANNOTATION = "Deletion methods must be annotated with ${Delete::class.java}"
32    val INVALID_ON_CONFLICT_VALUE = "On conflict value must be one of Insert.OnConflict values."
33    val INVALID_INSERTION_METHOD_RETURN_TYPE = "Methods annotated with @Insert can return either" +
34            " void, long, long[] or List<Long>."
35    val ABSTRACT_METHOD_IN_DAO_MISSING_ANY_ANNOTATION = "Abstract method in DAO must be annotated" +
36            " with ${Query::class.java} AND ${Insert::class.java}"
37    val CANNOT_USE_MORE_THAN_ONE_DAO_METHOD_ANNOTATION = "A DAO method can be annotated with only" +
38            " one of the following:" + DaoProcessor.PROCESSED_ANNOTATIONS.joinToString(",") {
39        it.java.simpleName
40    }
41    val CANNOT_RESOLVE_RETURN_TYPE = "Cannot resolve return type for %s"
42    val CANNOT_USE_UNBOUND_GENERICS_IN_QUERY_METHODS = "Cannot use unbound generics in query" +
43            " methods. It must be bound to a type through base Dao class."
44    val CANNOT_USE_UNBOUND_GENERICS_IN_INSERTION_METHODS = "Cannot use unbound generics in" +
45            " insertion methods. It must be bound to a type through base Dao class."
46    val CANNOT_USE_UNBOUND_GENERICS_IN_ENTITY_FIELDS = "Cannot use unbound fields in entities."
47    val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." +
48            " If you are trying to create a base DAO, create a normal class, extend it with type" +
49            " params then mark the subclass with @Dao."
50    val CANNOT_FIND_GETTER_FOR_FIELD = "Cannot find getter for field."
51    val CANNOT_FIND_SETTER_FOR_FIELD = "Cannot find setter for field."
52    val MISSING_PRIMARY_KEY = "An entity must have at least 1 field annotated with @PrimaryKey"
53    val DAO_MUST_BE_AN_ABSTRACT_CLASS_OR_AN_INTERFACE = "Dao class must be an abstract class or" +
54            " an interface"
55    val DATABASE_MUST_BE_ANNOTATED_WITH_DATABASE = "Database must be annotated with @Database"
56    val DAO_MUST_BE_ANNOTATED_WITH_DAO = "Dao class must be annotated with @Dao"
57    val ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY = "Entity class must be annotated with @Entity"
58    val DATABASE_ANNOTATION_MUST_HAVE_LIST_OF_ENTITIES = "@Database annotation must specify list" +
59            " of entities"
60    val COLUMN_NAME_CANNOT_BE_EMPTY = "Column name cannot be blank. If you don't want to set it" +
61            ", just remove the @ColumnName annotation."
62
63    val ENTITY_TABLE_NAME_CANNOT_BE_EMPTY = "Entity table name cannot be blank. If you don't want" +
64            " to set it, just remove the tableName property."
65
66    val CANNOT_CONVERT_QUERY_PARAMETER_TO_STRING = "Query method parameters should either be a" +
67            " type that can be converted into String or a List / Array that contains such type."
68
69    val QUERY_PARAMETERS_CANNOT_START_WITH_UNDERSCORE = "Query/Insert method parameters cannot " +
70            "start with underscore (_)."
71
72    val CANNOT_FIND_QUERY_RESULT_ADAPTER = "Not sure how to convert a Cursor to this method's " +
73            "return type"
74
75    val INSERTION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_INSERT = "Method annotated with" +
76            " @Insert but does not have any parameters to insert."
77
78    val INSERTION_METHOD_PARAMETERS_MUST_HAVE_THE_SAME_ENTITY_TYPE = "Parameter types in " +
79            "insertion methods must be the same type. If you want to insert entities from " +
80            "different types atomically, use a transaction."
81
82    val DELETION_DOES_NOT_HAVE_ANY_PARAMETERS_TO_DELETE = "Method annotated with" +
83            " @Delete but does not have any parameters to delete."
84
85    val DELETION_METHOD_PARAMETERS_MUST_HAVE_THE_SAME_ENTITY_TYPE = "Parameter types in " +
86            "deletion methods must be the same type. If you want to delete entities from " +
87            "different types atomically, use a transaction."
88
89    val CANNOT_FIND_ENTITY_FOR_SHORTCUT_QUERY_PARAMETER = "Type of the parameter must be a class " +
90            "annotated with @Entity or a collection/array of it."
91
92    val DB_MUST_EXTEND_ROOM_DB = "Classes annotated with @Database should extend " +
93            RoomTypeNames.ROOM_DB
94
95    val LIVE_DATA_QUERY_WITHOUT_SELECT = "LiveData return type can only be used with SELECT" +
96            " queries."
97
98    private val TOO_MANY_MATCHING_GETTERS = "Ambiguous getter for %s. All of the following " +
99            "match: %s. You can @Ignore the ones that you don't want to match."
100
101    fun tooManyMatchingGetters(field: Field, methodNames: List<String>): String {
102        return TOO_MANY_MATCHING_GETTERS.format(field, methodNames.joinToString(", "))
103    }
104
105    private val TOO_MANY_MATCHING_SETTERS = "Ambiguous setter for %s. All of the following " +
106            "match: %s. You can @Ignore the ones that you don't want to match."
107
108    fun tooManyMatchingSetter(field: Field, methodNames: List<String>): String {
109        return TOO_MANY_MATCHING_SETTERS.format(field, methodNames.joinToString(", "))
110    }
111
112    private val MISSING_PARAMETER_FOR_BIND = "Each bind variable in the query must have a" +
113            " matching method parameter. Cannot find method parameters for %s."
114
115    fun missingParameterForBindVariable(bindVarName: List<String>): String {
116        return MISSING_PARAMETER_FOR_BIND.format(bindVarName.joinToString(", "))
117    }
118
119    private val UNUSED_QUERY_METHOD_PARAMETER = "Unused parameter%s: %s"
120    fun unusedQueryMethodParameter(unusedParams: List<String>): String {
121        return UNUSED_QUERY_METHOD_PARAMETER.format(
122                if (unusedParams.size > 1) "s" else "",
123                unusedParams.joinToString(","))
124    }
125
126    private val DUPLICATE_TABLES = "Table name \"%s\" is used by multiple entities: %s"
127    fun duplicateTableNames(tableName: String, entityNames: List<String>): String {
128        return DUPLICATE_TABLES.format(tableName, entityNames.joinToString(", "))
129    }
130
131    val DELETION_METHODS_MUST_RETURN_VOID_OR_INT = "Deletion methods must either return void or" +
132            " return int (the number of deleted rows)."
133
134    val DAO_METHOD_CONFLICTS_WITH_OTHERS = "Dao method has conflicts."
135
136    fun duplicateDao(dao: TypeName, methodNames: List<String>): String {
137        return """
138                All of these functions (${methodNames.joinToString(", ")}) return the same DAO
139                class ($dao).
140                A database can use a DAO only once so you should remove ${methodNames.size - 1} of
141                these conflicting DAO methods. If you are implementing any of these to fulfill an
142                interface, don't make it abstract, instead, implement the code that calls the
143                other one.
144                """.trimIndent().replace(System.lineSeparator(), " ")
145    }
146
147    fun cursorPojoMismatch(pojoTypeName: TypeName,
148                           unusedColumns: List<String>, allColumns: List<String>,
149                           unusedFields: List<Field>, allFields: List<Field>): String {
150        val unusedColumnsWarning = if (unusedColumns.isNotEmpty()) { """
151                The query returns some columns (${unusedColumns.joinToString(", ")}) which are not
152                use by $pojoTypeName. You can use @ColumnName annotation on the fields to specify
153                the mapping.
154            """.trimIndent().replace(System.lineSeparator(), " ")
155        } else {
156            ""
157        }
158        val unusedFieldsWarning = if (unusedFields.isNotEmpty()) { """
159                $pojoTypeName has some fields
160                (${unusedFields.joinToString(", ") { it.columnName }}) which are not returned by the
161                query. If they are not supposed to be read from the result, you can mark them with
162                @Ignore annotation.
163            """.trimIndent().replace(System.lineSeparator(), " ")
164        } else {
165            ""
166        }
167        return """
168            $unusedColumnsWarning
169            $unusedFieldsWarning
170            You can suppress this warning by annotating the method with
171            @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH).
172            Columns returned by the query: ${allColumns.joinToString(", ")}.
173            Fields in $pojoTypeName: ${allFields.joinToString(", ") { it.columnName }}.
174            """.trimIndent().replace(System.lineSeparator(), " ")
175    }
176
177}
178