5.0.0-beta02
This adds support for Kotlin Symbol Processing, while maintaining backwards compatibility with java annotation processing via the xprocessing library from Room. Note that compilation speed with epoxy in KSP is not yet faster than KAPT due to some optimizations that remain to be made, but those should be made before long.
This includes a major version bump to 5.0.0 because there may be slight behavior differences with KSP, especially for generic types in generated code. For example, if you previously had an epoxy attribute in java source code with a raw type it may now appear in the generated code with a wildcard type, which may require tweaking the type that is passed to the model.
Additionally, some type checking was improved, for example more accurate validation of proper equals and hashcode implementations.
To use Epoxy with KSP, simply apply it with the ksp gradle plugin instead of kapt (https://github.com/google/ksp/blob/main/docs/quickstart.md). See the new epoxy-kspsample module for an example.
Note that unfortunately the databinding processor does NOT support KSP, simply because Android databinding itself uses KAPT and KSP cannot currently depend on KAPT sources. The code changes are in place to enable KSP with databinding once the databinding plugin from Android supports KSP (although this is unlikely) - alternatively it may be possible to configure the KSP plugin to run after KAPT and depend on its outputs (you're on your own if you want to try that).
Also, parallel processing support was removed because it is not compatible with KSP.
KSP Generated Sources in IDE
Note, that as of the current KSP version generated java sources are detected by the IDE but NOT generated kotlin sources. This means that generated epoxy kotlin extensions will not automatically be resolved in the IDE. You must manually configure your source sets to include ksp generated folders.
You can add this to your root build.gradle file to work around this
subprojects { project ->
afterEvaluate {
if (project.hasProperty("android")) {
android {
if (it instanceof com.android.build.gradle.LibraryExtension) {
libraryVariants.all { variant ->
def outputFolder = new File("build/generated/ksp/${variant.name}/kotlin")
variant.addJavaSourceFoldersToModel(outputFolder)
android.sourceSets.getAt(variant.name).java {
srcDir(outputFolder)
}
}
} else if (it instanceof com.android.build.gradle.AppExtension) {
applicationVariants.all { variant ->
def outputFolder = new File("build/generated/ksp/${variant.name}/kotlin")
variant.addJavaSourceFoldersToModel(outputFolder)
android.sourceSets.getAt(variant.name).java {
srcDir(outputFolder)
}
}
}
}
}
}
Of if you use kotlin build files you can apply it like this to a project.
private fun Project.registerKspKotlinOutputAsSourceSet() {
afterEvaluate {
val android: BaseExtension by lazy { extensions.findByType(BaseExtension::class.java) }
requireAndroidVariants().forEach { variant ->
val variantName = variant.name
val outputFolder = File("build/generated/ksp/$variantName/kotlin")
variant.addJavaSourceFoldersToModel(outputFolder)
android.sourceSets.getAt(variantName).java {
srcDir(outputFolder)
}
}
}
}
/**
* Return the Android variants for this module, or error if this is not a module with a known Android plugin.
*/
fun Project.requireAndroidVariants(): DomainObjectSet<out BaseVariant> {
return androidVariants() ?: error("no known android extension found for ${project.name}")
}
/**
* Return the Android variants for this module, or null if this is not a module with a known Android plugin.
*/
fun Project.androidVariants(): DomainObjectSet<out BaseVariant>? {
return when (val androidExtension = this.extensions.findByName("android")) {
is LibraryExtension -> {
androidExtension.libraryVariants
}
is AppExtension -> {
androidExtension.applicationVariants
}
else -> null
}
}