Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for KSP #323

Merged
merged 31 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bc3f409
Rename .java to .kt
Jun 15, 2021
01cb043
Convert processor ot Kotlin
Jun 15, 2021
575714a
Rename .java to .kt
Jun 16, 2021
e16e5ba
Convert all processor tests to Kotlin and use com.github.tschuchortde…
Jun 16, 2021
474a00c
Cleanup
Jun 16, 2021
e3e4ed4
Kotlin conversion cleanup and segmentation.
Jun 16, 2021
e56bcb8
First step of ksp conversion
Jun 21, 2021
138ebcc
First step of ksp conversion
Jun 22, 2021
181aa9c
Fix delegate and index generation
Jun 22, 2021
fc2714e
Cleanup
Jun 22, 2021
a8588a5
Moved all tests to mockk
Jun 24, 2021
d828dfc
Fix originating elements for Delegate generation.
Jun 24, 2021
b8a023c
Use | for separator of options
Jun 24, 2021
ec8ee63
Fix argument and disable kapt plugin
Jun 24, 2021
8f3ea81
Remove no unused jcenter
Jun 24, 2021
655a4ad
Add Kapt test library to show setup for kapt.
Jun 24, 2021
a21fda2
Use public version of xProcessorVersion
Jun 25, 2021
d01619e
Add ktlint plugin and clean up the processor.
Jun 25, 2021
9149fe6
Better error message match.
Jun 25, 2021
cda0540
When running ksp allow the incremental flag to not be set and still g…
Jun 25, 2021
0adc53a
Cleanup.
Jun 25, 2021
b2f9223
Typos
Jun 25, 2021
a106b85
Cleanup and Pr comments.
Jun 26, 2021
feea144
Rename .java to .kt
Jun 29, 2021
cbfa593
Made DeepLinkAnnotatedElement a sealed class
Jun 29, 2021
3df985c
Enable failing tests
Jun 29, 2021
1733fcd
Kotlin conversion
Jun 29, 2021
872847d
Make sure to generate java source files in correct package like it is…
Jun 29, 2021
c36b3af
Add missing import
Jun 29, 2021
e9e792d
Add note about Kotlin source files when using KSP.
Jun 29, 2021
87f5348
Remove note about kapt/ksp coexistance.
Jun 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ branches:
notifications:
email: false

script: ./gradlew assemble check
script: ./gradlew assemble check lintKotlin
rossbacher marked this conversation as resolved.
Show resolved Hide resolved

sudo: false

Expand Down
108 changes: 102 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,16 +292,93 @@ which saves you from defining a lot prefixes.

