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