Preparations for query adapter
This CL makes some changes in preparation for query adapters.
* re-packaged type adapters to be separated from query adapteres
* Changed TypeAdapter store to create chained TypeConverters that
can be merged with 1 ColumnAdapter to create a CompositeColumnAdapter.
In other words, now both CompositeColumnAdapter and
CompositeTypeConverter have just 2 items and they get chained as needed.
This simplifies the readability of our code a lot and has no effect on
the generated code.
* Implemented type converteres from pritivies to String. It is necessary
to create bind arguments for SQL.
* Cleaned up TypeAdapterStore
Test: BasicTypeConvertersTest.kt + existing tests
Bug: 32342709
Change-Id: Ibcd2e05796be2576847d6627b98d17339dfbea65
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt
index b173508..4c98a59 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/ext/javapoet_ext.kt
@@ -16,6 +16,17 @@
package com.android.support.room.ext
+import com.squareup.javapoet.ArrayTypeName
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
+import javax.lang.model.type.TypeMirror
+import kotlin.reflect.KClass
+
val L = "\$L"
val T = "\$T"
-val N = "\$N"
\ No newline at end of file
+val N = "\$N"
+val S = "\$S"
+
+fun KClass<*>.typeName() = ClassName.get(this.java)
+fun KClass<*>.arrayTypeName() = ArrayTypeName.of(typeName())
+fun TypeMirror.typeName() = TypeName.get(this)
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/parser/ParsedQuery.kt b/room/compiler/src/main/kotlin/com/android/support/room/parser/ParsedQuery.kt
index c0fcd70..c8d5a81 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/parser/ParsedQuery.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/parser/ParsedQuery.kt
@@ -16,6 +16,9 @@
package com.android.support.room.parser
+import com.android.support.room.parser.SectionType.BIND_VAR
+import com.android.support.room.parser.SectionType.NEWLINE
+import com.android.support.room.parser.SectionType.TEXT
import org.antlr.v4.runtime.tree.TerminalNode
enum class SectionType {
@@ -62,6 +65,7 @@
}
sections
}
+
val errors by lazy {
val hasUnnamed = inputs.any { it.text == "?" }
inputs.filter {
@@ -71,4 +75,15 @@
} + (if (hasUnnamed && inputs.size > 1) arrayListOf(ParserErrors.TOO_MANY_UNNAMED_VARIABLES)
else emptyList<String>()) + syntaxErrors
}
+
+ val queryWithReplacedBindParams by lazy {
+ sections.joinToString("") {
+ when(it.type) {
+ TEXT -> ""
+ BIND_VAR -> "?"
+ NEWLINE -> "\n"
+ else -> throw IllegalArgumentException("??")
+ }
+ }
+ }
}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/processor/Context.kt b/room/compiler/src/main/kotlin/com/android/support/room/processor/Context.kt
index 6757309..f684c3d 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/processor/Context.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/processor/Context.kt
@@ -18,6 +18,7 @@
import com.android.support.room.log.RLog
import com.android.support.room.preconditions.Checks
+import com.android.support.room.solver.TypeAdapterStore
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
@@ -25,4 +26,5 @@
val processingEnv: ProcessingEnvironment) {
val logger = RLog(processingEnv)
val checker = Checks(logger)
+ val typeAdapterStore = TypeAdapterStore(roundEnv, processingEnv)
}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/processor/ParameterParser.kt b/room/compiler/src/main/kotlin/com/android/support/room/processor/ParameterParser.kt
index 3ee1abe..641dea2 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/processor/ParameterParser.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/processor/ParameterParser.kt
@@ -17,6 +17,7 @@
package com.android.support.room.processor
import com.android.support.room.vo.Parameter
+import com.google.auto.common.MoreElements
import com.google.auto.common.MoreTypes
import com.squareup.javapoet.TypeName
import javax.lang.model.element.VariableElement
@@ -25,6 +26,12 @@
class ParameterParser(val context: Context) {
fun parse(containing: DeclaredType, element: VariableElement): Parameter {
val asMember = MoreTypes.asMemberOf(context.processingEnv.typeUtils, containing, element)
- return Parameter(element.simpleName.toString(), TypeName.get(asMember))
+ val typeConverter = context.typeAdapterStore.findTypeConverter(asMember,
+ context.processingEnv.elementUtils.getTypeElement("java.lang.String").asType()
+ )
+ context.checker.check(typeConverter != null, element,
+ ProcessorErrors.CANNOT_CONVERT_QUERY_PARAMETER_TO_STRING)
+
+ return Parameter(element.simpleName.toString(), TypeName.get(asMember), typeConverter)
}
}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt
index 3f1c511..6214463 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/processor/ProcessorErrors.kt
@@ -48,6 +48,9 @@
val ENTITY_TABLE_NAME_CANNOT_BE_EMPTY = "Entity table name cannot be blank. If you don't want" +
" to set it, just remove the tableName property."
+ val CANNOT_CONVERT_QUERY_PARAMETER_TO_STRING = "QueryMethod parameters should be suitable to" +
+ " be converted into String but I don't know how to convert this."
+
fun tooManyMatchingGetters(field : Field, methodNames : List<String>) : String {
return TOO_MANY_MATCHING_GETTERS.format(field, methodNames.joinToString(", "))
}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/CodeGenScope.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/CodeGenScope.kt
index 9ad3b49..e9f943f 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/CodeGenScope.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/CodeGenScope.kt
@@ -23,12 +23,13 @@
* Defines a code generation scope where we can provide temporary variables, global variables etc
*/
class CodeGenScope {
- private var tmpVarIndex = 0
+ private var tmpVarIndices = mutableMapOf<String, Int>()
private var builder : CodeBlock.Builder? = null
companion object {
- const val TMP_VAR_PREFIX = "_tmp"
+ const val TMP_VAR_DEFAULT_PREFIX = "_tmp"
@VisibleForTesting
- fun _tmpVar(index:Int) = "${TMP_VAR_PREFIX}_$index"
+ fun _tmpVar(index:Int) = _tmpVar(TMP_VAR_DEFAULT_PREFIX, index)
+ fun _tmpVar(prefix : String, index:Int) = "${prefix}_$index"
}
fun builder() : CodeBlock.Builder {
@@ -39,7 +40,17 @@
}
fun getTmpVar() : String {
- return _tmpVar(tmpVarIndex ++)
+ return getTmpVar(TMP_VAR_DEFAULT_PREFIX)
+ }
+
+ fun getTmpVar(prefix : String) : String {
+ if (!prefix.startsWith("_")) {
+ throw RuntimeException("tmp variable prefixes should start with _")
+ }
+ val index = tmpVarIndices.getOrElse(prefix) { 0 }
+ val result = _tmpVar(prefix, index)
+ tmpVarIndices.put(prefix, index + 1)
+ return result
}
fun generate() = builder().build().toString()
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/CompositeAdapter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/CompositeAdapter.kt
deleted file mode 100644
index 5d52668..0000000
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/CompositeAdapter.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.support.room.solver
-
-import com.android.support.room.ext.L
-import com.android.support.room.ext.T
-import com.squareup.javapoet.TypeName
-import javax.lang.model.type.TypeMirror
-
-/**
- * A column adapter that uses multiple type adapters to do the conversion.
- */
-class CompositeAdapter(out: TypeMirror, val columnTypeAdapter: ColumnTypeAdapter,
- val typeConverters: List<TypeConverter>) : ColumnTypeAdapter(out) {
- override fun readFromCursor(outVarName: String, cursorVarName: String, index: Int,
- scope: CodeGenScope) {
- val reversed = typeConverters.reversed()
-
- scope.builder().apply {
- val tmpCursorValue = scope.getTmpVar()
- addStatement("final $T $L", columnTypeAdapter.outTypeName, tmpCursorValue)
- columnTypeAdapter.readFromCursor(tmpCursorValue, cursorVarName, index, scope)
- var tmpInVar = tmpCursorValue
- var tmpOutVar = scope.getTmpVar()
- reversed.take(reversed.size - 1).forEach {
- addStatement("final $T $L", it.fromTypeName, tmpOutVar)
- it.convertBackward(tmpInVar, tmpOutVar, scope)
- tmpInVar = tmpOutVar
- tmpOutVar = scope.getTmpVar()
- }
- reversed.last().convertBackward(tmpInVar, outVarName, scope)
- }
- }
-
- override fun bindToStmt(stmtName: String, index: Int, valueVarName: String,
- scope: CodeGenScope) {
- var tmpInVar = valueVarName
- var tmpOutVar = scope.getTmpVar()
- scope.builder().apply {
- typeConverters.forEach {
- addStatement("final $T $L", it.toTypeName, tmpOutVar)
- it.convertForward(tmpInVar, tmpOutVar, scope)
- tmpInVar = tmpOutVar
- tmpOutVar = scope.getTmpVar()
- }
- columnTypeAdapter.bindToStmt(stmtName, index, tmpInVar, scope)
- }
- }
-}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/PrimitiveColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/PrimitiveColumnTypeAdapter.kt
deleted file mode 100644
index 13178ce..0000000
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/PrimitiveColumnTypeAdapter.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.support.room.solver
-
-import com.android.support.room.ext.L
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.type.PrimitiveType
-import javax.lang.model.type.TypeKind
-
-/**
- * Adapters for all primitives that has direct cursor mappings.
- */
-open class PrimitiveColumnTypeAdapter(out: PrimitiveType,
- val cursorGetter: String,
- val stmtSetter: String,
- cast: Boolean = false) : ColumnTypeAdapter(out) {
- val cast = if (cast) "(${out.kind.name.toLowerCase()}) " else ""
-
- companion object {
- fun createPrimitiveAdapters(processingEnvironment: ProcessingEnvironment)
- : List<ColumnTypeAdapter> {
- return listOf(PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.INT),
- cursorGetter = "getInt",
- stmtSetter = "bindLong"),
- PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.SHORT),
- cursorGetter = "getShort",
- stmtSetter = "bindLong"),
- PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.BYTE),
- cursorGetter = "getShort",
- stmtSetter = "bindLong",
- cast = true),
- PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.LONG),
- cursorGetter = "getLong",
- stmtSetter = "bindLong"),
- PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.CHAR),
- cursorGetter = "getInt",
- stmtSetter = "bindLong",
- cast = true),
- PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.FLOAT),
- cursorGetter = "getFloat",
- stmtSetter = "bindDouble"),
- PrimitiveColumnTypeAdapter(
- out = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.DOUBLE),
- cursorGetter = "getDouble",
- stmtSetter = "bindDouble"))
- }
- }
-
- override fun bindToStmt(stmtName: String, index: Int, valueVarName: String,
- scope: CodeGenScope) {
- scope.builder()
- .addStatement("$L.$L($L, $L)", stmtName, stmtSetter, index, valueVarName)
- }
-
- override fun readFromCursor(outVarName: String, cursorVarName: String, index: Int,
- scope: CodeGenScope) {
- scope.builder()
- .addStatement("$L = $L$L.$L($L)", outVarName, cast, cursorVarName,
- cursorGetter, index)
- }
-}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/TypeAdapterStore.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/TypeAdapterStore.kt
index 2e1d5de..6932cc5 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/TypeAdapterStore.kt
@@ -16,6 +16,20 @@
package com.android.support.room.solver
+import com.android.support.room.solver.types.BoxedBooleanToBoxedIntConverter
+import com.android.support.room.solver.types.BoxedPrimitiveToStringConverter
+import com.android.support.room.solver.types.ColumnTypeAdapter
+import com.android.support.room.solver.types.CompositeAdapter
+import com.android.support.room.solver.types.CompositeTypeConverter
+import com.android.support.room.solver.types.IntListConverter
+import com.android.support.room.solver.types.PrimitiveBooleanToIntConverter
+import com.android.support.room.solver.types.PrimitiveColumnTypeAdapter
+import com.android.support.room.solver.types.PrimitiveToStringConverter
+import com.android.support.room.solver.types.ReverseTypeConverter
+import com.android.support.room.solver.types.StringColumnTypeAdapter
+import com.android.support.room.solver.types.TypeConverter
+import com.google.common.annotations.VisibleForTesting
+import java.util.*
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.type.TypeMirror
@@ -25,72 +39,104 @@
* database column.
*/
class TypeAdapterStore(val roundEnv: RoundEnvironment,
- val processingEnvironment: ProcessingEnvironment) {
- private val columnTypeAdapters = arrayListOf<ColumnTypeAdapter>()
- private val typeAdapters = arrayListOf<TypeConverter>()
+ val processingEnvironment: ProcessingEnvironment,
+ @VisibleForTesting vararg extras : Any) {
+ private val columnTypeAdapters : List<ColumnTypeAdapter>
+ private val typeConverters : List<TypeConverter>
init {
- PrimitiveColumnTypeAdapter.createPrimitiveAdapters(processingEnvironment).forEach {
- addColumnAdapter(it)
- }
- addColumnAdapter(StringColumnTypeAdapter(processingEnvironment))
- addTypeAdapter(IntListConverter.create(processingEnvironment))
- addTypeAdapter(PrimitiveBooleanToIntConverter(processingEnvironment))
- }
-
- fun getTypeAdapters(input : TypeMirror, excludes : Set<TypeMirror>) : List<TypeConverter>? {
- // TODO optimize
- return if (findColumnAdapters(input).isNotEmpty()) {
- emptyList()
- } else {
- val candidate = findTypeAdapters(input)
- .filterNot { excludes.contains(it.to) }
- .map {
- Pair(it, getTypeAdapters(it.to, excludes + it.from))
- }
- .filterNot { it.second == null }
- .sortedBy { it.second!!.size }
- .firstOrNull()
- return if (candidate == null) {
- null
- } else {
- listOf(candidate.first) + candidate.second!!
+ val adapters = arrayListOf<ColumnTypeAdapter>()
+ val converters = arrayListOf<TypeConverter>()
+ extras.forEach {
+ when(it) {
+ is TypeConverter -> converters.add(it)
+ is ColumnTypeAdapter -> adapters.add(it)
+ else -> throw IllegalArgumentException("unknown extra")
}
}
+ fun addTypeConverter(converter: TypeConverter) {
+ converters.add(converter)
+ converters.add(ReverseTypeConverter(converter))
+ }
+
+ fun addColumnAdapter(adapter: ColumnTypeAdapter) {
+ adapters.add(adapter)
+ }
+
+ PrimitiveColumnTypeAdapter
+ .createPrimitiveAdapters(processingEnvironment)
+ .forEach(::addColumnAdapter)
+ addColumnAdapter(StringColumnTypeAdapter(processingEnvironment))
+ addTypeConverter(IntListConverter.create(processingEnvironment))
+ addTypeConverter(PrimitiveBooleanToIntConverter(processingEnvironment))
+ PrimitiveToStringConverter
+ .createPrimitives(processingEnvironment)
+ .forEach(::addTypeConverter)
+ BoxedPrimitiveToStringConverter
+ .createBoxedPrimitives(processingEnvironment)
+ .forEach(::addTypeConverter)
+ addTypeConverter(BoxedBooleanToBoxedIntConverter(processingEnvironment))
+ columnTypeAdapters = adapters
+ typeConverters = converters
}
- fun getAdapterFor(out : TypeMirror) : ColumnTypeAdapter? {
- val adapters = findColumnAdapters(out)
+ // type mirrors that be converted into columns w/o an extra converter
+ private val knownColumnTypeMirrors by lazy {
+ columnTypeAdapters.map { it.out }
+ }
+
+ fun findAdapter(out: TypeMirror): ColumnTypeAdapter? {
+ val adapters = getAllColumnAdapters(out)
if (adapters.isNotEmpty()) {
return adapters.last()
}
- val typeAdapters = getTypeAdapters(out, setOf(out))
- return if (typeAdapters == null) {
- null
- } else {
- return CompositeAdapter(out, findColumnAdapters(typeAdapters.last().to).last(),
- typeAdapters)
+ val converter = findTypeConverter(out, knownColumnTypeMirrors)
+ if (converter != null) {
+ return CompositeAdapter(out, getAllColumnAdapters(converter.to).first(), converter)
}
+ return null
}
- fun addTypeAdapter(converter: TypeConverter) {
- typeAdapters.add(converter)
- typeAdapters.add(ReverseTypeConverter(converter))
+ fun findTypeConverter(input: TypeMirror, output: TypeMirror): TypeConverter? {
+ return findTypeConverter(input, listOf(output))
}
- fun addColumnAdapter(adapter: ColumnTypeAdapter) {
- columnTypeAdapters.add(adapter)
+ private fun findTypeConverter(input: TypeMirror, outputs: List<TypeMirror>): TypeConverter? {
+ val types = processingEnvironment.typeUtils
+ val excludes = arrayListOf<TypeMirror>()
+ excludes.add(input)
+ val queue = LinkedList<TypeConverter>()
+ do {
+ val prev = if (queue.isEmpty()) null else queue.pop()
+ val from = prev?.to ?: input
+ val candidates = getAllTypeConverters(from, excludes)
+ val match = candidates.firstOrNull {
+ outputs.any { output -> types.isSameType(output, it.to) } }
+ if (match != null) {
+ return if (prev == null) match else CompositeTypeConverter(prev, match)
+ }
+ candidates.forEach {
+ excludes.add(it.to)
+ queue.add(
+ if (prev == null) it else CompositeTypeConverter(prev, it)
+ )
+ }
+ } while (queue.isNotEmpty())
+ return null
}
- fun findColumnAdapters(input : TypeMirror) : List<ColumnTypeAdapter> {
+ private fun getAllColumnAdapters(input: TypeMirror): List<ColumnTypeAdapter> {
return columnTypeAdapters.filter {
processingEnvironment.typeUtils.isSameType(input, it.out)
}
}
- fun findTypeAdapters(input : TypeMirror) : List<TypeConverter> {
- return typeAdapters.filter {
- processingEnvironment.typeUtils.isSameType(input, it.from)
+ private fun getAllTypeConverters(input: TypeMirror, excludes : List<TypeMirror>):
+ List<TypeConverter> {
+ val types = processingEnvironment.typeUtils
+ return typeConverters.filter { converter ->
+ types.isSameType(input, converter.from) &&
+ !excludes.any { types.isSameType(it, converter.to) }
}
}
}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/types/BoxedBooleanToBoxedIntConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/BoxedBooleanToBoxedIntConverter.kt
new file mode 100644
index 0000000..ec9702d
--- /dev/null
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/BoxedBooleanToBoxedIntConverter.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver.types
+
+import com.android.support.room.ext.L
+import com.android.support.room.solver.CodeGenScope
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.type.TypeKind
+import javax.lang.model.type.TypeKind.BOOLEAN
+import javax.lang.model.type.TypeKind.INT
+
+/**
+ * int to boolean adapter.
+ */
+class BoxedBooleanToBoxedIntConverter(processingEnvironment: ProcessingEnvironment) : TypeConverter(
+ from = processingEnvironment.elementUtils.getTypeElement("java.lang.Boolean").asType(),
+ to = processingEnvironment.elementUtils.getTypeElement("java.lang.Integer").asType()) {
+ override fun convertForward(inputVarName: String, outputVarName: String,
+ scope: CodeGenScope) {
+ scope.builder().addStatement("$L = $L == null ? null : ($L ? 1 : 0)",
+ outputVarName, inputVarName, inputVarName)
+ }
+
+ override fun convertBackward(inputVarName: String, outputVarName: String,
+ scope: CodeGenScope) {
+ scope.builder().addStatement("$L = $L == null ? null : $L != 0", outputVarName,
+ inputVarName, inputVarName)
+ }
+}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/types/BoxedPrimitiveToStringConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/BoxedPrimitiveToStringConverter.kt
new file mode 100644
index 0000000..016565f
--- /dev/null
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/BoxedPrimitiveToStringConverter.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver.types
+
+import com.android.support.room.ext.L
+import com.android.support.room.ext.T
+import com.android.support.room.ext.typeName
+import com.android.support.room.solver.CodeGenScope
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.type.TypeMirror
+
+@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
+open class BoxedPrimitiveToStringConverter(val boxed: TypeMirror,
+ val parseMethod: String,
+ stringType: TypeMirror)
+ : TypeConverter(boxed, stringType) {
+ companion object {
+ fun createBoxedPrimitives(processingEnv: ProcessingEnvironment): List<TypeConverter> {
+ val elmUtils = processingEnv.elementUtils
+ val stringType = processingEnv.elementUtils.getTypeElement("java.lang.String").asType()
+ return listOf(
+ Pair(java.lang.Integer::class, "parseInt"),
+ Pair(java.lang.Long::class, "parseLong"),
+ Pair(java.lang.Short::class, "parseShort"),
+ Pair(java.lang.Byte::class, "parseByte"),
+ Pair(java.lang.Float::class, "parseFloat"),
+ Pair(java.lang.Double::class, "parseDouble")
+ ).map {
+ BoxedPrimitiveToStringConverter(
+ boxed = elmUtils.getTypeElement(it.first.java.canonicalName).asType(),
+ parseMethod = it.second,
+ stringType = stringType
+ )
+ } + object : BoxedPrimitiveToStringConverter(
+ boxed = elmUtils.getTypeElement("java.lang.Character").asType(),
+ parseMethod = "",
+ stringType = stringType
+ ) {
+ override fun convertBackward(inputVarName: String, outputVarName: String,
+ scope: CodeGenScope) {
+ scope.builder().addStatement("$L = $L == null ? null : $L.charAt(0)",
+ outputVarName, inputVarName, inputVarName)
+ }
+ }
+ }
+ }
+
+ override fun convertForward(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
+ scope.builder()
+ .addStatement("$L = $L == null ? null : $T.toString($L)", outputVarName,
+ inputVarName, boxed.typeName(), inputVarName)
+ }
+
+ override fun convertBackward(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
+ scope.builder()
+ .addStatement("$L = $L == null ? null : $T.$L($L)", outputVarName, inputVarName,
+ boxed.typeName(), parseMethod, inputVarName)
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/ColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/ColumnTypeAdapter.kt
similarity index 92%
rename from room/compiler/src/main/kotlin/com/android/support/room/solver/ColumnTypeAdapter.kt
rename to room/compiler/src/main/kotlin/com/android/support/room/solver/types/ColumnTypeAdapter.kt
index 31ab2c9..af48ebd 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/ColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/ColumnTypeAdapter.kt
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.support.room.solver
+package com.android.support.room.solver.types
+import com.android.support.room.solver.CodeGenScope
import com.squareup.javapoet.TypeName
import javax.lang.model.type.TypeMirror
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/types/CompositeAdapter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/CompositeAdapter.kt
new file mode 100644
index 0000000..ccdd23f
--- /dev/null
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/CompositeAdapter.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver.types
+
+import com.android.support.room.ext.L
+import com.android.support.room.ext.T
+import com.android.support.room.solver.CodeGenScope
+import com.squareup.javapoet.TypeName
+import javax.lang.model.type.TypeMirror
+
+/**
+ * A column adapter that uses a type converter to do the conversion. The type converter may be
+ * a composite one.
+ */
+class CompositeAdapter(out: TypeMirror, val columnTypeAdapter: ColumnTypeAdapter,
+ val typeConverter : TypeConverter) : ColumnTypeAdapter(out) {
+ override fun readFromCursor(outVarName: String, cursorVarName: String, index: Int,
+ scope: CodeGenScope) {
+ scope.builder().apply {
+ val tmpCursorValue = scope.getTmpVar()
+ addStatement("final $T $L", columnTypeAdapter.outTypeName, tmpCursorValue)
+ columnTypeAdapter.readFromCursor(tmpCursorValue, cursorVarName, index, scope)
+ typeConverter.convertBackward(tmpCursorValue, outVarName, scope)
+ }
+ }
+
+ override fun bindToStmt(stmtName: String, index: Int, valueVarName: String,
+ scope: CodeGenScope) {
+ scope.builder().apply {
+ val tmpVar = scope.getTmpVar()
+ addStatement("final $T $L", columnTypeAdapter.out, tmpVar)
+ typeConverter.convertForward(valueVarName, tmpVar, scope)
+ columnTypeAdapter.bindToStmt(stmtName, index, tmpVar, scope)
+ }
+ }
+}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/types/CompositeTypeConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/CompositeTypeConverter.kt
new file mode 100644
index 0000000..c2658dc
--- /dev/null
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/CompositeTypeConverter.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver.types
+
+import com.android.support.room.ext.L
+import com.android.support.room.ext.T
+import com.android.support.room.ext.typeName
+import com.android.support.room.solver.CodeGenScope
+
+/**
+ * combines 2 type converters
+ */
+class CompositeTypeConverter(val conv1 : TypeConverter, val conv2 : TypeConverter) : TypeConverter(
+ conv1.from, conv2.to) {
+ override fun convertForward(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
+ scope.builder().apply {
+ val tmp = scope.getTmpVar()
+ addStatement("final $T $L", conv1.to.typeName(), tmp)
+ conv1.convertForward(inputVarName, tmp, scope)
+ conv2.convertForward(tmp, outputVarName, scope)
+ }
+
+ }
+
+ override fun convertBackward(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
+ scope.builder().apply {
+ val tmp = scope.getTmpVar()
+ addStatement("final $T $L", conv2.from.typeName(), tmp)
+ conv2.convertBackward(inputVarName, tmp, scope)
+ conv1.convertBackward(tmp, outputVarName, scope)
+ }
+ }
+}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/IntListConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/IntListConverter.kt
similarity index 95%
rename from room/compiler/src/main/kotlin/com/android/support/room/solver/IntListConverter.kt
rename to room/compiler/src/main/kotlin/com/android/support/room/solver/types/IntListConverter.kt
index 093661e..f48d041 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/IntListConverter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/IntListConverter.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.support.room.solver
+package com.android.support.room.solver.types
import com.android.support.room.ext.L
import com.android.support.room.ext.N
import com.android.support.room.ext.T
+import com.android.support.room.solver.CodeGenScope
import com.squareup.javapoet.ClassName
import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.type.TypeMirror
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/PrimitiveBooleanToIntConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveBooleanToIntConverter.kt
similarity index 83%
rename from room/compiler/src/main/kotlin/com/android/support/room/solver/PrimitiveBooleanToIntConverter.kt
rename to room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveBooleanToIntConverter.kt
index f4f312b..ea8ace8 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/PrimitiveBooleanToIntConverter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveBooleanToIntConverter.kt
@@ -14,18 +14,21 @@
* limitations under the License.
*/
-package com.android.support.room.solver
+package com.android.support.room.solver.types
import com.android.support.room.ext.L
+import com.android.support.room.solver.CodeGenScope
import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.type.TypeKind
+import javax.lang.model.type.TypeKind.BOOLEAN
+import javax.lang.model.type.TypeKind.INT
/**
* int to boolean adapter.
*/
class PrimitiveBooleanToIntConverter(processingEnvironment: ProcessingEnvironment) : TypeConverter(
- from = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.BOOLEAN),
- to = processingEnvironment.typeUtils.getPrimitiveType(TypeKind.INT)) {
+ from = processingEnvironment.typeUtils.getPrimitiveType(BOOLEAN),
+ to = processingEnvironment.typeUtils.getPrimitiveType(INT)) {
override fun convertForward(inputVarName: String, outputVarName: String,
scope: CodeGenScope) {
scope.builder().addStatement("$L = $L ? 1 : 0", outputVarName, inputVarName)
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveColumnTypeAdapter.kt
new file mode 100644
index 0000000..96aa080
--- /dev/null
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveColumnTypeAdapter.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver.types
+
+import com.android.support.room.ext.L
+import com.android.support.room.ext.typeName
+import com.android.support.room.solver.CodeGenScope
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.type.PrimitiveType
+import javax.lang.model.type.TypeKind
+import javax.lang.model.type.TypeKind.BYTE
+import javax.lang.model.type.TypeKind.CHAR
+import javax.lang.model.type.TypeKind.DOUBLE
+import javax.lang.model.type.TypeKind.FLOAT
+import javax.lang.model.type.TypeKind.INT
+import javax.lang.model.type.TypeKind.LONG
+import javax.lang.model.type.TypeKind.SHORT
+
+/**
+ * Adapters for all primitives that has direct cursor mappings.
+ */
+open class PrimitiveColumnTypeAdapter(out: PrimitiveType,
+ val cursorGetter: String,
+ val stmtSetter: String) : ColumnTypeAdapter(out) {
+ val cast = if (cursorGetter == "get${out.typeName().toString().capitalize()}")
+ ""
+ else
+ "(${out.typeName()}) "
+
+ companion object {
+ fun createPrimitiveAdapters(processingEnvironment: ProcessingEnvironment)
+ : List<ColumnTypeAdapter> {
+ return listOf(
+ Triple(INT, "getInt", "bindLong"),
+ Triple(SHORT, "getShort", "bindLong"),
+ Triple(BYTE, "getShort", "bindLong"),
+ Triple(LONG, "getLong", "bindLong"),
+ Triple(CHAR, "getInt", "bindLong"),
+ Triple(FLOAT, "getFloat", "bindDouble"),
+ Triple(DOUBLE, "getDouble", "bindDouble")
+ ).map {
+ PrimitiveColumnTypeAdapter(
+ out = processingEnvironment.typeUtils.getPrimitiveType(it.first),
+ cursorGetter = it.second,
+ stmtSetter = it.third
+ )
+ }
+ }
+ }
+
+ override fun bindToStmt(stmtName: String, index: Int, valueVarName: String,
+ scope: CodeGenScope) {
+ scope.builder()
+ .addStatement("$L.$L($L, $L)", stmtName, stmtSetter, index, valueVarName)
+ }
+
+ override fun readFromCursor(outVarName: String, cursorVarName: String, index: Int,
+ scope: CodeGenScope) {
+ scope.builder()
+ .addStatement("$L = $L$L.$L($L)", outVarName, cast, cursorVarName,
+ cursorGetter, index)
+ }
+}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveToStringConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveToStringConverter.kt
new file mode 100644
index 0000000..b849a0e
--- /dev/null
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/PrimitiveToStringConverter.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver.types
+
+import com.android.support.room.ext.L
+import com.android.support.room.ext.T
+import com.android.support.room.ext.typeName
+import com.android.support.room.solver.CodeGenScope
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.type.PrimitiveType
+import javax.lang.model.type.TypeKind.BYTE
+import javax.lang.model.type.TypeKind.CHAR
+import javax.lang.model.type.TypeKind.DOUBLE
+import javax.lang.model.type.TypeKind.FLOAT
+import javax.lang.model.type.TypeKind.INT
+import javax.lang.model.type.TypeKind.LONG
+import javax.lang.model.type.TypeKind.SHORT
+import javax.lang.model.type.TypeMirror
+
+@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
+open class PrimitiveToStringConverter(val boxed : TypeMirror,
+ val parseMethod : String?,
+ val primitiveType : PrimitiveType,
+ val stringType : TypeMirror) :
+ TypeConverter(primitiveType, stringType) {
+ companion object {
+ fun createPrimitives(processingEnv : ProcessingEnvironment) : List<TypeConverter> {
+ val elmUtils = processingEnv.elementUtils
+ val typeUtils = processingEnv.typeUtils
+ val stringType = processingEnv.elementUtils.getTypeElement("java.lang.String").asType()
+
+ return listOf(
+ Triple(java.lang.Integer::class, "parseInt", INT),
+ Triple(java.lang.Long::class, "parseLong", LONG),
+ Triple(java.lang.Short::class, "parseShort", SHORT),
+ Triple(java.lang.Byte::class, "parseByte", BYTE),
+ Triple(java.lang.Float::class, "parseFloat", FLOAT),
+ Triple(java.lang.Double::class, "parseDouble", DOUBLE)
+ ).map {
+ PrimitiveToStringConverter(
+ boxed = elmUtils.getTypeElement(it.first.java.canonicalName).asType(),
+ parseMethod = it.second,
+ primitiveType = typeUtils.getPrimitiveType(it.third),
+ stringType = stringType
+ )
+ } + object : PrimitiveToStringConverter(
+ boxed = elmUtils.getTypeElement("java.lang.Character").asType(),
+ parseMethod = null,
+ primitiveType = typeUtils.getPrimitiveType(CHAR),
+ stringType = stringType
+ ) {
+ override fun convertBackward(inputVarName: String, outputVarName: String,
+ scope: CodeGenScope) {
+ scope.builder().addStatement("$L = $L.charAt(0)", outputVarName,
+ inputVarName)
+ }
+ }
+
+ }
+ }
+
+ override fun convertForward(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
+ scope.builder()
+ .addStatement("$L = $T.toString($L)", outputVarName, boxed.typeName(), inputVarName)
+ }
+
+ override fun convertBackward(inputVarName: String, outputVarName: String, scope: CodeGenScope) {
+ scope.builder()
+ .addStatement("$L = $T.$L($L)", outputVarName, boxed.typeName(), parseMethod,
+ inputVarName)
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/ReverseTypeConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/ReverseTypeConverter.kt
similarity index 92%
rename from room/compiler/src/main/kotlin/com/android/support/room/solver/ReverseTypeConverter.kt
rename to room/compiler/src/main/kotlin/com/android/support/room/solver/types/ReverseTypeConverter.kt
index 919a374..c96c7cb 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/ReverseTypeConverter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/ReverseTypeConverter.kt
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.support.room.solver
+package com.android.support.room.solver.types
+
+import com.android.support.room.solver.CodeGenScope
/**
* Takes a type adapter and reverses it.
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/StringColumnTypeAdapter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/StringColumnTypeAdapter.kt
similarity index 94%
rename from room/compiler/src/main/kotlin/com/android/support/room/solver/StringColumnTypeAdapter.kt
rename to room/compiler/src/main/kotlin/com/android/support/room/solver/types/StringColumnTypeAdapter.kt
index a6ee779..8ff150b 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/StringColumnTypeAdapter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/StringColumnTypeAdapter.kt
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.support.room.solver
+package com.android.support.room.solver.types
import com.android.support.room.ext.L
+import com.android.support.room.solver.CodeGenScope
import javax.annotation.processing.ProcessingEnvironment
class StringColumnTypeAdapter(processingEnvironment: ProcessingEnvironment)
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/solver/TypeConverter.kt b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/TypeConverter.kt
similarity index 92%
rename from room/compiler/src/main/kotlin/com/android/support/room/solver/TypeConverter.kt
rename to room/compiler/src/main/kotlin/com/android/support/room/solver/types/TypeConverter.kt
index 68d5f79..e4300d1 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/solver/TypeConverter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/solver/types/TypeConverter.kt
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.support.room.solver
+package com.android.support.room.solver.types
+import com.android.support.room.solver.CodeGenScope
import com.squareup.javapoet.TypeName
import javax.lang.model.type.TypeMirror
@@ -30,4 +31,4 @@
abstract fun convertBackward(inputVarName: String, outputVarName: String,
scope: CodeGenScope)
-}
\ No newline at end of file
+}
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/vo/Parameter.kt b/room/compiler/src/main/kotlin/com/android/support/room/vo/Parameter.kt
index f9c1a70..cf63425 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/vo/Parameter.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/vo/Parameter.kt
@@ -16,9 +16,15 @@
package com.android.support.room.vo
+import com.android.support.room.solver.types.TypeConverter
import com.squareup.javapoet.TypeName
/**
* Holds the parameter for a {@link QueryMethod}.
*/
-data class Parameter(val name: String, val type: TypeName)
+data class Parameter(val name: String, val type: TypeName,
+ /**
+ * Used when converting this parameter into the String[] of the query
+ * parameters
+ */
+ val stringTypeConverter : TypeConverter?)
diff --git a/room/compiler/src/main/kotlin/com/android/support/room/vo/QueryMethod.kt b/room/compiler/src/main/kotlin/com/android/support/room/vo/QueryMethod.kt
index 9ecaabe..13d2e1d 100644
--- a/room/compiler/src/main/kotlin/com/android/support/room/vo/QueryMethod.kt
+++ b/room/compiler/src/main/kotlin/com/android/support/room/vo/QueryMethod.kt
@@ -18,11 +18,11 @@
import com.android.support.room.parser.ParsedQuery
import com.squareup.javapoet.TypeName
-import javax.lang.model.element.Element
+import javax.lang.model.element.ExecutableElement
/**
* A class that holds information about a QueryMethod.
* It is self sufficient and must have all generics etc resolved once created.
*/
-data class QueryMethod(val element : Element, val query: ParsedQuery, val name: String,
+data class QueryMethod(val element : ExecutableElement, val query: ParsedQuery, val name: String,
val returnType: TypeName, val parameters: List<Parameter>)
diff --git a/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicColumnTypeAdaptersTest.kt b/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicColumnTypeAdaptersTest.kt
index 3c9a937..2ea3649 100644
--- a/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicColumnTypeAdaptersTest.kt
+++ b/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicColumnTypeAdaptersTest.kt
@@ -79,7 +79,7 @@
fun bind() {
simpleRun { invocation ->
val adapter = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
- .getAdapterFor(input.getTypeMirror(invocation.processingEnv))!!
+ .findAdapter(input.getTypeMirror(invocation.processingEnv))!!
adapter.bindToStmt("st", 6, "inp", scope)
assertThat(scope.generate().trim(), `is`(bindCode))
generateCode(invocation)
@@ -106,7 +106,7 @@
fun read() {
simpleRun { invocation ->
val adapter = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
- .getAdapterFor(input.getTypeMirror(invocation.processingEnv))!!
+ .findAdapter(input.getTypeMirror(invocation.processingEnv))!!
adapter.readFromCursor("out", "crs", 9, scope)
assertThat(scope.generate().trim(), `is`(cursorCode))
generateCode(invocation)
diff --git a/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicTypeConvertersTest.kt b/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicTypeConvertersTest.kt
new file mode 100644
index 0000000..662fe4b
--- /dev/null
+++ b/room/compiler/src/test/kotlin/com/android/support/room/solver/BasicTypeConvertersTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.support.room.solver
+
+import com.android.support.room.testing.TestInvocation
+import com.squareup.javapoet.*
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import simpleRun
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.type.TypeKind
+import javax.lang.model.type.TypeKind.DECLARED
+import javax.lang.model.type.TypeMirror
+
+@RunWith(Parameterized::class)
+class BasicTypeConvertersTest(val input: Input, val forwardCode: String,
+ val backwardCode: String) {
+ val scope = CodeGenScope()
+
+ companion object {
+ @Parameterized.Parameters(name = "kind:{0},bind:_{1},cursor:_{2}")
+ @JvmStatic
+ fun params(): List<Array<Any>> {
+ return listOf(
+ arrayOf(Input(TypeKind.BOOLEAN),
+ """
+ final int _tmp_0;
+ _tmp_0 = inp ? 1 : 0;
+ out = java.lang.Integer.toString(_tmp_0);
+ """.trimIndent(),
+ """
+ final int _tmp_0;
+ _tmp_0 = java.lang.Integer.parseInt(inp);
+ out = _tmp_0 != 0;
+ """.trimIndent()),
+ arrayOf(Input(TypeKind.INT),
+ "out = java.lang.Integer.toString(inp);",
+ "out = java.lang.Integer.parseInt(inp);"),
+ arrayOf(Input(TypeKind.BYTE),
+ "out = java.lang.Byte.toString(inp);",
+ "out = java.lang.Byte.parseByte(inp);"),
+ arrayOf(Input(TypeKind.SHORT),
+ "out = java.lang.Short.toString(inp);",
+ "out = java.lang.Short.parseShort(inp);"),
+ arrayOf(Input(TypeKind.LONG),
+ "out = java.lang.Long.toString(inp);",
+ "out = java.lang.Long.parseLong(inp);"),
+ arrayOf(Input(TypeKind.CHAR),
+ "out = java.lang.Character.toString(inp);",
+ "out = inp.charAt(0);"),
+ arrayOf(Input(TypeKind.FLOAT),
+ "out = java.lang.Float.toString(inp);",
+ "out = java.lang.Float.parseFloat(inp);"),
+ arrayOf(Input(TypeKind.DOUBLE),
+ "out = java.lang.Double.toString(inp);",
+ "out = java.lang.Double.parseDouble(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Integer"),
+ "out = inp == null ? null : java.lang.Integer.toString(inp);",
+ "out = inp == null ? null : java.lang.Integer.parseInt(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Byte"),
+ "out = inp == null ? null : java.lang.Byte.toString(inp);",
+ "out = inp == null ? null : java.lang.Byte.parseByte(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Short"),
+ "out = inp == null ? null : java.lang.Short.toString(inp);",
+ "out = inp == null ? null : java.lang.Short.parseShort(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Long"),
+ "out = inp == null ? null : java.lang.Long.toString(inp);",
+ "out = inp == null ? null : java.lang.Long.parseLong(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Float"),
+ "out = inp == null ? null : java.lang.Float.toString(inp);",
+ "out = inp == null ? null : java.lang.Float.parseFloat(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Double"),
+ "out = inp == null ? null : java.lang.Double.toString(inp);",
+ "out = inp == null ? null : java.lang.Double.parseDouble(inp);"),
+ arrayOf(Input(DECLARED, "java.lang.Character"),
+ "out = inp == null ? null : java.lang.Character.toString(inp);",
+ "out = inp == null ? null : inp.charAt(0);"),
+ arrayOf(Input(DECLARED, "java.lang.Boolean"),
+ """
+ final java.lang.Integer _tmp_0;
+ _tmp_0 = inp == null ? null : (inp ? 1 : 0);
+ out = _tmp_0 == null ? null : java.lang.Integer.toString(_tmp_0);
+ """.trimIndent(),
+ """
+ final java.lang.Integer _tmp_0;
+ _tmp_0 = inp == null ? null : java.lang.Integer.parseInt(inp);
+ out = _tmp_0 == null ? null : _tmp_0 != 0;
+ """.trimIndent()))
+ }
+ }
+
+ @Test
+ fun forward() {
+ simpleRun { invocation ->
+ val stringTypeMirror = invocation
+ .processingEnv.elementUtils
+ .getTypeElement("java.lang.String").asType()
+ val converter = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
+ .findTypeConverter(input.getTypeMirror(invocation.processingEnv),
+ stringTypeMirror)!!
+ converter.convertForward("inp", "out", scope)
+ assertThat(scope.generate().trim(), `is`(forwardCode))
+ generateCode(invocation, input.getTypeMirror(invocation.processingEnv),
+ stringTypeMirror)
+ }.compilesWithoutError()
+ }
+
+ @Test
+ fun backward() {
+ simpleRun { invocation ->
+ val stringTypeMirror = invocation
+ .processingEnv.elementUtils
+ .getTypeElement("java.lang.String").asType()
+ val converter = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
+ .findTypeConverter(input.getTypeMirror(invocation.processingEnv),
+ stringTypeMirror)!!
+ converter.convertBackward("inp", "out", scope)
+ assertThat(scope.generate().trim(), `is`(backwardCode))
+ generateCode(invocation, stringTypeMirror,
+ input.getTypeMirror(invocation.processingEnv))
+ }.compilesWithoutError()
+ }
+
+ private fun generateCode(invocation: TestInvocation, inpType : TypeMirror,
+ outType : TypeMirror) {
+ input.getTypeMirror(invocation.processingEnv)
+ val spec = TypeSpec.classBuilder("OutClass")
+ .addField(FieldSpec.builder(TypeName.get(outType), "out").build())
+ .addField(FieldSpec.builder(TypeName.get(inpType), "inp").build())
+ .addMethod(
+ MethodSpec.methodBuilder("foo")
+ .addCode(scope.builder().build())
+ .build()
+ )
+ .build()
+ JavaFile.builder("foo.bar", spec).build().writeTo(invocation.processingEnv.filer)
+ }
+
+ data class Input(val typeKind: TypeKind, val qName : String? = null) {
+ fun getTypeMirror(processingEnv: ProcessingEnvironment) : TypeMirror {
+ return if (typeKind.isPrimitive) {
+ processingEnv.typeUtils.getPrimitiveType(typeKind)
+ } else {
+ processingEnv.elementUtils.getTypeElement(qName).asType()
+ }
+ }
+ }
+}
diff --git a/room/compiler/src/test/kotlin/com/android/support/room/solver/TypeAdapterStoreTest.kt b/room/compiler/src/test/kotlin/com/android/support/room/solver/TypeAdapterStoreTest.kt
index 25fce2f..3e94524 100644
--- a/room/compiler/src/test/kotlin/com/android/support/room/solver/TypeAdapterStoreTest.kt
+++ b/room/compiler/src/test/kotlin/com/android/support/room/solver/TypeAdapterStoreTest.kt
@@ -19,6 +19,8 @@
import com.android.support.room.Entity
import com.android.support.room.ext.L
import com.android.support.room.ext.T
+import com.android.support.room.solver.types.CompositeAdapter
+import com.android.support.room.solver.types.TypeConverter
import com.android.support.room.testing.TestInvocation
import com.android.support.room.testing.TestProcessor
import com.google.common.truth.Truth
@@ -45,7 +47,7 @@
singleRun { invocation ->
val store = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
val primitiveType = invocation.processingEnv.typeUtils.getPrimitiveType(TypeKind.INT)
- val adapter = store.getAdapterFor(primitiveType)
+ val adapter = store.findAdapter(primitiveType)
assertThat(adapter, notNullValue())
}.compilesWithoutError()
}
@@ -56,7 +58,7 @@
val store = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
val booleanType = invocation.processingEnv.typeUtils
.getPrimitiveType(TypeKind.BOOLEAN)
- val adapter = store.getAdapterFor(booleanType)
+ val adapter = store.findAdapter(booleanType)
assertThat(adapter, notNullValue())
assertThat(adapter, instanceOf(CompositeAdapter::class.java))
val bindScope = CodeGenScope()
@@ -80,22 +82,22 @@
@Test
fun testVia2TypeAdapters() {
singleRun { invocation ->
- val store = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv)
- store.addTypeAdapter(PointTypeConverter(invocation.processingEnv))
+ val store = TypeAdapterStore(invocation.roundEnv, invocation.processingEnv,
+ PointTypeConverter(invocation.processingEnv))
val pointType = invocation.processingEnv.elementUtils
.getTypeElement("foo.bar.Point").asType()
- val adapter = store.getAdapterFor(pointType)
+ val adapter = store.findAdapter(pointType)
assertThat(adapter, notNullValue())
assertThat(adapter, instanceOf(CompositeAdapter::class.java))
val bindScope = CodeGenScope()
adapter!!.bindToStmt("stmt", 41, "fooVar", bindScope)
assertThat(bindScope.generate().trim(), `is`("""
- final boolean ${tmp(0)};
- ${tmp(0)} = foo.bar.Point.toBoolean(fooVar);
- final int ${tmp(1)};
- ${tmp(1)} = ${tmp(0)} ? 1 : 0;
- stmt.bindLong(41, ${tmp(1)});
+ final int ${tmp(0)};
+ final boolean ${tmp(1)};
+ ${tmp(1)} = foo.bar.Point.toBoolean(fooVar);
+ ${tmp(0)} = ${tmp(1)} ? 1 : 0;
+ stmt.bindLong(41, ${tmp(0)});
""".trimIndent()))
val cursorScope = CodeGenScope()
@@ -120,7 +122,7 @@
val listType = invocation.processingEnv.elementUtils
.getTypeElement(java.util.List::class.java.canonicalName)
val listOfInts = invocation.processingEnv.typeUtils.getDeclaredType(listType, intType)
- val adapter = store.getAdapterFor(listOfInts)
+ val adapter = store.findAdapter(listOfInts)
assertThat(adapter, notNullValue())
val bindScope = CodeGenScope()