PojoProcessor.kt revision b9ea73472fb85e1a7074734824ad11c3f64cad83
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 2964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.isCollection 3064db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.ext.toClassType 3164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD 3264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD 3364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.CANNOT_FIND_TYPE 3464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.ProcessorErrors.POJO_FIELD_HAS_DUPLICATE_COLUMN_NAME 3564db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.processor.cache.Cache 3664db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.CallType 3764db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Constructor 384d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyarimport android.arch.persistence.room.vo.EmbeddedField 3964db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Entity 40b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.vo.Field 41b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.vo.FieldGetter 4264db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.FieldSetter 4364db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyarimport android.arch.persistence.room.vo.Pojo 44b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyarimport android.arch.persistence.room.vo.Warning 45092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport com.google.auto.common.AnnotationMirrors 4613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreElements 4713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport com.google.auto.common.MoreTypes 4813a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.ExecutableElement 4913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.ABSTRACT 5013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.PRIVATE 515bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PROTECTED 525bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.element.Modifier.PUBLIC 5313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.Modifier.STATIC 54a3a639f77c2d82b09b5cbcd4125b1d3b2a8ed252Yigit Boyarimport javax.lang.model.element.Modifier.TRANSIENT 551a74519922de68e007027d56aae9370ee21f31f9shepshapardimport javax.lang.model.element.Name 5613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.element.TypeElement 57092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyarimport javax.lang.model.element.VariableElement 5896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyarimport javax.lang.model.type.DeclaredType 5913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyarimport javax.lang.model.type.TypeKind 605bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyarimport javax.lang.model.type.TypeMirror 61f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyarimport javax.lang.model.util.ElementFilter 6213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 6313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar/** 6413a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar * Processes any class as if it is a Pojo. 6513a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar */ 661a74519922de68e007027d56aae9370ee21f31f9shepshapardclass PojoProcessor(baseContext: Context, 671a74519922de68e007027d56aae9370ee21f31f9shepshapard val element: TypeElement, 6896cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val bindingScope: FieldProcessor.BindingScope, 691a74519922de68e007027d56aae9370ee21f31f9shepshapard val parent: EmbeddedField?, 701a74519922de68e007027d56aae9370ee21f31f9shepshapard val referenceStack: LinkedHashSet<Name> = LinkedHashSet<Name>()) { 71aa82fce1d73394bdc7f4c2510cf94a3572032b24Yigit Boyar val context = baseContext.fork(element) 72092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar companion object { 734d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val PROCESSED_ANNOTATIONS = listOf(ColumnInfo::class, Embedded::class, 74092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar Relation::class) 75092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 765124503104860e68981cc3e3092b95932586f66fYigit Boyar fun process() : Pojo { 775124503104860e68981cc3e3092b95932586f66fYigit Boyar return context.cache.pojos.get(Cache.PojoKey(element, bindingScope, parent), { 781a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack.add(element.qualifiedName) 791a74519922de68e007027d56aae9370ee21f31f9shepshapard try { 801a74519922de68e007027d56aae9370ee21f31f9shepshapard doProcess() 811a74519922de68e007027d56aae9370ee21f31f9shepshapard } 821a74519922de68e007027d56aae9370ee21f31f9shepshapard 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 2014d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar private fun chooseConstructor(myFields: List<Field>, embedded: List<EmbeddedField>) 202f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar : 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 { 220f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar typeUtils.isAssignable(paramType, field.type) 221f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 222f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 223f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 224f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val exactFieldMatch = fieldMap[paramName] 225f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 226f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (matches(exactFieldMatch)) { 227f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return@param Constructor.FieldParam(exactFieldMatch!!) 228f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 2294d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val exactEmbeddedMatch = embeddedMap[paramName] 2304d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar if (matches(exactEmbeddedMatch?.field)) { 2314d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar return@param Constructor.EmbeddedParam(exactEmbeddedMatch!!) 232f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 233f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 234f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val matchingFields = myFields.filter { 235f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar matches(it) 236f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 2374d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val embeddedMatches = embedded.filter { 238f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar matches(it.field) 239f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 2404d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar if (matchingFields.isEmpty() && embeddedMatches.isEmpty()) { 241f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 2424d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar } else if (matchingFields.size + embeddedMatches.size == 1) { 243f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (matchingFields.isNotEmpty()) { 244f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar Constructor.FieldParam(matchingFields.first()) 245f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 2464d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar Constructor.EmbeddedParam(embeddedMatches.first()) 247f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 248f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 249f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(param, ProcessorErrors.ambigiousConstructor( 250f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar pojo = element.qualifiedName.toString(), 251f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar paramName = param.simpleName.toString(), 252f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar matchingFields = matchingFields.map { it.getPath() } 2534d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar + embedded.map { it.field.getPath() } 254f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar )) 255f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 256f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 257f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 258f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (params.any { it == null }) { 259f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar failedConstructors.put(constructor, params) 260f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar null 261f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } else { 262f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar @Suppress("UNCHECKED_CAST") 263f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar Constructor(constructor, params as List<Constructor.Param>) 264f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 265f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar }.filterNotNull() 266f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (goodConstructors.isEmpty()) { 267f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (failedConstructors.isNotEmpty()) { 268f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val failureMsg = failedConstructors.entries.joinToString("\n") { entry -> 269f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar val paramsMatching = entry.key.parameters.withIndex().joinToString(", ") { 270f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar "${it.value.simpleName} : ${entry.value[it.index]?.log()}" 271f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 272f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar "${entry.key} : [$paramsMatching]" 273f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 274f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR + 275f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar "\nTried the following constructors but they failed to match:\n$failureMsg") 276f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 277f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(element, ProcessorErrors.MISSING_POJO_CONSTRUCTOR) 278f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return null 279b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar } else if (goodConstructors.size > 1) { 280b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar // if there is a no-arg constructor, pick it. Even though it is weird, easily happens 281b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar // with kotlin data classes. 282b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar val noArg = goodConstructors.firstOrNull { it.params.isEmpty() } 283b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar if (noArg != null) { 284b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar context.logger.w(Warning.DEFAULT_CONSTRUCTOR, element, 285b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS_CHOOSING_NO_ARG) 286b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar return noArg 287b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar } 288f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar goodConstructors.forEach { 289f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar context.logger.e(it.element, ProcessorErrors.TOO_MANY_POJO_CONSTRUCTORS) 290f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 291f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return null 292b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar } else { 293b9ea73472fb85e1a7074734824ad11c3f64cad83Yigit Boyar return goodConstructors.first() 294f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 295f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 296f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar 2971a74519922de68e007027d56aae9370ee21f31f9shepshapard private fun processEmbeddedField(declaredType: DeclaredType?, variableElement: VariableElement) 2981a74519922de68e007027d56aae9370ee21f31f9shepshapard : EmbeddedField? { 2991a74519922de68e007027d56aae9370ee21f31f9shepshapard 3001a74519922de68e007027d56aae9370ee21f31f9shepshapard val asTypeElement = MoreTypes.asTypeElement(variableElement.asType()) 3011a74519922de68e007027d56aae9370ee21f31f9shepshapard 3021a74519922de68e007027d56aae9370ee21f31f9shepshapard if (detectReferenceRecursion(asTypeElement)) { 3031a74519922de68e007027d56aae9370ee21f31f9shepshapard return null 3041a74519922de68e007027d56aae9370ee21f31f9shepshapard } 3051a74519922de68e007027d56aae9370ee21f31f9shepshapard 3061a74519922de68e007027d56aae9370ee21f31f9shepshapard val fieldPrefix = variableElement 3071a74519922de68e007027d56aae9370ee21f31f9shepshapard .getAnnotationValue(Embedded::class.java, "prefix") 3081a74519922de68e007027d56aae9370ee21f31f9shepshapard ?.toString() 3091a74519922de68e007027d56aae9370ee21f31f9shepshapard ?: "" 31096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar val inheritedPrefix = parent?.prefix ?: "" 3111a74519922de68e007027d56aae9370ee21f31f9shepshapard val embeddedField = Field(variableElement, 3121a74519922de68e007027d56aae9370ee21f31f9shepshapard variableElement.simpleName.toString(), 3131a74519922de68e007027d56aae9370ee21f31f9shepshapard type = context 3141a74519922de68e007027d56aae9370ee21f31f9shepshapard .processingEnv 3151a74519922de68e007027d56aae9370ee21f31f9shepshapard .typeUtils 3161a74519922de68e007027d56aae9370ee21f31f9shepshapard .asMemberOf(declaredType, variableElement), 3171a74519922de68e007027d56aae9370ee21f31f9shepshapard affinity = null, 3181a74519922de68e007027d56aae9370ee21f31f9shepshapard parent = parent) 3194d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar val subParent = EmbeddedField( 3204d4bae3f216e55f824d7d7fbfe2f8861906ee3e2Yigit Boyar field = embeddedField, 32196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar prefix = inheritedPrefix + fieldPrefix, 32296cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar parent = parent) 3231a74519922de68e007027d56aae9370ee21f31f9shepshapard subParent.pojo = PojoProcessor( 3241a74519922de68e007027d56aae9370ee21f31f9shepshapard baseContext = context.fork(variableElement), 3251a74519922de68e007027d56aae9370ee21f31f9shepshapard element = asTypeElement, 32696cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar bindingScope = bindingScope, 3271a74519922de68e007027d56aae9370ee21f31f9shepshapard parent = subParent, 3281a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack = referenceStack).process() 32996cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar return subParent 33096cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar } 33196cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar 332092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar private fun processRelationField(myFields : List<Field>, container: DeclaredType?, 333092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar relationElement: VariableElement) 33464db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar : android.arch.persistence.room.vo.Relation? { 3351a74519922de68e007027d56aae9370ee21f31f9shepshapard 3361a74519922de68e007027d56aae9370ee21f31f9shepshapard val asTypeElement = MoreTypes.asTypeElement(MoreElements.asVariable(relationElement).asType()) 3371a74519922de68e007027d56aae9370ee21f31f9shepshapard 3381a74519922de68e007027d56aae9370ee21f31f9shepshapard if (detectReferenceRecursion(asTypeElement)) { 3391a74519922de68e007027d56aae9370ee21f31f9shepshapard return null 3401a74519922de68e007027d56aae9370ee21f31f9shepshapard } 3411a74519922de68e007027d56aae9370ee21f31f9shepshapard 342092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val annotation = MoreElements.getAnnotationMirror(relationElement, Relation::class.java) 343092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .orNull()!! 344f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar val parentColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "parentColumn") 345092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAsString("") ?: "" 346092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 347092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val parentField = myFields.firstOrNull { 348f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar it.columnName == parentColumnInput 349092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 350092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (parentField == null) { 351092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, 352092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.relationCannotFindParentEntityField( 353092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entityName = element.qualifiedName.toString(), 354f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar columnName = parentColumnInput, 355f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar availableColumns = myFields.map { it.columnName })) 356092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 357092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 358092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar // parse it as an entity. 359092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val asMember = MoreTypes 360092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .asMemberOf(context.processingEnv.typeUtils, container, relationElement) 361092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (asMember.kind == TypeKind.ERROR) { 362092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(ProcessorErrors.CANNOT_FIND_TYPE, element) 363092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 364092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 365092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val declared = MoreTypes.asDeclared(asMember) 366092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (!declared.isCollection()) { 367092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, ProcessorErrors.RELATION_NOT_COLLECTION) 368092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 369092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 370092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val typeArg = declared.typeArguments.first() 371092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (typeArg.kind == TypeKind.ERROR) { 372092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(MoreTypes.asTypeElement(typeArg), CANNOT_FIND_TYPE) 373092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 374092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 375092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val typeArgElement = MoreTypes.asTypeElement(typeArg) 376092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val entityClassInput = AnnotationMirrors 377092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAnnotationValue(annotation, "entity").toClassType() 378092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val pojo : Pojo 379092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val entity : Entity 380092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (entityClassInput == null 381092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar || MoreTypes.isTypeOf(Any::class.java, entityClassInput)) { 3821a74519922de68e007027d56aae9370ee21f31f9shepshapard entity = EntityProcessor(context, typeArgElement, referenceStack).process() 383092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar pojo = entity 384092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } else { 3851a74519922de68e007027d56aae9370ee21f31f9shepshapard entity = EntityProcessor(context, MoreTypes.asTypeElement(entityClassInput), 3861a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack).process() 3871a74519922de68e007027d56aae9370ee21f31f9shepshapard pojo = PojoProcessor( 3881a74519922de68e007027d56aae9370ee21f31f9shepshapard baseContext = context, 389092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar element = typeArgElement, 390092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR, 3911a74519922de68e007027d56aae9370ee21f31f9shepshapard parent = parent, 3921a74519922de68e007027d56aae9370ee21f31f9shepshapard referenceStack = referenceStack).process() 393092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 394092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar // now find the field in the entity. 395f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar val entityColumnInput = AnnotationMirrors.getAnnotationValue(annotation, "entityColumn") 396092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAsString() ?: "" 397092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val entityField = entity.fields.firstOrNull { 398f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar it.columnName == entityColumnInput 399092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 400092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 401092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (entityField == null) { 402092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, 403092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.relationCannotFindEntityField( 404092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entityName = entity.typeName.toString(), 405f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar columnName = entityColumnInput, 406f385ca501bbfd3ccaf6b412f8f09c64d9ee742f2Yigit Boyar availableColumns = entity.fields.map { it.columnName })) 407092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar return null 408092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 409092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 410092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val field = Field( 411092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar element = relationElement, 412092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = relationElement.simpleName.toString(), 413092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = context.processingEnv.typeUtils.asMemberOf(container, relationElement), 414092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar affinity = null, 415092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar parent = parent) 416092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 417092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val projection = AnnotationMirrors.getAnnotationValue(annotation, "projection") 418092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar .getAsStringList() 419092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if(projection.isNotEmpty()) { 420092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val missingColumns = projection.filterNot { columnName -> 421092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entity.fields.any { columnName == it.columnName } 422092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 423092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar if (missingColumns.isNotEmpty()) { 424092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(relationElement, 425092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.relationBadProject(entity.typeName.toString(), 426092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar missingColumns, entity.fields.map { it.columnName })) 427092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 428092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 429092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 430092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar // if types don't match, row adapter prints a warning 43164db0cc15b78b62a1d44a70fc8b4552e660d952cYigit Boyar return android.arch.persistence.room.vo.Relation( 432092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entity = entity, 433092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar pojo = pojo, 434092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field = field, 435092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar parentField = parentField, 436092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar entityField = entityField, 437092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar projection = projection 438092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ) 439092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 440092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 4411a74519922de68e007027d56aae9370ee21f31f9shepshapard private fun detectReferenceRecursion(typeElement: TypeElement): Boolean { 4421a74519922de68e007027d56aae9370ee21f31f9shepshapard if (referenceStack.contains(typeElement.qualifiedName)) { 4431a74519922de68e007027d56aae9370ee21f31f9shepshapard context.logger.e( 4441a74519922de68e007027d56aae9370ee21f31f9shepshapard typeElement, 4451a74519922de68e007027d56aae9370ee21f31f9shepshapard ProcessorErrors 4461a74519922de68e007027d56aae9370ee21f31f9shepshapard .RECURSIVE_REFERENCE_DETECTED 4471a74519922de68e007027d56aae9370ee21f31f9shepshapard .format(computeReferenceRecursionString(typeElement))) 4481a74519922de68e007027d56aae9370ee21f31f9shepshapard return true 4491a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4501a74519922de68e007027d56aae9370ee21f31f9shepshapard return false 4511a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4521a74519922de68e007027d56aae9370ee21f31f9shepshapard 4531a74519922de68e007027d56aae9370ee21f31f9shepshapard private fun computeReferenceRecursionString(typeElement: TypeElement): String { 4541a74519922de68e007027d56aae9370ee21f31f9shepshapard val recursiveTailTypeName = typeElement.qualifiedName 4551a74519922de68e007027d56aae9370ee21f31f9shepshapard 4561a74519922de68e007027d56aae9370ee21f31f9shepshapard val referenceRecursionList = mutableListOf<Name>() 4571a74519922de68e007027d56aae9370ee21f31f9shepshapard with (referenceRecursionList) { 4581a74519922de68e007027d56aae9370ee21f31f9shepshapard add(recursiveTailTypeName) 4591a74519922de68e007027d56aae9370ee21f31f9shepshapard addAll(referenceStack.toList().takeLastWhile { it != recursiveTailTypeName }) 4601a74519922de68e007027d56aae9370ee21f31f9shepshapard add(recursiveTailTypeName) 4611a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4621a74519922de68e007027d56aae9370ee21f31f9shepshapard 4631a74519922de68e007027d56aae9370ee21f31f9shepshapard return referenceRecursionList.joinToString(" -> ") 4641a74519922de68e007027d56aae9370ee21f31f9shepshapard } 4651a74519922de68e007027d56aae9370ee21f31f9shepshapard 46613a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar private fun assignGetters(fields: List<Field>, getterCandidates: List<ExecutableElement>) { 46713a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar fields.forEach { field -> 468092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignGetter(field, getterCandidates) 46913a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 47013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 47113a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar 472092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar private fun assignGetter(field: Field, getterCandidates: List<ExecutableElement>) { 473092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val success = chooseAssignment(field = field, 474092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar candidates = getterCandidates, 475092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar nameVariations = field.getterNameWithVariations, 476092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar getType = { method -> 477092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar method.returnType 478092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 479092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromField = { 480092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.getter = FieldGetter( 481092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = field.name, 482092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = field.type, 483092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.FIELD) 484092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 485092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromMethod = { match -> 486092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.getter = FieldGetter( 487092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = match.simpleName.toString(), 488092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = match.returnType, 489092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.METHOD) 490092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 491092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar reportAmbiguity = { matching -> 492092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(field.element, 493092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.tooManyMatchingGetters(field, matching)) 494092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }) 495092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD) 496092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 497092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 498f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>, 499f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar constructor : Constructor?) { 50013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar fields.forEach { field -> 501f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar assignSetter(field, setterCandidates, constructor) 5025bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5035bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5045bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar 505f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar private fun assignSetter(field: Field, setterCandidates: List<ExecutableElement>, 506f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar constructor: Constructor?) { 507f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar if (constructor != null && constructor.hasField(field)) { 508f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar field.setter = FieldSetter(field.name, field.type, CallType.CONSTRUCTOR) 509f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar return 510f8c3624579d5761a2d34a7199932492d267f5f85Yigit Boyar } 511092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val success = chooseAssignment(field = field, 512092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar candidates = setterCandidates, 513092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar nameVariations = field.setterNameWithVariations, 514092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar getType = { method -> 515092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar method.parameters.first().asType() 516092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 517092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromField = { 518092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.setter = FieldSetter( 519092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = field.name, 520092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = field.type, 521092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.FIELD) 522092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 523092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar assignFromMethod = { match -> 524092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar val paramType = match.parameters.first().asType() 525092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar field.setter = FieldSetter( 526092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar name = match.simpleName.toString(), 527092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar type = paramType, 528092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar callType = CallType.METHOD) 529092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }, 530092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar reportAmbiguity = { matching -> 531092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.logger.e(field.element, 532092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar ProcessorErrors.tooManyMatchingSetter(field, matching)) 533092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar }) 534092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD) 535092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar } 536092164e5501d0a254001225acd9dca42e5fa57e9Yigit Boyar 5375bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar /** 5385bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * Finds a setter/getter from available list of methods. 5395bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * It returns true if assignment is successful, false otherwise. 5405bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * At worst case, it sets to the field as if it is accessible so that the rest of the 5415bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar * compilation can continue. 5425bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar */ 5435bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar private fun chooseAssignment(field: Field, candidates: List<ExecutableElement>, 54496cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar nameVariations: List<String>, 54596cc740203eaa752fc85ca7ca722a8de550ae88cYigit Boyar getType: (ExecutableElement) -> TypeMirror, 5465bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField: () -> Unit, 5475bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromMethod: (ExecutableElement) -> Unit, 5485bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar reportAmbiguity: (List<String>) -> Unit): Boolean { 5495bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (field.element.hasAnyOf(PUBLIC)) { 5505bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField() 5515bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return true 5525bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5535bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar val types = context.processingEnv.typeUtils 5546d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar 5555bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar val matching = candidates 5565bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar .filter { 5576d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar types.isAssignable(getType(it), field.element.asType()) 5586d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar && (field.nameWithVariations.contains(it.simpleName.toString()) 5596d6fe7fde68c1285107cedd5fc18d4c02232a4a6Yigit Boyar || nameVariations.contains(it.simpleName.toString())) 56013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 5615bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar .groupBy { 5625bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (it.hasAnyOf(PUBLIC)) PUBLIC else PROTECTED 5635bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5645bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (matching.isEmpty()) { 5655bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar // we always assign to avoid NPEs in the rest of the compilation. 5665bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField() 5675bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar // if field is not private, assume it works (if we are on the same package). 5685bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar // if not, compiler will tell, we didn't have any better alternative anyways. 5695bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return !field.element.hasAnyOf(PRIVATE) 5705bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5715bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar val match = verifyAndChooseOneFrom(matching[PUBLIC], reportAmbiguity) ?: 5725bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar verifyAndChooseOneFrom(matching[PROTECTED], reportAmbiguity) 5735bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (match == null) { 5745bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromField() 5755bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return false 5765bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } else { 5775bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar assignFromMethod(match) 5785bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return true 5795bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5805bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5815bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar 5825bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar private fun verifyAndChooseOneFrom(candidates: List<ExecutableElement>?, 5835bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar reportAmbiguity: (List<String>) -> Unit) 5845bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar : ExecutableElement? { 5855bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (candidates == null) { 5865bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return null 5875bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar } 5885bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar if (candidates.size > 1) { 5895bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar reportAmbiguity(candidates.map { it.simpleName.toString() }) 59013a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 5915bd1d1b032b37561f015985ca8854b89214bbcb3Yigit Boyar return candidates.first() 59213a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar } 59313a2048db98b1cc2dbd1692b73b794527975a446Yigit Boyar} 594