Add to your project `build.gradle` file (Latest version is [![DeeplinkDispatch version](https://badge.fury.io/gh/airbnb%2FDeepLinkDispatch.svg)](https://badge.fury.io/gh/airbnb%2FDeepLinkDispatch)
):
```groovy
dependencies {
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
}
```

DeeplinkDispatch supports three ways to run the annotation processor dependin on which one you choose
the setup is slightly different.

### KSP

When using Kotlin we strongly suggest to use KSP as it can bring major speed improvements.
rossbacher marked this conversation as resolved.
Show resolved Hide resolved

To run the processor via KSP you first have to apply the KSP plugin. Add the dependency to the
`build.gradle` file of your main project:

```groovy
buildscript {

apply from: rootProject.file("dependencies.gradle")

repositories {
google()
gradlePluginPortal()
}
dependencies {
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:<ksp-version>"
}
}
```

Apply the plugin in the `build.gradle` file of the project you want to use it:

```groovy
plugins {
id("com.google.devtools.ksp")
}
```

and don't forget the dependency to the annotation procesor and DeepLinkDispatch itself:

```groovy
dependencies {
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
ksp 'com.airbnb:deeplinkdispatch-processor:x.x.x'
}
```

**Note:** When using KSP (you have `ksp 'com.airbnb:deeplinkdispatch-processor:x.x.x'` in your dependencies) at least one Kotlin source file *must* be present in the project or no output will be generated!

As an example the main `sample` app is set up using KSP.

### Kapt

If your project is already setup for Kotlin the only thing you have to add is the plugin:

```groovy
plugins {
id("kotlin-kapt")
}
```

and don't forget the dependency to the annotation procesor and DeepLinkDispatch itself:

```groovy
dependencies {
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
kapt 'com.airbnb:deeplinkdispatch-processor:x.x.x'
}
```

As an example the `sample-kapt-library` is set up using Kapt

### Java annotation processor

Just add the dependency to DeepLinkDispatch and to the annotation processor:

```groovy
dependencies {
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
annotationProcessor 'com.airbnb:deeplinkdispatch-processor:x.x.x'
}
```

_For **Kotlin** you should use_ `kapt` _instead of_ `annotationProcessor`
As an example the `sample-library` is set up using the Java annotation processor

Create your deep link module(s) (**new on DeepLinkDispatch v3**). For every class you annotate with `@DeepLinkModule`, DeepLinkDispatch will generate a "Registry" class, which contains a registry of all your `@DeepLink` annotations.
When this is done, create your deep link module(s) (**new on DeepLinkDispatch v3**). For every class you annotate with `@DeepLinkModule`, DeepLinkDispatch will generate a "Registry" class, which contains a registry of all your `@DeepLink` annotations.

```java
/** This will generate a AppDeepLinkModuleRegistry class */
Expand Down Expand Up @@ -387,7 +464,7 @@ When upgrading to 5.x+ you may experience some breaking API changes. Read about

### Incremental annotation processing

You must update your build.gradle to opt into incremental annotation processing. When enabled, all custom deep link annotations must be registered in the build.gradle (comma separated), otherwise they will be silently ignored.
You must update your build.gradle to opt into incremental annotation processing. When enabled, all custom deep link annotations must be registered in the build.gradle (pipe (`|`) separated), otherwise they will be silently ignored.
rossbacher marked this conversation as resolved.
Show resolved Hide resolved

Examples of this configuration are as follows:

Expand All @@ -397,7 +474,7 @@ javaCompileOptions {
annotationProcessorOptions {
arguments = [
'deepLink.incremental': 'true',
'deepLink.customAnnotations': 'com.airbnb.AppDeepLink,com.airbnb.WebDeepLink'
'deepLink.customAnnotations': 'com.airbnb.AppDeepLink|com.airbnb.WebDeepLink'
]
}
}
Expand All @@ -408,11 +485,23 @@ javaCompileOptions {
kapt {
arguments {
arg("deepLink.incremental", "true")
arg("deepLink.customAnnotations", "com.airbnb.AppDeepLink,com.airbnb.WebDeepLink")
arg("deepLink.customAnnotations", "com.airbnb.AppDeepLink|com.airbnb.WebDeepLink")
}
}
```

**KSP**

KSP is always incremental and you always have to provide the list of `deepLink.customAnnotation` if
you have any or they will not be processed.

```groovy
ksp {
arg("deepLink.incremental", "true")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you feel about removing the non incremental option? Looking through this PR, it would reduces complexity, and really everyone should want to use incremental.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just wanted to keep it backwards compatible. It would imho not reduce complexity by that much. But it can be on the chopping block if it does not fit with any other major changes.

arg("deepLink.customAnnotations", "com.airbnb.AppDeepLink|com.airbnb.WebDeepLink")
}
```

### Performance

Starting with v5 DeeplinkDispatch is designed to be very fast in resolving deep links even if there are a lot of them. To ensure we do not regress from this benchmark tests using [`androidx.benchmark`](https://developer.android.com/studio/profile/benchmark#top_of_page) were added.
Expand Down Expand Up @@ -457,7 +546,7 @@ tasks.withType(JavaCompile) {
}
```

If you are using Kotlin this is how you can enable it for kapt
When using Kotlin Kapt
```groovy
kapt {
arguments {
Expand All @@ -466,6 +555,13 @@ kapt {
}
```

and if you are using KSP
```groovy
kapt {
arg("deepLinkDoc.output", "${buildDir}/doc/deeplinks.txt")
}
```

The documentation will be generated in the following format:
```
* {DeepLink1}\n|#|\n[Description part of javadoc]\n|#|\n{ClassName}#[MethodName]\n|##|\n
Expand Down
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ buildscript {
repositories {
google()
mavenCentral()
jcenter() // Still needed for some old dependencies
gradlePluginPortal()
maven { url "https://oss.sonatype.org/service/local/repositories/snapshots/content/" }
}
dependencies {
Expand All @@ -17,6 +17,8 @@ buildscript {
classpath deps.benchmarkGradlePlugin
// Dokka is needed on classpath for vanniktech publish plugin
classpath deps.dokkaPlugin
classpath deps.kspGradlePlugin
classpath deps.ktlintGradlePlugin
}
}

Expand All @@ -26,7 +28,6 @@ allprojects {
repositories {
google()
mavenCentral()
jcenter() // Still needed for some old dependencies
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,6 @@ data class DeepLinkEntry(
}

override fun toString(): String {
return "uriTemplate: $uriTemplate activity: ${activityClass.name} method: $method"
return "uriTemplate: $uriTemplate className: $className method: $method"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@
// are not so we need to mark them as RetentionPolicy.RUNTIME.
@Retention(RetentionPolicy.RUNTIME)
public @interface DeepLinkSpec {
String[] prefix();
String[] prefix();
}
17 changes: 14 additions & 3 deletions deeplinkdispatch-processor/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'org.jmailen.kotlinter'

sourceCompatibility = 1.8

Expand All @@ -11,8 +12,9 @@ dependencies {
implementation deps.jsr305
implementation deps.kotlinStdLib
implementation deps.javaPoet
implementation deps.autoCommon
implementation deps.androidXAnnotations
implementation deps.ksp
implementation deps.xProcessor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are you thinking we should handle the fact that xProcessor is still in alpha, and ksp in beta for the public release?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could release a DLD next major version beta.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can drop the feature in the next release For this one it does not make that much sense dropping it as itis all working already. And yes this tests incremental compilation.


testImplementation deps.junit
testImplementation deps.assertJ
Expand All @@ -21,8 +23,9 @@ dependencies {
// Cannot depend on them from Maven as they are .aar and not .jar files (this is a java project)
testImplementation fileTree(dir: 'libs', include: ['androidx.localbroadcastmanager-1.0.0-beta1.jar','androidx.core-1.0.0-beta1.jar'])
testImplementation deps.compileTesting
testImplementation deps.truth
testImplementation deps.mockito
testImplementation deps.compileTestingKsp
testImplementation deps.mockk
testImplementation deps.kotlinReflect
testImplementation files("${System.properties['java.home']}/../lib/tools.jar")
}

Expand All @@ -31,3 +34,11 @@ checkstyle {
showViolations true
configProperties = ['checkstyle.cache.file': rootProject.file('build/checkstyle.cache')]
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-Xopt-in=androidx.room.compiler.processing.ExperimentalProcessingApi"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.airbnb.deeplinkdispatch

import androidx.room.compiler.processing.XProcessingEnv
import androidx.room.compiler.processing.XRoundEnv
import androidx.room.compiler.processing.XTypeElement
import androidx.room.compiler.processing.compat.XConverters.toXProcessing
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.symbol.KSAnnotated
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.SourceVersion
import javax.lang.model.element.TypeElement

/**
* Creates a unified abstraction for processors of both KSP and java annotation processing.
*/
abstract class BaseProcessor(val symbolProcessorEnvironment: SymbolProcessorEnvironment?) :
AbstractProcessor(),
SymbolProcessor {

lateinit var environment: XProcessingEnv
private set

override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.RELEASE_8

final override fun init(processingEnv: ProcessingEnvironment) {
super<AbstractProcessor>.init(processingEnv)
environment = XProcessingEnv.create(processingEnv)
}

final override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
if (roundEnv.errorRaised()) {
rossbacher marked this conversation as resolved.
Show resolved Hide resolved
onError()
}

process(annotations.map { it.toXProcessing(environment) }.toSet(), environment, XRoundEnv.create(environment, roundEnv))

if (roundEnv.processingOver()) {
finish()
}

return false
}

final override fun process(resolver: Resolver): List<KSAnnotated> {
val symbolProcessorEnvironment = requireNotNull(symbolProcessorEnvironment)
environment = XProcessingEnv.create(
symbolProcessorEnvironment.options,
resolver,
symbolProcessorEnvironment.codeGenerator,
symbolProcessorEnvironment.logger
)
process(null, environment, XRoundEnv.create(environment))
return emptyList()
}

abstract fun process(
annotations: Set<XTypeElement>?,
environment: XProcessingEnv,
round: XRoundEnv
)
}

This file was deleted.

Loading