[go: nahoru, domu]

blob: d40c108a03f0a14de21faa3098f31d51bf5f72c9 [file] [log] [blame]
/*
* Copyright 2021 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 androidx.room.compiler.processing
import com.squareup.javapoet.ClassName
/**
* This wraps annotations that may be declared in sources, and thus not representable with a
* compiled type. This is an equivalent to the Java AnnotationMirror API.
*
* Values in the annotation can be accessed via [annotationValues], the [XAnnotation.get] extension
* function, or any of the "getAs*" helper functions.
*
* In comparison, [XAnnotationBox] is used in situations where the annotation class is already
* compiled and can be referenced. This can be converted with [asAnnotationBox] if the annotation
* class is already compiled.
*/
interface XAnnotation {
/**
* The simple name of the annotation class.
*/
val name: String
/**
* The fully qualified name of the annotation class.
* Accessing this forces the type to be resolved.
*/
val qualifiedName: String
/**
* The [XType] representing the annotation class.
*
* Accessing this requires resolving the type, and is thus more expensive that just accessing
* [name].
*/
val type: XType
/**
* The [XTypeElement] representing the annotation class.
*
* Accessing this requires resolving the type, and is thus more expensive that just accessing
* [name].
*/
val typeElement: XTypeElement
// All annotations are represented by XTypeElements, so this should always be non-null.
get() = requireNotNull(type.typeElement)
/**
* The [ClassName] representing the annotation class.
*
* Accessing this requires resolving the type, and is thus more expensive that just accessing
* [name].
*/
val className: ClassName
get() = typeElement.asClassName().java
/** All values declared in the annotation class. */
val annotationValues: List<XAnnotationValue>
/** Returns the value of the given [methodName] as a type reference. */
fun getAsType(methodName: String): XType = getAnnotationValue(methodName).asType()
/** Returns the value of the given [methodName] as a list of type references. */
fun getAsTypeList(methodName: String): List<XType> = getAnnotationValue(methodName).asTypeList()
/** Returns the value of the given [methodName] as another [XAnnotation]. */
fun getAsAnnotation(methodName: String): XAnnotation =
getAnnotationValue(methodName).asAnnotation()
/** Returns the value of the given [methodName] as a list of [XAnnotation]. */
fun getAsAnnotationList(methodName: String): List<XAnnotation> =
getAnnotationValue(methodName).asAnnotationList()
/** Returns the value of the given [methodName] as a [XEnumEntry]. */
fun getAsEnum(methodName: String): XEnumEntry = getAnnotationValue(methodName).asEnum()
/** Returns the value of the given [methodName] as a list of [XEnumEntry]. */
fun getAsEnumList(methodName: String): List<XEnumEntry> =
getAnnotationValue(methodName).asEnumList()
/** Returns the value of the given [methodName] as a [Boolean]. */
fun getAsBoolean(methodName: String): Boolean = getAnnotationValue(methodName).asBoolean()
/** Returns the value of the given [methodName] as a list of [Boolean]. */
fun getAsBooleanList(methodName: String): List<Boolean> =
getAnnotationValue(methodName).asBooleanList()
/** Returns the value of the given [methodName] as a [String]. */
fun getAsString(methodName: String): String = getAnnotationValue(methodName).asString()
/** Returns the value of the given [methodName] as a list of [String]. */
fun getAsStringList(methodName: String): List<String> =
getAnnotationValue(methodName).asStringList()
/** Returns the value of the given [methodName] as a [Int]. */
fun getAsInt(methodName: String): Int = getAnnotationValue(methodName).asInt()
/** Returns the value of the given [methodName] as a list of [Int]. */
fun getAsIntList(methodName: String): List<Int> = getAnnotationValue(methodName).asIntList()
/** Returns the value of the given [methodName] as a [Long]. */
fun getAsLong(methodName: String): Long = getAnnotationValue(methodName).asLong()
/** Returns the value of the given [methodName] as a list of [Long]. */
fun getAsLongList(methodName: String): List<Long> = getAnnotationValue(methodName).asLongList()
/** Returns the value of the given [methodName] as a [Short]. */
fun getAsShort(methodName: String): Short = getAnnotationValue(methodName).asShort()
/** Returns the value of the given [methodName] as a list of [Short]. */
fun getAsShortList(methodName: String): List<Short> =
getAnnotationValue(methodName).asShortList()
/** Returns the value of the given [methodName] as a [Float]. */
fun getAsFloat(methodName: String): Float = getAnnotationValue(methodName).asFloat()
/** Returns the value of the given [methodName] as a list of [Float]. */
fun getAsFloatList(methodName: String): List<Float> =
getAnnotationValue(methodName).asFloatList()
/** Returns the value of the given [methodName] as a [Double]. */
fun getAsDouble(methodName: String): Double = getAnnotationValue(methodName).asDouble()
/** Returns the value of the given [methodName] as a list of [Double]. */
fun getAsDoubleList(methodName: String): List<Double> =
getAnnotationValue(methodName).asDoubleList()
/** Returns the value of the given [methodName] as a [Byte]. */
fun getAsByte(methodName: String): Byte = getAnnotationValue(methodName).asByte()
/** Returns the value of the given [methodName] as a list of [Byte]. */
fun getAsByteList(methodName: String): List<Byte> = getAnnotationValue(methodName).asByteList()
/** Returns the value of the given [methodName] as a list of [Byte]. */
fun getAsAnnotationValueList(methodName: String): List<XAnnotationValue> =
getAnnotationValue(methodName).asAnnotationValueList()
/** Returns the value of the given [methodName] as a [XAnnotationValue]. */
fun getAnnotationValue(methodName: String): XAnnotationValue
}
/**
* Returns the value of the given [methodName], throwing an exception if the method is not
* found or if the given type [T] does not match the actual type.
*
* Note that non primitive types are wrapped by interfaces in order to allow them to be
* represented by the process:
* - "Class" types are represented with [XType]
* - Annotations are represented with [XAnnotation]
* - Enums are represented with [XEnumEntry]
*
* For convenience, wrapper functions are provided for these types, eg [XAnnotation.getAsType]
*/
// TODO: Consider deprecating this method for getAs*() methods
@Suppress("DEPRECATION")
inline fun <reified T> XAnnotation.get(methodName: String): T = get(methodName, T::class.java)
/**
* Returns the value of the given [methodName], throwing an exception if the method is not
* found or if the given type [T] does not match the actual type.
*
* This uses a non-reified type and takes in a Class so it is callable by Java users.
*
* Note that non primitive types are wrapped by interfaces in order to allow them to be
* represented by the process:
* - "Class" types are represented with [XType]
* - Annotations are represented with [XAnnotation]
* - Enums are represented with [XEnumEntry]
*
* For convenience, wrapper functions are provided for these types, eg [XAnnotation.getAsType]
*/
@Deprecated("Use one of the getAs*() methods instead, e.g. getAsBoolean().")
fun <T> XAnnotation.get(methodName: String, clazz: Class<T>): T {
val argument = getAnnotationValue(methodName)
val value = if (argument.hasListValue()) {
// If the argument is for a list, unwrap each item in the list
argument.asAnnotationValueList().map { it.value }
} else {
argument.value
}
if (!clazz.isInstance(value)) {
error("Value of $methodName of type ${value?.javaClass} cannot be cast to $clazz")
}
@Suppress("UNCHECKED_CAST")
return value as T
}
/**
* Get a representation of this [XAnnotation] as a [XAnnotationBox]. This is helpful for converting
* to [XAnnotationBox] after getting annotations with [XAnnotated.getAllAnnotations].
*
* Only possible if the annotation class is available (ie it is in the classpath and not in
* the compiled sources).
*/
inline fun <reified T : Annotation> XAnnotation.asAnnotationBox(): XAnnotationBox<T> {
return (this as InternalXAnnotation).asAnnotationBox(T::class.java)
}