Merge "Expose a list of default values for XAnnotation" into androidx-main
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
index a0e190e..3df0f9f 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
@@ -74,6 +74,9 @@
/** All values declared in the annotation class. */
val annotationValues: List<XAnnotationValue>
+ /** All default values declared in the annotation class. */
+ val defaultValues: List<XAnnotationValue>
+
/** Returns the value of the given [methodName] as a type reference. */
fun getAsType(methodName: String): XType = getAnnotationValue(methodName).asType()
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt
index a1cd205..1582a0e 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt
@@ -21,7 +21,6 @@
import androidx.room.compiler.processing.XAnnotationValue
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XType
-import androidx.room.compiler.processing.compat.XConverters.toXProcessing
import com.google.auto.common.AnnotationMirrors
import com.google.auto.common.MoreTypes
import javax.lang.model.element.AnnotationMirror
@@ -49,10 +48,23 @@
annotationValues.filter { explicitValues.contains(it.name) }
}
+ override val defaultValues: List<XAnnotationValue> by lazy {
+ annotationValues.mapNotNull {
+ val method = (it as JavacAnnotationValue).method
+ method.element.getDefaultValue()?.let { value ->
+ JavacAnnotationValue(env, method, value)
+ }
+ }
+ }
+
override val annotationValues: List<XAnnotationValue> by lazy {
AnnotationMirrors.getAnnotationValuesWithDefaults(mirror)
.map { (executableElement, annotationValue) ->
- annotationValue.toXProcessing(executableElement, env)
+ JavacAnnotationValue(
+ env,
+ env.wrapExecutableElement(executableElement) as JavacMethodElement,
+ annotationValue
+ )
}
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
index c4eb412..fb9cdaa 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
@@ -31,7 +31,7 @@
internal class JavacAnnotationValue(
val env: JavacProcessingEnv,
- private val method: JavacMethodElement,
+ val method: JavacMethodElement,
val annotationValue: AnnotationValue,
override val valueType: XType = method.returnType,
private val valueProvider: () -> Any? = {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
index 00cafd2..023311f 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
@@ -67,4 +67,8 @@
}
}
}
+
+ override val defaultValues: List<XAnnotationValue> by lazy {
+ typeElement.getDeclaredMethods().mapNotNull { it.defaultValue }
+ }
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
index 2012535..1e244b3 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
@@ -23,6 +23,7 @@
import com.google.devtools.ksp.getConstructors
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSValueArgument
import com.google.devtools.ksp.symbol.Origin
internal class KspAnnotation(
@@ -50,32 +51,20 @@
}
}
+ override val defaultValues: List<XAnnotationValue> by lazy {
+ wrap(ksAnnotated.defaultArguments)
+ }
+
override val annotationValues: List<XAnnotationValue> by lazy {
- // Whether the annotation value is being treated as property or abstract method depends on
- // the actual usage of the annotation. If the annotation is being used on Java source, then
- // the annotation value will have a corresponding method element, otherwise, it will become
- // a kotlin property.
- val typesByName =
- buildMap {
- typeElement.getDeclaredMethods()
- .filter {
- if ((typeElement as KspTypeElement).declaration
- .getConstructors()
- .single().parameters
- .isNotEmpty()) {
- it.isKotlinPropertyMethod()
- } else {
- it.isAbstract()
- }
- }.forEach {
- put(it.name, it.returnType)
- put(it.jvmName, it.returnType)
- }
- }
- // KSAnnotated.arguments isn't guaranteed to have the same ordering as declared in the
- // annotation declaration, so we order it manually using a map from name to index.
+ wrap(ksAnnotated.arguments)
+ }
+
+ private fun wrap(source: List<KSValueArgument>): List<XAnnotationValue> {
+ // KSAnnotated.arguments / KSAnnotated.defaultArguments isn't guaranteed to have the same
+ // ordering as declared in the annotation declaration, so we order it manually using a map
+ // from name to index.
val indexByName = typesByName.keys.mapIndexed { index, name -> name to index }.toMap()
- ksAnnotated.arguments.map {
+ return source.map {
val valueName = it.name?.asString()
?: error("Value argument $it does not have a name.")
val valueType = typesByName[valueName]
@@ -84,6 +73,31 @@
}.sortedBy { indexByName[it.name] }
}
+ // A map of annotation value name to type.
+ private val typesByName: Map<String, XType> by lazy {
+ buildMap {
+ typeElement.getDeclaredMethods()
+ .filter {
+ // Whether the annotation value is being treated as property or
+ // abstract method depends on the actual usage of the annotation.
+ // If the annotation is being used on Java source, then the annotation
+ // value will have a corresponding method element, otherwise, it
+ // will become a kotlin property.
+ if ((typeElement as KspTypeElement).declaration
+ .getConstructors()
+ .single().parameters
+ .isNotEmpty()) {
+ it.isKotlinPropertyMethod()
+ } else {
+ it.isAbstract()
+ }
+ }.forEach {
+ put(it.name, it.returnType)
+ put(it.jvmName, it.returnType)
+ }
+ }
+ }
+
override fun <T : Annotation> asAnnotationBox(annotationClass: Class<T>): XAnnotationBox<T> {
return KspAnnotationBox(
env = env,
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
index 2953253..71d5c12 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
@@ -708,6 +708,20 @@
}.forEach { typeElement ->
val annotation = typeElement.requireAnnotation<JavaAnnotationWithDefaults>()
+ assertThat(annotation.defaultValues.map { it.name })
+ .containsExactly(
+ "stringVal",
+ "stringArrayVal",
+ "typeVal",
+ "typeArrayVal",
+ "intVal",
+ "intArrayVal",
+ "enumVal",
+ "enumArrayVal",
+ "otherAnnotationVal",
+ "otherAnnotationArrayVal"
+ ).inOrder()
+
assertThat(annotation.get<Int>("intVal"))
.isEqualTo(3)
assertThat(annotation.get<List<Int>>("intArrayVal"))