1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.room.processor 18 19 import androidx.room.ColumnInfo 20 import androidx.room.ext.getAsBoolean 21 import androidx.room.ext.getAsInt 22 import androidx.room.ext.getAsString 23 import androidx.room.parser.Collate 24 import androidx.room.parser.SQLTypeAffinity 25 import androidx.room.vo.EmbeddedField 26 import androidx.room.vo.Field 27 import com.google.auto.common.AnnotationMirrors 28 import com.google.auto.common.MoreElements 29 import com.squareup.javapoet.TypeName 30 import javax.lang.model.element.Element 31 import javax.lang.model.type.DeclaredType 32 33 class FieldProcessor(baseContext: Context, val containing: DeclaredType, val element: Element, 34 val bindingScope: BindingScope, 35 // pass only if this is processed as a child of Embedded field 36 val fieldParent: EmbeddedField?) { 37 val context = baseContext.fork(element) processnull38 fun process(): Field { 39 val member = context.processingEnv.typeUtils.asMemberOf(containing, element) 40 val type = TypeName.get(member) 41 val columnInfoAnnotation = MoreElements.getAnnotationMirror(element, 42 ColumnInfo::class.java) 43 val name = element.simpleName.toString() 44 val columnName: String 45 val affinity: SQLTypeAffinity? 46 val collate: Collate? 47 val fieldPrefix = fieldParent?.prefix ?: "" 48 val indexed: Boolean 49 if (columnInfoAnnotation.isPresent) { 50 val nameInAnnotation = AnnotationMirrors 51 .getAnnotationValue(columnInfoAnnotation.get(), "name") 52 .getAsString(ColumnInfo.INHERIT_FIELD_NAME) 53 columnName = fieldPrefix + if (nameInAnnotation == ColumnInfo.INHERIT_FIELD_NAME) { 54 name 55 } else { 56 nameInAnnotation 57 } 58 59 affinity = try { 60 val userDefinedAffinity = AnnotationMirrors 61 .getAnnotationValue(columnInfoAnnotation.get(), "typeAffinity") 62 .getAsInt(ColumnInfo.UNDEFINED)!! 63 SQLTypeAffinity.fromAnnotationValue(userDefinedAffinity) 64 } catch (ex: NumberFormatException) { 65 null 66 } 67 68 collate = Collate.fromAnnotationValue(AnnotationMirrors.getAnnotationValue( 69 columnInfoAnnotation.get(), "collate").getAsInt(ColumnInfo.UNSPECIFIED)!!) 70 71 indexed = AnnotationMirrors 72 .getAnnotationValue(columnInfoAnnotation.get(), "index") 73 .getAsBoolean(false) 74 } else { 75 columnName = fieldPrefix + name 76 affinity = null 77 collate = null 78 indexed = false 79 } 80 context.checker.notBlank(columnName, element, 81 ProcessorErrors.COLUMN_NAME_CANNOT_BE_EMPTY) 82 context.checker.notUnbound(type, element, 83 ProcessorErrors.CANNOT_USE_UNBOUND_GENERICS_IN_ENTITY_FIELDS) 84 85 val field = Field(name = name, 86 type = member, 87 element = element, 88 columnName = columnName, 89 affinity = affinity, 90 collate = collate, 91 parent = fieldParent, 92 indexed = indexed) 93 94 when (bindingScope) { 95 BindingScope.TWO_WAY -> { 96 val adapter = context.typeAdapterStore.findColumnTypeAdapter(field.type, 97 field.affinity) 98 field.statementBinder = adapter 99 field.cursorValueReader = adapter 100 field.affinity = adapter?.typeAffinity ?: field.affinity 101 context.checker.check(adapter != null, field.element, 102 ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER) 103 } 104 BindingScope.BIND_TO_STMT -> { 105 field.statementBinder = context.typeAdapterStore 106 .findStatementValueBinder(field.type, field.affinity) 107 context.checker.check(field.statementBinder != null, field.element, 108 ProcessorErrors.CANNOT_FIND_STMT_BINDER) 109 } 110 BindingScope.READ_FROM_CURSOR -> { 111 field.cursorValueReader = context.typeAdapterStore 112 .findCursorValueReader(field.type, field.affinity) 113 context.checker.check(field.cursorValueReader != null, field.element, 114 ProcessorErrors.CANNOT_FIND_CURSOR_READER) 115 } 116 } 117 return field 118 } 119 120 /** 121 * Defines what we need to assign 122 */ 123 enum class BindingScope { 124 TWO_WAY, // both bind and read. 125 BIND_TO_STMT, // just value to statement 126 READ_FROM_CURSOR // just cursor to value 127 } 128 } 129