EntityProcessor.kt revision 8bad027c789d3fb3da8e68fa0154f2a24ccc2865
11600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar/*
21600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * Copyright (C) 2016 The Android Open Source Project
31600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar *
41600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
51600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * you may not use this file except in compliance with the License.
61600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * You may obtain a copy of the License at
71600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar *
81600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
91600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar *
101600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * Unless required by applicable law or agreed to in writing, software
111600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
121600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * See the License for the specific language governing permissions and
141600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar * limitations under the License.
151600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar */
161600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
171600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarpackage com.android.support.room.processor
181600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
191600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.android.support.room.Ignore
201600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.android.support.room.errors.ElementBoundException
211600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.android.support.room.ext.hasAnnotation
221600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.android.support.room.ext.hasAnyOf
23e6325fbeaa2e6759496ea2ca9a4d3d958df690d7Yigit Boyarimport com.android.support.room.preconditions.Checks
241600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.android.support.room.vo.*
251600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.google.auto.common.MoreElements
261600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.google.auto.common.MoreTypes
271600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport com.squareup.javapoet.TypeName
281600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.annotation.processing.ProcessingEnvironment
291600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.annotation.processing.RoundEnvironment
301600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.lang.model.element.ElementKind
311600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.lang.model.element.ExecutableElement
321600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.lang.model.element.Modifier
331600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.lang.model.element.Modifier.*
341600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.lang.model.element.TypeElement
351600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyarimport javax.lang.model.type.TypeKind
361600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
378bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyarclass EntityProcessor(val roundEnv: RoundEnvironment,
388bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar                      val processingEnvironment: ProcessingEnvironment) {
398bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar    val fieldParser = FieldProcessor(roundEnv, processingEnvironment)
401600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
411600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    fun parse(element: TypeElement): Entity {
428bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar        Checks.hasAnnotation(element, com.android.support.room.Entity::class,
438bad027c789d3fb3da8e68fa0154f2a24ccc2865Yigit Boyar                ProcessorErrors.ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY)
441600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val declaredType = MoreTypes.asDeclared(element.asType())
451600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val allMembers = processingEnvironment.elementUtils.getAllMembers(element)
461600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val fields = allMembers
471600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                .filter {
481600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                    it.kind == ElementKind.FIELD
491600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            && !it.hasAnnotation(Ignore::class)
501600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            && !it.hasAnyOf(Modifier.STATIC)
511600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                }
521600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                .map { fieldParser.parse(declaredType, it) }
531600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
541600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val methods = allMembers
551600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                .filter {
561600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                    it.kind == ElementKind.METHOD
571600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            && !it.hasAnyOf(PRIVATE, ABSTRACT, STATIC)
581600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            && !it.hasAnnotation(Ignore::class)
591600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                }
601600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                .map { MoreElements.asExecutable(it) }
611600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
621600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val getterCandidates = methods.filter {
631600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            it.parameters.size == 0 && it.returnType.kind != TypeKind.VOID
641600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        }
651600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
661600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val setterCandidates = methods.filter {
671600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            it.parameters.size == 1 && it.returnType.kind == TypeKind.VOID
681600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        }
691600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
701600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        assignGetters(fields, getterCandidates)
711600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        assignSetters(fields, setterCandidates)
72e6325fbeaa2e6759496ea2ca9a4d3d958df690d7Yigit Boyar        val entity = Entity(TypeName.get(declaredType), fields)
73e6325fbeaa2e6759496ea2ca9a4d3d958df690d7Yigit Boyar        Checks.check(entity.primaryKeys.isNotEmpty(), element, ProcessorErrors.MISSING_PRIMARY_KEY)
74e6325fbeaa2e6759496ea2ca9a4d3d958df690d7Yigit Boyar        return entity
751600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    }
761600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
771600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    private fun assignGetters(fields: List<Field>, getterCandidates: List<ExecutableElement>) {
781600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val types = processingEnvironment.typeUtils
791600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
801600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        fields.forEach { field ->
811600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            if (!field.element.hasAnyOf(PRIVATE)) {
821600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                field.getter = FieldGetter(field.name, CallType.FIELD)
831600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            } else {
841600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                val matching = getterCandidates
851600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                        .filter {
861600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            types.isSameType(field.element.asType(), it.returnType)
871600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    && field.nameWithVariations.contains(it.simpleName.toString())
881600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    || field.getterNameWithVariations
891600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    .contains(it.simpleName.toString())
901600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                        }
911600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                if (matching.isEmpty()) {
921600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                    throw ElementBoundException(field.element,
931600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            ProcessorErrors.CANNOT_FIND_GETTER_FOR_FIELD)
941600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                }
951600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                if (matching.size > 1) {
961600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                    throw ElementBoundException(field.element,
971600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            ProcessorErrors.tooManyMatchingGetters(field,
981600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    matching.map { it.simpleName.toString() }))
991600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                }
1001600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                val match = matching.first()
1011600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                field.getter = FieldGetter(match.simpleName.toString(), CallType.METHOD)
1021600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            }
1031600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        }
1041600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    }
1051600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
1061600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    private fun assignSetters(fields: List<Field>, setterCandidates: List<ExecutableElement>) {
1071600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        val types = processingEnvironment.typeUtils
1081600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar
1091600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        fields.forEach { field ->
1101600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            if (!field.element.hasAnyOf(PRIVATE)) {
1111600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                field.setter = FieldSetter(field.name, CallType.FIELD)
1121600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            } else {
1131600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                val matching = setterCandidates
1141600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                        .filter {
1151600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            types.isSameType(field.element.asType(), it.parameters.first().asType())
1161600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    && field.nameWithVariations.contains(it.simpleName.toString())
1171600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    || field.setterNameWithVariations
1181600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    .contains(it.simpleName.toString())
1191600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                        }
1201600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                if (matching.isEmpty()) {
1211600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                    throw ElementBoundException(field.element,
1221600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            ProcessorErrors.CANNOT_FIND_SETTER_FOR_FIELD)
1231600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                }
1241600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                if (matching.size > 1) {
1251600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                    throw ElementBoundException(field.element,
1261600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                            ProcessorErrors.tooManyMatchingSetter(field,
1271600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                                    matching.map { it.simpleName.toString() }))
1281600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                }
1291600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                val match = matching.first()
1301600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar                field.setter = FieldSetter(match.simpleName.toString(), CallType.METHOD)
1311600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar            }
1321600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar        }
1331600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar    }
1341600cc11df868b62b6ae3995d94a3ec0b86559adYigit Boyar}
135