Skip to content

Commit

Permalink
support ksp
Browse files Browse the repository at this point in the history
  • Loading branch information
v.lantratov committed Sep 15, 2022
1 parent 766dcaa commit 19e09ec
Show file tree
Hide file tree
Showing 14 changed files with 363 additions and 142 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ buildscript {
classpath(Dependencies.androidPlugin)
classpath(Dependencies.kotlinPlugin)
classpath(Dependencies.dokkaPlugin)
classpath(Dependencies.kspPlugin)
}
}

Expand Down
7 changes: 7 additions & 0 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ object Versions {
const val targetSdk = 30

const val kotlin = "1.5.30"
const val kotlinSymbolProcessingApi = "1.5.30-1.0.0"
const val androidTools = "7.0.2"

const val kspPlugin = "1.5.30-1.0.0"

const val coroutines = "1.5.2"

const val androidxCore = "1.6.0"
Expand Down Expand Up @@ -57,6 +60,7 @@ object Dependencies {
const val kotlinPlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}"
const val androidPlugin = "com.android.tools.build:gradle:${Versions.androidTools}"
const val dokkaPlugin = "org.jetbrains.dokka:dokka-gradle-plugin:${Versions.kotlin}"
const val kspPlugin = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:${Versions.kspPlugin}"

const val kotlinReflect = "org.jetbrains.kotlin:kotlin-reflect:${Versions.kotlin}"

Expand All @@ -76,6 +80,9 @@ object Dependencies {
const val agConnectRemoteConfig = "com.huawei.agconnect:agconnect-remoteconfig:${Versions.agConnectRemoteConfig}"

const val kotlinpoet = "com.squareup:kotlinpoet:${Versions.kotlinpoet}"
const val kotlinpoetKsp = "com.squareup:kotlinpoet-ksp:${Versions.kotlinpoet}"

const val kotlinSymbolProcessingApi = "com.google.devtools.ksp:symbol-processing-api:${Versions.kotlinSymbolProcessingApi}"

const val junit = "junit:junit:${Versions.junit}"
const val mockito = "org.mockito:mockito-core:${Versions.mockito}"
Expand Down
2 changes: 2 additions & 0 deletions compiler/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ tasks.withType<KotlinCompile> {
dependencies {
api(project(":core"))
implementation(Dependencies.kotlinpoet)
implementation(Dependencies.kotlinpoetKsp)
implementation(Dependencies.kotlinSymbolProcessingApi)
}

setupJavaLibraryPublishing()
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package com.qiwi.featuretoggle.compiler

import com.qiwi.featuretoggle.annotation.Factory
import com.qiwi.featuretoggle.annotation.FeatureFlag
import com.qiwi.featuretoggle.compiler.generate.createFeatureFactoryRegistryFileSpec
import com.qiwi.featuretoggle.factory.FeatureFactory
import com.qiwi.featuretoggle.registry.FeatureFactoryRegistry
import com.squareup.kotlinpoet.*
Expand All @@ -39,19 +40,6 @@ import javax.lang.model.type.DeclaredType
*/
class FeatureFactoryRegistryProcessor: AbstractProcessor() {

companion object {

/**
* Package name where generated implementation of [FeatureFactoryRegistry] will be placed.
*/
const val GENERATED_PACKAGE_NAME = "com.qiwi.featuretoggle.registry"

/**
* Name for generated implementation of [FeatureFactoryRegistry].
*/
const val GENERATED_CLASS_NAME = "FeatureFactoryRegistryGenerated"
}

override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported()

override fun getSupportedAnnotationTypes(): Set<String> = setOf(Factory::class.java.canonicalName)
Expand All @@ -73,53 +61,10 @@ class FeatureFactoryRegistryProcessor: AbstractProcessor() {
featureClass to Pair(featureKey, featureFactoryClass)
}.toMap().toSortedMap()
if(featureFactoryMap.isNotEmpty()) {
createFeatureFactoryRegistry(featureFactoryMap)
createFeatureFactoryRegistryFileSpec(featureFactoryMap)
.writeTo(processingEnv.filer)
}
return false
}

private fun createFeatureFactoryRegistry(featureFactoryMap: Map<ClassName, Pair<String, ClassName>>) {
val factoryMapType = MAP.parameterizedBy(
Class::class.asTypeName().parameterizedBy(WildcardTypeName.producerOf(Any::class)),
Pair::class.asTypeName().parameterizedBy(
String::class.asTypeName(), Class::class.asTypeName().parameterizedBy(
WildcardTypeName.producerOf(Any::class)
)
)
)
val registry = TypeSpec.classBuilder(GENERATED_CLASS_NAME)
.addSuperinterface(FeatureFactoryRegistry::class)
.addProperty(
PropertySpec.builder("factoryMap", factoryMapType, KModifier.PRIVATE)
.initializer(getFactoryMapInitializer(featureFactoryMap))
.build())
.addFunction(
FunSpec.builder("getFactoryMap")
.addModifiers(KModifier.OVERRIDE)
.returns(factoryMapType)
.addCode(
CodeBlock.Builder()
.addStatement("return factoryMap")
.build())
.build())
.build()
FileSpec.builder(GENERATED_PACKAGE_NAME, GENERATED_CLASS_NAME)
.addType(registry)
.build()
.writeTo(processingEnv.filer)
}

private fun getFactoryMapInitializer(featureFactoryMap: Map<ClassName, Pair<String, ClassName>>): CodeBlock {
val builder = CodeBlock.Builder().addStatement("mapOf(")
featureFactoryMap.entries.forEachIndexed { index, entry ->
val featureClassName = entry.key
val featureKey = entry.value.first
val featureFactoryClassName = entry.value.second
val endOfStatement = if(index == featureFactoryMap.size-1) "" else ","
builder.addStatement("%T::class.java to Pair(%S, %T::class.java)$endOfStatement", featureClassName, featureKey, featureFactoryClassName)
}
return builder
.addStatement(")")
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package com.qiwi.featuretoggle.compiler

import com.qiwi.featuretoggle.annotation.FeatureFlag
import com.qiwi.featuretoggle.compiler.generate.createFeatureFlagRegistryFileSpec
import com.qiwi.featuretoggle.registry.FeatureFlagRegistry
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
Expand All @@ -36,19 +37,6 @@ import javax.lang.model.element.TypeElement
*/
class FeatureFlagRegistryProcessor: AbstractProcessor() {

companion object {

/**
* Package name where generated implementation of [FeatureFlagRegistry] will be placed.
*/
const val GENERATED_PACKAGE_NAME = "com.qiwi.featuretoggle.registry"

/**
* Name for generated implementation of [FeatureFlagRegistry].
*/
const val GENERATED_CLASS_NAME = "FeatureFlagRegistryGenerated"
}

override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latestSupported()

override fun getSupportedAnnotationTypes(): Set<String> = setOf(FeatureFlag::class.java.canonicalName)
Expand All @@ -68,78 +56,10 @@ class FeatureFlagRegistryProcessor: AbstractProcessor() {
}.toMap().toSortedMap()
if(featureFlagMap.isNotEmpty()) {
val featureKeyMap = featureFlagMap.entries.associateBy({ it.value }) { it.key }.toSortedMap()
createFeatureFlagRegistry(featureFlagMap, featureKeyMap)
createFeatureFlagRegistryFileSpec(featureFlagMap, featureKeyMap)
.writeTo(processingEnv.filer)
}
return false
}

private fun createFeatureFlagRegistry(featureFlagsMap: Map<String, ClassName>, featureKeysMap: Map<ClassName, String>) {
val flagsMapType = MAP.parameterizedBy(
String::class.asTypeName(),
Class::class.asTypeName().parameterizedBy(WildcardTypeName.producerOf(Any::class))
)
val keysMapType = MAP.parameterizedBy(
Class::class.asTypeName().parameterizedBy(WildcardTypeName.producerOf(Any::class)),
String::class.asTypeName()
)
val registry = TypeSpec.classBuilder(GENERATED_CLASS_NAME)
.addSuperinterface(FeatureFlagRegistry::class)
.addProperty(
PropertySpec.builder("flagsMap", flagsMapType, KModifier.PRIVATE)
.initializer(getFlagsMapInitializer(featureFlagsMap))
.build())
.addProperty(
PropertySpec.builder("keysMap", keysMapType, KModifier.PRIVATE)
.initializer(getKeysMapInitializer(featureKeysMap))
.build())
.addFunction(
FunSpec.builder("getFeatureFlagsMap")
.addModifiers(KModifier.OVERRIDE)
.returns(flagsMapType)
.addCode(
CodeBlock.Builder()
.addStatement("return flagsMap")
.build())
.build())
.addFunction(
FunSpec.builder("getFeatureKeysMap")
.addModifiers(KModifier.OVERRIDE)
.returns(keysMapType)
.addCode(
CodeBlock.Builder()
.addStatement("return keysMap")
.build())
.build())
.build()
FileSpec.builder(GENERATED_PACKAGE_NAME, GENERATED_CLASS_NAME)
.addType(registry)
.build()
.writeTo(processingEnv.filer)
}

private fun getFlagsMapInitializer(featureFlagMap: Map<String, ClassName>): CodeBlock {
val builder = CodeBlock.Builder().addStatement("mapOf(")
featureFlagMap.entries.forEachIndexed { index, entry ->
val key = entry.key
val className = entry.value
val endOfStatement = if(index == featureFlagMap.size-1) "" else ","
builder.addStatement("%S to %T::class.java$endOfStatement", key, className)
}
return builder
.addStatement(")")
.build()
}

private fun getKeysMapInitializer(featureKeysMap: Map<ClassName, String>): CodeBlock {
val builder = CodeBlock.Builder().addStatement("mapOf(")
featureKeysMap.entries.forEachIndexed { index, entry ->
val className = entry.key
val key = entry.value
val endOfStatement = if(index == featureKeysMap.size-1) "" else ","
builder.addStatement("%T::class.java to %S$endOfStatement", className, key)
}
return builder
.addStatement(")")
.build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.qiwi.featuretoggle.compiler.generate

import com.qiwi.featuretoggle.registry.FeatureFactoryRegistry
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.MAP
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.WildcardTypeName
import com.squareup.kotlinpoet.asTypeName

/**
* Package name where generated implementation of [FeatureFactoryRegistry] will be placed.
*/
private const val GENERATED_PACKAGE_NAME = "com.qiwi.featuretoggle.registry"

/**
* Name for generated implementation of [FeatureFactoryRegistry].
*/
private const val GENERATED_CLASS_NAME = "FeatureFactoryRegistryGenerated"

fun createFeatureFactoryRegistryFileSpec(featureFactoryMap: Map<ClassName, Pair<String, ClassName>>): FileSpec {
val factoryMapType = MAP.parameterizedBy(
Class::class.asTypeName().parameterizedBy(WildcardTypeName.producerOf(Any::class)),
Pair::class.asTypeName().parameterizedBy(
String::class.asTypeName(), Class::class.asTypeName().parameterizedBy(
WildcardTypeName.producerOf(Any::class)
)
)
)
val registry = TypeSpec.classBuilder(GENERATED_CLASS_NAME)
.addSuperinterface(FeatureFactoryRegistry::class)
.addProperty(
PropertySpec.builder("factoryMap", factoryMapType, KModifier.PRIVATE)
.initializer(getFactoryMapInitializer(featureFactoryMap))
.build()
)
.addFunction(
FunSpec.builder("getFactoryMap")
.addModifiers(KModifier.OVERRIDE)
.returns(factoryMapType)
.addCode(
CodeBlock.Builder()
.addStatement("return factoryMap")
.build()
)
.build()
)
.build()
return FileSpec.builder(GENERATED_PACKAGE_NAME, GENERATED_CLASS_NAME)
.addType(registry)
.build()
}

private fun getFactoryMapInitializer(featureFactoryMap: Map<ClassName, Pair<String, ClassName>>): CodeBlock {
val builder = CodeBlock.Builder().addStatement("mapOf(")
featureFactoryMap.entries.forEachIndexed { index, entry ->
val featureClassName = entry.key
val featureKey = entry.value.first
val featureFactoryClassName = entry.value.second
val endOfStatement = if (index == featureFactoryMap.size - 1) "" else ","
builder.addStatement(
"%T::class.java to Pair(%S, %T::class.java)$endOfStatement",
featureClassName,
featureKey,
featureFactoryClassName
)
}
return builder
.addStatement(")")
.build()
}

0 comments on commit 19e09ec

Please sign in to comment.