in sample/plugins-compiler/plugins-compiler/kotlin/src/main/kotlin/com/uber/crumb/sample/pluginscompiler/PluginsCompiler.kt [84:179]
override fun consume(context: CrumbContext,
type: TypeElement,
annotations: Collection<AnnotationMirror>,
metadata: Set<ConsumerMetadata>) {
// Must be a type that supports extension values
if (type.kind != CLASS) {
context.processingEnv
.messager
.printMessage(ERROR,
"@${PluginPoint::class.java.simpleName} is only applicable on classes when consuming!",
type)
return
}
val kmetadata = type.kotlinMetadata
if (kmetadata == null
&& type.annotationMirrors.any {
MoreElements.asType(it.annotationType.asElement()).qualifiedName.toString() == METADATA_FQCN
}) {
context.processingEnv
.messager
.printMessage(ERROR,
"Metadata annotation was unreadable on $type. Please ensure the kotlin standard library is a " +
"dependency of this project.",
type)
return
}
if (kmetadata !is KotlinClassMetadata) {
context.processingEnv
.messager
.printMessage(ERROR,
"@${PluginPoint::class.java.simpleName} can't be applied to $type: must be a class.",
type)
return
}
val classData = kmetadata.data
val (nameResolver, classProto) = classData
// Must be an object class.
if (classProto.classKind != ProtoBuf.Class.Kind.OBJECT) {
context.processingEnv
.messager
.printMessage(ERROR,
"@${PluginPoint::class.java.simpleName} can't be applied to $type: must be a Kotlin object class",
type)
return
}
val packageName = nameResolver.getString(classProto.fqName)
.substringBeforeLast('/')
.replace('/', '.')
// Read the pluginpoint's target type, e.g. "MyPluginInterface"
val pluginPoint = type.getAnnotation(PluginPoint::class.java)
val targetPlugin: TypeMirror = try {
pluginPoint.value
throw IllegalStateException("This shouldn't actually happen")
} catch (e: MirroredTypesException) {
e.typeMirrors[0]
}
// List of plugin TypeElements
val pluginClasses = metadata
.mapNotNull { it[METADATA_KEY] }
.map { pluginClass -> context.processingEnv.elementUtils.getTypeElement(pluginClass) }
.filter {
context
.processingEnv
.typeUtils
.isAssignable(it.asType(), targetPlugin)
}
.toSet()
val initializerCode = "return setOf(${pluginClasses.joinToString { "%T()" }})"
val initializerValues = pluginClasses
.map { it.asClassName() }
.toTypedArray()
val pluginsFunction = FunSpec.builder("obtain")
.receiver(type.asClassName())
.returns(Set::class.asClassName().parameterizedBy(
targetPlugin.asTypeName()))
.addStatement(initializerCode, *initializerValues)
.build()
// Generate the file
val generatedDir = context.processingEnv.options[kaptGeneratedOption]?.let(::File)
?: throw IllegalStateException("Could not resolve kotlin generated directory!")
FileSpec.builder(packageName, "${type.simpleName}_Plugins")
.addFunction(pluginsFunction)
.build()
.writeTo(generatedDir)
}