PojoProcessor.kt revision 2fb00f11f2e6d90edf678daaa921a3ef1b55a51b
113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/* 213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Copyright (C) 2017 The Android Open Source Project 313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * 413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * you may not use this file except in compliance with the License. 613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * You may obtain a copy of the License at 713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * 813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * 1013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Unless required by applicable law or agreed to in writing, software 1113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 1213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * See the License for the specific language governing permissions and 1413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * limitations under the License. 1513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */ 1613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 1764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarpackage android.arch.persistence.room.processor 1813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 1964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ColumnInfo 204d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyarimport android.arch.persistence.room.Embedded 2164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.Ignore 22b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.Relation 2364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAllFieldsIncludingPrivateSupers 2464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAnnotationValue 2564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAsString 2664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.getAsStringList 2764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.hasAnnotation 2864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.hasAnyOf 292fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyarimport android.arch.persistence.room.ext.isAssignableWithoutVariance 3064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.isCollection 3164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.toClassType 3264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD 3364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD 3464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_TYPE 3564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME 3664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.cache.Cache 3764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.CallType 3864db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Constructor 394d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyarimport android.arch.persistence.room.vo.EmbeddedField 4064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Entity 41b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.vo.Field 42b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.vo.FieldGetter 4364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.FieldSetter 4464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Pojo 45b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.vo.Warning 46092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport com.google.auto.common.AnnotationMirrors 4713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreElements 4813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreTypes 4913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.ExecutableElement 5013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.ABSTRACT 5113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.PRIVATE 525bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PROTECTED 535bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PUBLIC 5413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.STATIC 55a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyarimport javax.lang.model.element.Modifier.TRANSIENT 561a74519922de68e007027d56aae9370ee21f31f9shepshapardimport javax.lang.model.element.Name 5713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.TypeElement 58092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport javax.lang.model.element.VariableElement 5996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarimport javax.lang.model.type.DeclaredType 6013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.type.TypeKind 615bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.type.TypeMirror 62f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyarimport javax.lang.model.util.ElementFilter 6313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 6413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/** 6513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Processes any class as if it is a Pojo. 6613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */ 671a74519922de68e007027d56aae9370ee21f31f9shepshapardclass PojoProcessor(baseContext: Context, 681a74519922de68e007027d56aae9370ee21f31f9shepshapard val element: TypeElement, 6996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val bindingScope: FieldProcessor.BindingScope, 701a74519922de68e007027d56aae9370ee21f31f9shepshapard val parent: EmbeddedField?, 711a74519922de68e007027d56aae9370ee21f31f9shepshapard val referenceStack: LinkedHashSet<Name> = LinkedHashSet<Name>()) { 72aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar val context = baseContext.fork(element) 73092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar companion object { 744d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val PROCESSED_ANNOTATIONS = listOf(ColumnInfo::class, Embedded::class, 75092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar Relation::class) 76092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 776f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas fun process(): Pojo { 785124503104860e68981cc3e3092b95932586f66fYigit Boyar return context.cache.pojos.get(Cache.PojoKey(element, bindingScope, parent), { 791a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack.add(element.qualifiedName) 801a74519922de68e007027d56aae9370ee21f31f9shepshapard try { 811a74519922de68e007027d56aae9370ee21f31f9shepshapard doProcess() 826f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas } finally { 831a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack.remove(element.qualifiedName) 841a74519922de68e007027d56aae9370ee21f31f9shepshapard } 855124503104860e68981cc3e3092b95932586f66fYigit Boyar }) 865124503104860e68981cc3e3092b95932586f66fYigit Boyar } 875124503104860e68981cc3e3092b95932586f66fYigit Boyar 885124503104860e68981cc3e3092b95932586f66fYigit Boyar private fun doProcess(): Pojo { 8913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar val declaredType = MoreTypes.asDeclared(element.asType()) 9096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar // TODO handle conflicts with super: b/35568142 9196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val allFields = element.getAllFieldsIncludingPrivateSupers(context.processingEnv) 9213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar .filter { 93a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar !it.hasAnnotation(Ignore::class) 94a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar && !it.hasAnyOf(STATIC) 95a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar && (!it.hasAnyOf(TRANSIENT) 96a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar || it.hasAnnotation(ColumnInfo::class) 97a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar || it.hasAnnotation(Embedded::class) 98a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyar || it.hasAnnotation(Relation::class)) 9996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar } 100092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .groupBy { field -> 101092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.checker.check( 102092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar PROCESSED_ANNOTATIONS.count { field.hasAnnotation(it) } < 2, field, 103092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION 104092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ) 1054d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar if (field.hasAnnotation(Embedded::class)) { 1064d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar Embedded::class 107092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } else if (field.hasAnnotation(Relation::class)) { 108092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar Relation::class 109092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } else { 110092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar null 111092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 112092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 1131a74519922de68e007027d56aae9370ee21f31f9shepshapard 114092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val myFields = allFields[null] 115092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ?.map { 11696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar FieldProcessor( 11796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar baseContext = context, 11896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar containing = declaredType, 11996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar element = it, 12096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar bindingScope = bindingScope, 12196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar fieldParent = parent).process() 122092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } ?: emptyList() 123092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 1241a74519922de68e007027d56aae9370ee21f31f9shepshapard val embeddedFields = 1251a74519922de68e007027d56aae9370ee21f31f9shepshapard allFields[Embedded::class] 1261a74519922de68e007027d56aae9370ee21f31f9shepshapard ?.map { 1271a74519922de68e007027d56aae9370ee21f31f9shepshapard processEmbeddedField(declaredType, it) 1281a74519922de68e007027d56aae9370ee21f31f9shepshapard } 1291a74519922de68e007027d56aae9370ee21f31f9shepshapard ?.filterNotNull() 1301a74519922de68e007027d56aae9370ee21f31f9shepshapard ?: emptyList() 13113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 1321a74519922de68e007027d56aae9370ee21f31f9shepshapard val subFields = embeddedFields.flatMap { it.pojo.fields } 13396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val fields = myFields + subFields 134092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 135092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val myRelationsList = allFields[Relation::class] 136092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ?.map { 137092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar processRelationField(fields, declaredType, it) 138092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 1391a74519922de68e007027d56aae9370ee21f31f9shepshapard ?.filterNotNull() 1401a74519922de68e007027d56aae9370ee21f31f9shepshapard ?: emptyList() 141092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 1424d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val subRelations = embeddedFields.flatMap { it.pojo.relations } 143092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val relations = myRelationsList + subRelations 144092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 14596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar fields.groupBy { it.columnName } 14696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar .filter { it.value.size > 1 } 14796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar .forEach { 14896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar context.logger.e(element, ProcessorErrors.pojoDuplicateFieldNames( 14996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar it.key, it.value.map(Field::getPath) 15096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar )) 15196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar it.value.forEach { 15296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar context.logger.e(it.element, POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME) 15396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar } 15496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar } 1551a74519922de68e007027d56aae9370ee21f31f9shepshapard 15696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val methods = MoreElements.getLocalAndInheritedMethods(element, 15796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar context.processingEnv.elementUtils) 15813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar .filter { 15996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar !it.hasAnyOf(PRIVATE, ABSTRACT, STATIC) 16013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar && !it.hasAnnotation(Ignore::class) 16113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 16213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar .map { MoreElements.asExecutable(it) } 16313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 16413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar val getterCandidates = methods.filter { 16513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar it.parameters.size == 0 && it.returnType.kind != TypeKind.VOID 16613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 16713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 16813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar val setterCandidates = methods.filter { 16913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar it.parameters.size == 1 && it.returnType.kind == TypeKind.VOID 17013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 1711a74519922de68e007027d56aae9370ee21f31f9shepshapard 172f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar // don't try to find a constructor for binding to statement. 173f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val constructor = if (bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT) { 174f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar // we don't need to construct this POJO. 175f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 176f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 1774d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar chooseConstructor(myFields, embeddedFields) 178f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 17913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 18096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar assignGetters(myFields, getterCandidates) 181f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar assignSetters(myFields, setterCandidates, constructor) 182092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 1834d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar embeddedFields.forEach { 184092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignGetter(it.field, getterCandidates) 185f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar assignSetter(it.field, setterCandidates, constructor) 186092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 187092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 188092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar myRelationsList.forEach { 189092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignGetter(it.field, getterCandidates) 190f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar assignSetter(it.field, setterCandidates, constructor) 191092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 192092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 1931a74519922de68e007027d56aae9370ee21f31f9shepshapard return Pojo(element = element, 19496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar type = declaredType, 19596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar fields = fields, 1964d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar embeddedFields = embeddedFields, 197f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar relations = relations, 198f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar constructor = constructor) 19913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 20013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 2016f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas private fun chooseConstructor( 2026f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas myFields: List<Field>, embedded: List<EmbeddedField>): Constructor? { 203f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val constructors = ElementFilter.constructorsIn(element.enclosedElements) 204f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar .filterNot { it.hasAnnotation(Ignore::class) || it.hasAnyOf(PRIVATE) } 205f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val fieldMap = myFields.associateBy { it.name } 2064d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val embeddedMap = embedded.associateBy { it.field.name } 207f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val typeUtils = context.processingEnv.typeUtils 208f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val failedConstructors = mutableMapOf<ExecutableElement, List<Constructor.Param?>>() 209f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val goodConstructors = constructors.map { constructor -> 210f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val params = constructor.parameters.map param@ { param -> 211f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val paramName = param.simpleName.toString() 212f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val paramType = param.asType() 213f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 214f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val matches = fun(field: Field?): Boolean { 215f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return if (field == null) { 216f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar false 217f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else if (!field.nameWithVariations.contains(paramName)) { 218f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar false 219f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 2202fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar // see: b/69164099 2212fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar typeUtils.isAssignableWithoutVariance(paramType, field.type) 222f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 223f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 224f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 225f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val exactFieldMatch = fieldMap[paramName] 226f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 227f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (matches(exactFieldMatch)) { 228f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return@param Constructor.FieldParam(exactFieldMatch!!) 229f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 2304d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val exactEmbeddedMatch = embeddedMap[paramName] 2314d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar if (matches(exactEmbeddedMatch?.field)) { 2324d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar return@param Constructor.EmbeddedParam(exactEmbeddedMatch!!) 233f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 234f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 235f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val matchingFields = myFields.filter { 236f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar matches(it) 237f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 2384d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val embeddedMatches = embedded.filter { 239f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar matches(it.field) 240f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 2414d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar if (matchingFields.isEmpty() && embeddedMatches.isEmpty()) { 242f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 2434d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar } else if (matchingFields.size + embeddedMatches.size == 1) { 244f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (matchingFields.isNotEmpty()) { 245f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar Constructor.FieldParam(matchingFields.first()) 246f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 2474d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar Constructor.EmbeddedParam(embeddedMatches.first()) 248f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 249f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 250f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(param, ProcessorErrors.ambigiousConstructor( 251f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar pojo = element.qualifiedName.toString(), 252f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar paramName = param.simpleName.toString(), 253f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar matchingFields = matchingFields.map { it.getPath() } 2544d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar + embedded.map { it.field.getPath() } 255f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar )) 256f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 257f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 258f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 259f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (params.any { it == null }) { 260f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar failedConstructors.put(constructor, params) 261f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 262f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 263f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar @Suppress("UNCHECKED_CAST") 264f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar Constructor(constructor, params as List<Constructor.Param>) 265f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 266f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar }.filterNotNull() 267f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (goodConstructors.isEmpty()) { 268f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (failedConstructors.isNotEmpty()) { 269f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val failureMsg = failedConstructors.entries.joinToString("\n") { entry -> 270f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val paramsMatching = entry.key.parameters.withIndex().joinToString(", ") { 271f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar "${it.value.simpleName} : ${entry.value[it.index]?.log()}" 272f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 273f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar "${entry.key} : [$paramsMatching]" 274f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 275f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR + 276f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar "\nTried the following constructors but they failed to match:\n$failureMsg") 277f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 278f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR) 279f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return null 280b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar } else if (goodConstructors.size > 1) { 281b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar // if there is a no-arg constructor, pick it. Even though it is weird, easily happens 282b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar // with kotlin data classes. 283b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar val noArg = goodConstructors.firstOrNull { it.params.isEmpty() } 284b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar if (noArg != null) { 285b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar context.logger.w(Warning.DEFAULT_CONSTRUCTOR, element, 286b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG) 287b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar return noArg 288b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar } 289f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar goodConstructors.forEach { 290f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS) 291f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 292f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return null 293b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar } else { 294b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar return goodConstructors.first() 295f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 296f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 297f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 2986f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas private fun processEmbeddedField( 2996f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas declaredType: DeclaredType?, variableElement: VariableElement): EmbeddedField? { 3001a74519922de68e007027d56aae9370ee21f31f9shepshapard 3011a74519922de68e007027d56aae9370ee21f31f9shepshapard val asTypeElement = MoreTypes.asTypeElement(variableElement.asType()) 3021a74519922de68e007027d56aae9370ee21f31f9shepshapard 3031a74519922de68e007027d56aae9370ee21f31f9shepshapard if (detectReferenceRecursion(asTypeElement)) { 3041a74519922de68e007027d56aae9370ee21f31f9shepshapard return null 3051a74519922de68e007027d56aae9370ee21f31f9shepshapard } 3061a74519922de68e007027d56aae9370ee21f31f9shepshapard 3071a74519922de68e007027d56aae9370ee21f31f9shepshapard val fieldPrefix = variableElement 3081a74519922de68e007027d56aae9370ee21f31f9shepshapard .getAnnotationValue(Embedded::class.java, "prefix") 3091a74519922de68e007027d56aae9370ee21f31f9shepshapard ?.toString() 3101a74519922de68e007027d56aae9370ee21f31f9shepshapard ?: "" 31196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val inheritedPrefix = parent?.prefix ?: "" 3126f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas val embeddedField = Field( 3136f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas variableElement, 3146f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas variableElement.simpleName.toString(), 3156f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas type = context 3166f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas .processingEnv 3176f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas .typeUtils 3186f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas .asMemberOf(declaredType, variableElement), 3196f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas affinity = null, 3206f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas parent = parent) 3214d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val subParent = EmbeddedField( 3224d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar field = embeddedField, 32396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar prefix = inheritedPrefix + fieldPrefix, 32496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar parent = parent) 3251a74519922de68e007027d56aae9370ee21f31f9shepshapard subParent.pojo = PojoProcessor( 3261a74519922de68e007027d56aae9370ee21f31f9shepshapard baseContext = context.fork(variableElement), 3271a74519922de68e007027d56aae9370ee21f31f9shepshapard element = asTypeElement, 32896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar bindingScope = bindingScope, 3291a74519922de68e007027d56aae9370ee21f31f9shepshapard parent = subParent, 3301a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack = referenceStack).process() 33196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar return subParent 33296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar } 33396cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar 3346f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas private fun processRelationField( 3356f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas myFields: List<Field>, container: DeclaredType?, 3366f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas relationElement: VariableElement 3376f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas ): android.arch.persistence.room.vo.Relation? { 33887a16a53f9806fe8bcbe4e3bef751fc214a4235aAurimas Liutikas val asTypeElement = MoreTypes.asTypeElement( 33987a16a53f9806fe8bcbe4e3bef751fc214a4235aAurimas Liutikas MoreElements.asVariable(relationElement).asType()) 3401a74519922de68e007027d56aae9370ee21f31f9shepshapard 3411a74519922de68e007027d56aae9370ee21f31f9shepshapard if (detectReferenceRecursion(asTypeElement)) { 3421a74519922de68e007027d56aae9370ee21f31f9shepshapard return null 3431a74519922de68e007027d56aae9370ee21f31f9shepshapard } 3441a74519922de68e007027d56aae9370ee21f31f9shepshapard 345092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val annotation = MoreElements.getAnnotationMirror(relationElement, Relation::class.java) 346092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .orNull()!! 347f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar val parentColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "parentColumn") 348092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAsString("") ?: "" 349092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 350092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val parentField = myFields.firstOrNull { 351f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar it.columnName == parentColumnInput 352092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 353092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (parentField == null) { 354092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, 355092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.relationCannotFindParentEntityField( 356092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entityName = element.qualifiedName.toString(), 357f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar columnName = parentColumnInput, 358f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar availableColumns = myFields.map { it.columnName })) 359092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 360092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 361092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar // parse it as an entity. 362092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val asMember = MoreTypes 363092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .asMemberOf(context.processingEnv.typeUtils, container, relationElement) 364092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (asMember.kind == TypeKind.ERROR) { 365092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(ProcessorErrors.CANNOT_FIND_TYPE, element) 366092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 367092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 368092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val declared = MoreTypes.asDeclared(asMember) 369092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (!declared.isCollection()) { 370092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, ProcessorErrors.RELATION_NOT_COLLECTION) 371092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 372092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 373092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val typeArg = declared.typeArguments.first() 374092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (typeArg.kind == TypeKind.ERROR) { 375092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(MoreTypes.asTypeElement(typeArg), CANNOT_FIND_TYPE) 376092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 377092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 378092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val typeArgElement = MoreTypes.asTypeElement(typeArg) 379092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val entityClassInput = AnnotationMirrors 380092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAnnotationValue(annotation, "entity").toClassType() 3816f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas val pojo: Pojo 3826f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas val entity: Entity 383092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (entityClassInput == null 384092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar || MoreTypes.isTypeOf(Any::class.java, entityClassInput)) { 3851a74519922de68e007027d56aae9370ee21f31f9shepshapard entity = EntityProcessor(context, typeArgElement, referenceStack).process() 386092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar pojo = entity 387092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } else { 3881a74519922de68e007027d56aae9370ee21f31f9shepshapard entity = EntityProcessor(context, MoreTypes.asTypeElement(entityClassInput), 3896f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas referenceStack).process() 3901a74519922de68e007027d56aae9370ee21f31f9shepshapard pojo = PojoProcessor( 3911a74519922de68e007027d56aae9370ee21f31f9shepshapard baseContext = context, 392092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar element = typeArgElement, 393092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR, 3941a74519922de68e007027d56aae9370ee21f31f9shepshapard parent = parent, 3951a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack = referenceStack).process() 396092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 397092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar // now find the field in the entity. 398f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar val entityColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "entityColumn") 399092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAsString() ?: "" 400092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val entityField = entity.fields.firstOrNull { 401f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar it.columnName == entityColumnInput 402092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 403092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 404092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (entityField == null) { 405092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, 406092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.relationCannotFindEntityField( 407092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entityName = entity.typeName.toString(), 408f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar columnName = entityColumnInput, 409f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar availableColumns = entity.fields.map { it.columnName })) 410092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 411092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 412092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 413092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val field = Field( 414092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar element = relationElement, 415092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = relationElement.simpleName.toString(), 416092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = context.processingEnv.typeUtils.asMemberOf(container, relationElement), 417092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar affinity = null, 418092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar parent = parent) 419092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 420092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val projection = AnnotationMirrors.getAnnotationValue(annotation, "projection") 421092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAsStringList() 4226f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas if (projection.isNotEmpty()) { 423092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val missingColumns = projection.filterNot { columnName -> 424092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entity.fields.any { columnName == it.columnName } 425092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 426092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (missingColumns.isNotEmpty()) { 427092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, 428092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.relationBadProject(entity.typeName.toString(), 429092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar missingColumns, entity.fields.map { it.columnName })) 430092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 431092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 432092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 433092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar // if types don't match, row adapter prints a warning 43464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar return android.arch.persistence.room.vo.Relation( 435092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entity = entity, 436092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar pojo = pojo, 437092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field = field, 438092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar parentField = parentField, 439092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entityField = entityField, 440092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar projection = projection 441092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ) 442092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 443092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 4441a74519922de68e007027d56aae9370ee21f31f9shepshapard private fun detectReferenceRecursion(typeElement: TypeElement): Boolean { 4451a74519922de68e007027d56aae9370ee21f31f9shepshapard if (referenceStack.contains(typeElement.qualifiedName)) { 4461a74519922de68e007027d56aae9370ee21f31f9shepshapard context.logger.e( 4471a74519922de68e007027d56aae9370ee21f31f9shepshapard typeElement, 4481a74519922de68e007027d56aae9370ee21f31f9shepshapard ProcessorErrors 4491a74519922de68e007027d56aae9370ee21f31f9shepshapard .RECURSIVE_REFERENCE_DETECTED 4501a74519922de68e007027d56aae9370ee21f31f9shepshapard .format(computeReferenceRecursionString(typeElement))) 4511a74519922de68e007027d56aae9370ee21f31f9shepshapard return true 4521a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4531a74519922de68e007027d56aae9370ee21f31f9shepshapard return false 4541a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4551a74519922de68e007027d56aae9370ee21f31f9shepshapard 4561a74519922de68e007027d56aae9370ee21f31f9shepshapard private fun computeReferenceRecursionString(typeElement: TypeElement): String { 4571a74519922de68e007027d56aae9370ee21f31f9shepshapard val recursiveTailTypeName = typeElement.qualifiedName 4581a74519922de68e007027d56aae9370ee21f31f9shepshapard 4591a74519922de68e007027d56aae9370ee21f31f9shepshapard val referenceRecursionList = mutableListOf<Name>() 4601a74519922de68e007027d56aae9370ee21f31f9shepshapard with (referenceRecursionList) { 4611a74519922de68e007027d56aae9370ee21f31f9shepshapard add(recursiveTailTypeName) 4621a74519922de68e007027d56aae9370ee21f31f9shepshapard addAll(referenceStack.toList().takeLastWhile { it != recursiveTailTypeName }) 4631a74519922de68e007027d56aae9370ee21f31f9shepshapard add(recursiveTailTypeName) 4641a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4651a74519922de68e007027d56aae9370ee21f31f9shepshapard 4661a74519922de68e007027d56aae9370ee21f31f9shepshapard return referenceRecursionList.joinToString(" -> ") 4671a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4681a74519922de68e007027d56aae9370ee21f31f9shepshapard 46913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar private fun assignGetters(fields: List<Field>, getterCandidates: List<ExecutableElement>) { 47013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar fields.forEach { field -> 471092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignGetter(field, getterCandidates) 47213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 47313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 47413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 475092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar private fun assignGetter(field: Field, getterCandidates: List<ExecutableElement>) { 476092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val success = chooseAssignment(field = field, 477092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar candidates = getterCandidates, 478092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar nameVariations = field.getterNameWithVariations, 479092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar getType = { method -> 480092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar method.returnType 481092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 482092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromField = { 483092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.getter = FieldGetter( 484092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = field.name, 485092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = field.type, 486092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.FIELD) 487092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 488092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromMethod = { match -> 489092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.getter = FieldGetter( 490092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = match.simpleName.toString(), 491092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = match.returnType, 492092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.METHOD) 493092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 494092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar reportAmbiguity = { matching -> 495092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(field.element, 496092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.tooManyMatchingGetters(field, matching)) 497092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }) 498092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD) 499092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 500092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 501f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>, 5026f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas constructor: Constructor?) { 50313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar fields.forEach { field -> 504f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar assignSetter(field, setterCandidates, constructor) 5055bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5065bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5075bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar 508f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar private fun assignSetter(field: Field, setterCandidates: List<ExecutableElement>, 509f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar constructor: Constructor?) { 510f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (constructor != null && constructor.hasField(field)) { 511f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar field.setter = FieldSetter(field.name, field.type, CallType.CONSTRUCTOR) 512f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return 513f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 514092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val success = chooseAssignment(field = field, 515092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar candidates = setterCandidates, 516092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar nameVariations = field.setterNameWithVariations, 517092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar getType = { method -> 518092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar method.parameters.first().asType() 519092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 520092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromField = { 521092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.setter = FieldSetter( 522092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = field.name, 523092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = field.type, 524092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.FIELD) 525092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 526092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromMethod = { match -> 527092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val paramType = match.parameters.first().asType() 528092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.setter = FieldSetter( 529092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = match.simpleName.toString(), 530092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = paramType, 531092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.METHOD) 532092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 533092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar reportAmbiguity = { matching -> 534092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(field.element, 535092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.tooManyMatchingSetter(field, matching)) 536092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }) 537092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD) 538092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 539092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 5405bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar /** 5415bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * Finds a setter/getter from available list of methods. 5425bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * It returns true if assignment is successful, false otherwise. 5435bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * At worst case, it sets to the field as if it is accessible so that the rest of the 5445bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * compilation can continue. 5455bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar */ 5465bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar private fun chooseAssignment(field: Field, candidates: List<ExecutableElement>, 54796cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar nameVariations: List<String>, 54896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar getType: (ExecutableElement) -> TypeMirror, 5495bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField: () -> Unit, 5505bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromMethod: (ExecutableElement) -> Unit, 5515bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar reportAmbiguity: (List<String>) -> Unit): Boolean { 5525bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (field.element.hasAnyOf(PUBLIC)) { 5535bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField() 5545bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return true 5555bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5565bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar val types = context.processingEnv.typeUtils 5576d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar 5585bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar val matching = candidates 5595bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar .filter { 5602fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar // b/69164099 5612fb00f11f2e6d90edf678daaa921a3ef1b55a51bYigit Boyar types.isAssignableWithoutVariance(getType(it), field.element.asType()) 5626d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar && (field.nameWithVariations.contains(it.simpleName.toString()) 5636d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar || nameVariations.contains(it.simpleName.toString())) 56413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 5655bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar .groupBy { 5665bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (it.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED 5675bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5685bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (matching.isEmpty()) { 5695bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar // we always assign to avoid NPEs in the rest of the compilation. 5705bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField() 5715bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar // if field is not private, assume it works (if we are on the same package). 5725bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar // if not, compiler will tell, we didn't have any better alternative anyways. 5735bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return !field.element.hasAnyOf(PRIVATE) 5745bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5755bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity) ?: 5765bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity) 5775bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (match == null) { 5785bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField() 5795bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return false 5805bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } else { 5815bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromMethod(match) 5825bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return true 5835bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5845bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5855bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar 5866f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas private fun verifyAndChooseOneFrom( 5876f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas candidates: List<ExecutableElement>?, 5886f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas reportAmbiguity: (List<String>) -> Unit 5896f1f5567abe765d30fda9c8fedce5617ecdeda9cAurimas Liutikas ): ExecutableElement? { 5905bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (candidates == null) { 5915bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return null 5925bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5935bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (candidates.size > 1) { 5945bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar reportAmbiguity(candidates.map { it.simpleName.toString() }) 59513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 5965bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return candidates.first() 59713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 59813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar} 599