Last active
February 19, 2019 14:27
-
-
Save malvinstn/80a68f632d692a6b5f646b0b4051776b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@AutoService(Processor::class) | |
class AnalyticsEventProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils { | |
companion object { | |
private val ANNOTATION = AnalyticsEvent::class.java | |
private const val EVENT_PARAMETER_NAME = "event" | |
private const val EVENT_NAME_PARAMETER_NAME = "name" | |
private const val EVENT_PARAM_PARAMETER_NAME = "params" | |
private const val LOG_EVENT_FUNCTION_NAME = "logEvent" | |
private val EVENT_TRACKER_CLASS = ClassName("com.malvinstn.tracker", "EventTracker") | |
private val BUNDLE_CLASS = ClassName("android.os", "Bundle") | |
private val BUNDLE_OF_FUNCTION = ClassName("androidx.core.os", "bundleOf") | |
} | |
... | |
override fun process( | |
annotations: Set<TypeElement>, | |
roundEnv: RoundEnvironment | |
): Boolean { | |
val outputDir = generatedDir | |
if (outputDir == null) { | |
messager.printMessage( | |
Diagnostic.Kind.ERROR, | |
"Cannot find generated output dir." | |
) | |
return false | |
} | |
// Get all elements that has been annotated with our annotation | |
val annotatedElements = roundEnv.getElementsAnnotatedWith(ANNOTATION) | |
for (annotatedElement in annotatedElements) { | |
// Check if the annotatedElement is a Kotlin sealed class | |
val analyticsElement = getAnalyticsElement(annotatedElement) ?: continue | |
// Get all the declared inner class as our Analytics Event | |
val declaredAnalyticsEvents = getDeclaredAnalyticsEvents(analyticsElement) | |
if (declaredAnalyticsEvents.isEmpty()) { | |
// No declared Analytics Event, skip this class. | |
messager.printMessage( | |
Diagnostic.Kind.WARNING, | |
"$analyticsElement has no valid inner class." | |
) | |
continue | |
} | |
// Generate codes with KotlinPoet | |
generateCode(analyticsElement, declaredAnalyticsEvents, outputDir) | |
} | |
return true | |
} | |
private fun getAnalyticsElement(element: Element): TypeElement? {...} | |
private fun getDeclaredAnalyticsEvents( | |
analyticsElement: TypeElement | |
): Map<ClassName, List<String>> {...} | |
private fun generateCode( | |
analyticsElement: TypeElement, | |
analyticEvents: Map<ClassName, List<String>>, | |
outputDir: File | |
) { | |
val className = analyticsElement.asClassName() | |
val extensionFunSpecBuilder = FunSpec.builder(LOG_EVENT_FUNCTION_NAME) | |
.receiver(EVENT_TRACKER_CLASS) | |
.addParameter(EVENT_PARAMETER_NAME, className) | |
.addStatement("val %L: %T", EVENT_NAME_PARAMETER_NAME, String::class) | |
.addStatement("val %L: %T", EVENT_PARAM_PARAMETER_NAME, BUNDLE_CLASS) | |
.beginControlFlow("when (%L)", EVENT_PARAMETER_NAME) | |
for ((eventName, eventParamList) in analyticEvents) { | |
val codeBlock = CodeBlock.builder() | |
.addStatement("is %T -> {", eventName) | |
.indent() | |
.addStatement( | |
"%L = %S", | |
EVENT_NAME_PARAMETER_NAME, | |
eventName.simpleName.convertCase( | |
CaseFormat.UPPER_CAMEL, | |
CaseFormat.LOWER_UNDERSCORE | |
) | |
) | |
.apply { | |
if (eventParamList.isNotEmpty()) { | |
addStatement("%L = %T(", EVENT_PARAM_PARAMETER_NAME, BUNDLE_OF_FUNCTION) | |
indent() | |
for ((index, parameter) in eventParamList.withIndex()) { | |
val size = eventParamList.size | |
val separator = if (index == size - 1) { "" } else { "," } | |
addStatement( | |
"%S to %L.%L%L", | |
parameter.convertCase( | |
CaseFormat.LOWER_CAMEL, | |
CaseFormat.LOWER_UNDERSCORE | |
), | |
EVENT_PARAMETER_NAME, | |
parameter, | |
separator | |
) | |
} | |
unindent() | |
addStatement(")") | |
} else { | |
addStatement("%L = %T()", EVENT_PARAM_PARAMETER_NAME, BUNDLE_CLASS) | |
} | |
} | |
.unindent() | |
.addStatement("}") | |
.build() | |
extensionFunSpecBuilder.addCode(codeBlock) | |
} | |
extensionFunSpecBuilder.endControlFlow() | |
.addStatement( | |
"%L(%L, %L)", | |
LOG_EVENT_FUNCTION_NAME, | |
EVENT_NAME_PARAMETER_NAME, | |
EVENT_PARAM_PARAMETER_NAME | |
) | |
FileSpec.builder(className.packageName, className.simpleName) | |
.addFunction(extensionFunSpecBuilder.build()) | |
.build() | |
.writeTo(outputDir) | |
} | |
} | |
/** | |
* Helper function to convert String case | |
* using guava's [CaseFormat]. | |
*/ | |
private fun String.convertCase( | |
fromCase: CaseFormat, | |
toCase: CaseFormat | |
): String { | |
return fromCase.to(toCase, this) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment