blob: e17cad7116165e657917b21bb9ba54a99caaada9 [file] [log] [blame]
Alan Viverette6c563342018-03-08 18:02:39 -05001/*
2 * Copyright (C) 2017 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
17package androidx.room.solver.types
18
mzgreen7bd7c652020-09-19 06:02:23 +000019import androidx.room.ProvidedTypeConverter
Alan Viverette6c563342018-03-08 18:02:39 -050020import androidx.room.ext.L
21import androidx.room.ext.N
22import androidx.room.ext.T
Daniel Santiago Rivera38bb0772021-06-24 15:04:32 -070023import androidx.room.ext.decapitalize
Alan Viverette6c563342018-03-08 18:02:39 -050024import androidx.room.solver.CodeGenScope
25import androidx.room.vo.CustomTypeConverter
mzgreen7bd7c652020-09-19 06:02:23 +000026import androidx.room.writer.DaoWriter
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040027import androidx.room.writer.TypeWriter
Alan Viverette6c563342018-03-08 18:02:39 -050028import com.squareup.javapoet.ClassName
mzgreen7bd7c652020-09-19 06:02:23 +000029import com.squareup.javapoet.CodeBlock
Alan Viverette6c563342018-03-08 18:02:39 -050030import com.squareup.javapoet.FieldSpec
mzgreen7bd7c652020-09-19 06:02:23 +000031import com.squareup.javapoet.MethodSpec
Simon Schiller5746e332020-08-24 04:31:51 -070032import java.util.Locale
Alan Viverette6c563342018-03-08 18:02:39 -050033import javax.lang.model.element.Modifier
34
35/**
36 * Wraps a type converter specified by the developer and forwards calls to it.
37 */
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040038class CustomTypeConverterWrapper(
39 val custom: CustomTypeConverter
40) : SingleStatementTypeConverter(custom.from, custom.to) {
Yigit Boyar3b17b092021-08-27 18:38:33 -070041 override fun buildStatement(inputVarName: String, scope: CodeGenScope): CodeBlock {
42 return if (custom.isEnclosingClassKotlinObject) {
43 CodeBlock.of(
44 "$T.INSTANCE.$L($L)",
45 custom.typeName,
46 custom.methodName, inputVarName
47 )
48 } else if (custom.isStatic) {
49 CodeBlock.of(
50 "$T.$L($L)",
51 custom.typeName,
52 custom.methodName, inputVarName
53 )
54 } else {
55 if (custom.isProvidedConverter) {
56 CodeBlock.of(
57 "$N().$L($L)",
58 providedTypeConverter(scope),
Jeff Gaston63c23102020-09-18 12:53:59 -040059 custom.methodName, inputVarName
60 )
Alan Viverette6c563342018-03-08 18:02:39 -050061 } else {
Yigit Boyar3b17b092021-08-27 18:38:33 -070062 CodeBlock.of(
63 "$N.$L($L)",
64 typeConverter(scope),
65 custom.methodName, inputVarName
66 )
Alan Viverette6c563342018-03-08 18:02:39 -050067 }
68 }
69 }
70
mzgreen7bd7c652020-09-19 06:02:23 +000071 private fun providedTypeConverter(scope: CodeGenScope): MethodSpec {
72 val className = custom.typeName as ClassName
73 val baseName = className.simpleName().decapitalize(Locale.US)
74
75 val converterClassName = custom.typeName as ClassName
76 scope.writer.addRequiredTypeConverter(converterClassName)
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040077 val converterField = scope.writer.getOrCreateField(
78 object : TypeWriter.SharedFieldSpec(
79 baseName, custom.typeName
80 ) {
Jeff Gaston63c23102020-09-18 12:53:59 -040081 override fun getUniqueKey(): String {
82 return "converter_${custom.typeName}"
83 }
mzgreen7bd7c652020-09-19 06:02:23 +000084
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040085 override fun prepare(writer: TypeWriter, builder: FieldSpec.Builder) {
Jeff Gaston63c23102020-09-18 12:53:59 -040086 builder.addModifiers(Modifier.PRIVATE)
87 }
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040088 }
89 )
mzgreen7bd7c652020-09-19 06:02:23 +000090
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040091 return scope.writer.getOrCreateMethod(object : TypeWriter.SharedMethodSpec(baseName) {
mzgreen7bd7c652020-09-19 06:02:23 +000092 override fun getUniqueKey(): String {
93 return "converterMethod_${custom.typeName}"
94 }
95
96 override fun prepare(
97 methodName: String,
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -040098 writer: TypeWriter,
mzgreen7bd7c652020-09-19 06:02:23 +000099 builder: MethodSpec.Builder
100 ) {
101 builder.apply {
102 addModifiers(Modifier.PRIVATE)
103 addModifiers(Modifier.SYNCHRONIZED)
104 returns(custom.typeName)
105 addCode(buildConvertMethodBody(writer))
106 }
107 }
108
109 private fun buildConvertMethodBody(
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -0400110 writer: TypeWriter
mzgreen7bd7c652020-09-19 06:02:23 +0000111 ): CodeBlock {
112 val methodScope = CodeGenScope(writer)
113 methodScope.builder().apply {
114 beginControlFlow("if ($N == null)", converterField)
115 addStatement(
116 "$N = $N.getTypeConverter($T.class)",
117 converterField,
118 DaoWriter.dbField,
119 custom.typeName
120 )
121 endControlFlow()
122 addStatement("return $N", converterField)
123 }
124 return methodScope.builder().build()
125 }
126 })
127 }
128
Alan Viverette6c563342018-03-08 18:02:39 -0500129 fun typeConverter(scope: CodeGenScope): FieldSpec {
Simon Schiller5746e332020-08-24 04:31:51 -0700130 val baseName = (custom.typeName as ClassName).simpleName().decapitalize(Locale.US)
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -0400131 return scope.writer.getOrCreateField(
132 object : TypeWriter.SharedFieldSpec(
133 baseName, custom.typeName
134 ) {
Jeff Gaston63c23102020-09-18 12:53:59 -0400135 override fun getUniqueKey(): String {
136 return "converter_${custom.typeName}"
137 }
Alan Viverette6c563342018-03-08 18:02:39 -0500138
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -0400139 override fun prepare(writer: TypeWriter, builder: FieldSpec.Builder) {
Jeff Gaston63c23102020-09-18 12:53:59 -0400140 builder.addModifiers(Modifier.PRIVATE)
141 builder.addModifiers(Modifier.FINAL)
142 builder.initializer("new $T()", custom.typeName)
143 }
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -0400144 }
145 )
Alan Viverette6c563342018-03-08 18:02:39 -0500146 }
147}
mzgreen7bd7c652020-09-19 06:02:23 +0000148
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -0400149fun TypeWriter.addRequiredTypeConverter(className: ClassName) {
mzgreen7bd7c652020-09-19 06:02:23 +0000150 this[ProvidedTypeConverter::class] = getRequiredTypeConverters() + setOf(className)
151}
152
Daniel Santiago Riverafe98c702022-09-22 22:58:50 -0400153fun TypeWriter.getRequiredTypeConverters(): Set<ClassName> {
mzgreen7bd7c652020-09-19 06:02:23 +0000154 return this.get<Set<ClassName>>(ProvidedTypeConverter::class) ?: emptySet()
155}