Skip to content

Commit 218c162

Browse files
rossbacherAndreas Rossbacher
and
Andreas Rossbacher
authored
Add support for KSP (#323)
* Rename .java to .kt * Convert processor ot Kotlin * Rename .java to .kt * Convert all processor tests to Kotlin and use com.github.tschuchortdev:kotlin-compile-testing for testing. Moved all tests over and make them more meaningful by testing what ends up in the index instad of just 1:1 ow which code they generate) which with the index bing binary is unverifiable. * Cleanup * Kotlin conversion cleanup and segmentation. * First step of ksp conversion * First step of ksp conversion * Fix delegate and index generation * Cleanup * Moved all tests to mockk Removed old unused dependencies Check generated source on top of functionality Split method and class elements into two sets for processing Fixed index generation for inner classes Added processor test with inner class Enabled ksp for sample project * Fix originating elements for Delegate generation. Fix originalting elment for Registry generation. Made unit test when running via ksp not to compiled code check. * Use | for separator of options * Fix argument and disable kapt plugin * Remove no unused jcenter Fix warning Updated gradle to 7.1 * Add Kapt test library to show setup for kapt. Clean up gralde plugin dependency for ksp. Updated documentation. * Use public version of xProcessorVersion Remove airbnb repo dependency * Add ktlint plugin and clean up the processor. Also add ktlint to ci checks. * Better error message match. * When running ksp allow the incremental flag to not be set and still get the custom processors from config. Use testKsp to test that behavior. * Cleanup. * Typos * Cleanup and Pr comments. * Rename .java to .kt * Made DeepLinkAnnotatedElement a sealed class Adde Kotlin source base tests. Cleanup/fixes * Enable failing tests * Kotlin conversion * Make sure to generate java source files in correct package like it is done for room (mentioned here tschuchortdev/kotlin-compile-testing#105 (comment)) but this also does not work. Disabled ksp test for inner classes in java because of tschuchortdev/kotlin-compile-testing#105 * Add missing import Add Kotlin based module * Add note about Kotlin source files when using KSP. * Remove note about kapt/ksp coexistance. Co-authored-by: Andreas Rossbacher <[email protected]>
1 parent cfaafa7 commit 218c162

File tree

53 files changed

+3214
-1897
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3214
-1897
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ branches:
2323
notifications:
2424
email: false
2525

26-
script: ./gradlew assemble check
26+
script: ./gradlew assemble check lintKotlin
2727

2828
sudo: false
2929

README.md

+102-6
Original file line numberDiff line numberDiff line change
@@ -292,16 +292,93 @@ which saves you from defining a lot prefixes.
292292

293293
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)
294294
):
295+
```groovy
296+
dependencies {
297+
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
298+
}
299+
```
300+
301+
DeeplinkDispatch supports three ways to run the annotation processor dependin on which one you choose
302+
the setup is slightly different.
303+
304+
### KSP
305+
306+
When using Kotlin we strongly suggest to use KSP as it can bring major speed improvements.
307+
308+
To run the processor via KSP you first have to apply the KSP plugin. Add the dependency to the
309+
`build.gradle` file of your main project:
310+
311+
```groovy
312+
buildscript {
313+
314+
apply from: rootProject.file("dependencies.gradle")
315+
316+
repositories {
317+
google()
318+
gradlePluginPortal()
319+
}
320+
dependencies {
321+
classpath "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:<ksp-version>"
322+
}
323+
}
324+
```
325+
326+
Apply the plugin in the `build.gradle` file of the project you want to use it:
327+
328+
```groovy
329+
plugins {
330+
id("com.google.devtools.ksp")
331+
}
332+
```
333+
334+
and don't forget the dependency to the annotation procesor and DeepLinkDispatch itself:
335+
336+
```groovy
337+
dependencies {
338+
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
339+
ksp 'com.airbnb:deeplinkdispatch-processor:x.x.x'
340+
}
341+
```
342+
343+
**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!
344+
345+
As an example the main `sample` app is set up using KSP.
346+
347+
### Kapt
348+
349+
If your project is already setup for Kotlin the only thing you have to add is the plugin:
350+
351+
```groovy
352+
plugins {
353+
id("kotlin-kapt")
354+
}
355+
```
356+
357+
and don't forget the dependency to the annotation procesor and DeepLinkDispatch itself:
358+
359+
```groovy
360+
dependencies {
361+
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
362+
kapt 'com.airbnb:deeplinkdispatch-processor:x.x.x'
363+
}
364+
```
365+
366+
As an example the `sample-kapt-library` is set up using Kapt
367+
368+
### Java annotation processor
369+
370+
Just add the dependency to DeepLinkDispatch and to the annotation processor:
371+
295372
```groovy
296373
dependencies {
297374
implementation 'com.airbnb:deeplinkdispatch:x.x.x'
298375
annotationProcessor 'com.airbnb:deeplinkdispatch-processor:x.x.x'
299376
}
300377
```
301378

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

304-
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.
381+
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.
305382

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

388465
### Incremental annotation processing
389466

390-
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.
467+
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.
391468

392469
Examples of this configuration are as follows:
393470

@@ -397,7 +474,7 @@ javaCompileOptions {
397474
annotationProcessorOptions {
398475
arguments = [
399476
'deepLink.incremental': 'true',
400-
'deepLink.customAnnotations': 'com.airbnb.AppDeepLink,com.airbnb.WebDeepLink'
477+
'deepLink.customAnnotations': 'com.airbnb.AppDeepLink|com.airbnb.WebDeepLink'
401478
]
402479
}
403480
}
@@ -408,11 +485,23 @@ javaCompileOptions {
408485
kapt {
409486
arguments {
410487
arg("deepLink.incremental", "true")
411-
arg("deepLink.customAnnotations", "com.airbnb.AppDeepLink,com.airbnb.WebDeepLink")
488+
arg("deepLink.customAnnotations", "com.airbnb.AppDeepLink|com.airbnb.WebDeepLink")
412489
}
413490
}
414491
```
415492

493+
**KSP**
494+
495+
KSP is always incremental and you always have to provide the list of `deepLink.customAnnotation` if
496+
you have any or they will not be processed.
497+
498+
```groovy
499+
ksp {
500+
arg("deepLink.incremental", "true")
501+
arg("deepLink.customAnnotations", "com.airbnb.AppDeepLink|com.airbnb.WebDeepLink")
502+
}
503+
```
504+
416505
### Performance
417506

418507
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.
@@ -457,7 +546,7 @@ tasks.withType(JavaCompile) {
457546
}
458547
```
459548

460-
If you are using Kotlin this is how you can enable it for kapt
549+
When using Kotlin Kapt
461550
```groovy
462551
kapt {
463552
arguments {
@@ -466,6 +555,13 @@ kapt {
466555
}
467556
```
468557

558+
and if you are using KSP
559+
```groovy
560+
kapt {
561+
arg("deepLinkDoc.output", "${buildDir}/doc/deeplinks.txt")
562+
}
563+
```
564+
469565
The documentation will be generated in the following format:
470566
```
471567
* {DeepLink1}\n|#|\n[Description part of javadoc]\n|#|\n{ClassName}#[MethodName]\n|##|\n

build.gradle

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ buildscript {
77
repositories {
88
google()
99
mavenCentral()
10-
jcenter() // Still needed for some old dependencies
10+
gradlePluginPortal()
1111
maven { url "https://oss.sonatype.org/service/local/repositories/snapshots/content/" }
1212
}
1313
dependencies {
@@ -17,6 +17,8 @@ buildscript {
1717
classpath deps.benchmarkGradlePlugin
1818
// Dokka is needed on classpath for vanniktech publish plugin
1919
classpath deps.dokkaPlugin
20+
classpath deps.kspGradlePlugin
21+
classpath deps.ktlintGradlePlugin
2022
}
2123
}
2224

@@ -26,7 +28,6 @@ allprojects {
2628
repositories {
2729
google()
2830
mavenCentral()
29-
jcenter() // Still needed for some old dependencies
3031
}
3132
}
3233

deeplinkdispatch-base/src/main/java/com/airbnb/deeplinkdispatch/DeepLinkEntry.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,6 @@ data class DeepLinkEntry(
103103
}
104104

105105
override fun toString(): String {
106-
return "uriTemplate: $uriTemplate activity: ${activityClass.name} method: $method"
106+
return "uriTemplate: $uriTemplate className: $className method: $method"
107107
}
108108
}

deeplinkdispatch-base/src/main/java/com/airbnb/deeplinkdispatch/DeepLinkSpec.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@
4444
// are not so we need to mark them as RetentionPolicy.RUNTIME.
4545
@Retention(RetentionPolicy.RUNTIME)
4646
public @interface DeepLinkSpec {
47-
String[] prefix();
47+
String[] prefix();
4848
}

deeplinkdispatch-processor/build.gradle

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
apply plugin: 'java'
22
apply plugin: 'kotlin'
3+
apply plugin: 'org.jmailen.kotlinter'
34

45
sourceCompatibility = 1.8
56

@@ -11,8 +12,9 @@ dependencies {
1112
implementation deps.jsr305
1213
implementation deps.kotlinStdLib
1314
implementation deps.javaPoet
14-
implementation deps.autoCommon
1515
implementation deps.androidXAnnotations
16+
implementation deps.ksp
17+
implementation deps.xProcessor
1618

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

@@ -31,3 +34,11 @@ checkstyle {
3134
showViolations true
3235
configProperties = ['checkstyle.cache.file': rootProject.file('build/checkstyle.cache')]
3336
}
37+
38+
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
39+
kotlinOptions {
40+
jvmTarget = "1.8"
41+
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
42+
freeCompilerArgs += "-Xopt-in=androidx.room.compiler.processing.ExperimentalProcessingApi"
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.airbnb.deeplinkdispatch
2+
3+
import androidx.room.compiler.processing.XProcessingEnv
4+
import androidx.room.compiler.processing.XRoundEnv
5+
import androidx.room.compiler.processing.XTypeElement
6+
import androidx.room.compiler.processing.compat.XConverters.toXProcessing
7+
import com.google.devtools.ksp.processing.Resolver
8+
import com.google.devtools.ksp.processing.SymbolProcessor
9+
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
10+
import com.google.devtools.ksp.symbol.KSAnnotated
11+
import javax.annotation.processing.AbstractProcessor
12+
import javax.annotation.processing.ProcessingEnvironment
13+
import javax.annotation.processing.RoundEnvironment
14+
import javax.lang.model.SourceVersion
15+
import javax.lang.model.element.TypeElement
16+
17+
/**
18+
* Creates a unified abstraction for processors of both KSP and java annotation processing.
19+
*/
20+
abstract class BaseProcessor(val symbolProcessorEnvironment: SymbolProcessorEnvironment?) :
21+
AbstractProcessor(),
22+
SymbolProcessor {
23+
24+
lateinit var environment: XProcessingEnv
25+
private set
26+
27+
override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.RELEASE_8
28+
29+
final override fun init(processingEnv: ProcessingEnvironment) {
30+
super<AbstractProcessor>.init(processingEnv)
31+
environment = XProcessingEnv.create(processingEnv)
32+
}
33+
34+
final override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
35+
if (roundEnv.errorRaised()) {
36+
onError()
37+
}
38+
39+
process(annotations.map { it.toXProcessing(environment) }.toSet(), environment, XRoundEnv.create(environment, roundEnv))
40+
41+
if (roundEnv.processingOver()) {
42+
finish()
43+
}
44+
45+
return false
46+
}
47+
48+
final override fun process(resolver: Resolver): List<KSAnnotated> {
49+
val symbolProcessorEnvironment = requireNotNull(symbolProcessorEnvironment)
50+
environment = XProcessingEnv.create(
51+
symbolProcessorEnvironment.options,
52+
resolver,
53+
symbolProcessorEnvironment.codeGenerator,
54+
symbolProcessorEnvironment.logger
55+
)
56+
process(null, environment, XRoundEnv.create(environment))
57+
return emptyList()
58+
}
59+
60+
abstract fun process(
61+
annotations: Set<XTypeElement>?,
62+
environment: XProcessingEnv,
63+
round: XRoundEnv
64+
)
65+
}

deeplinkdispatch-processor/src/main/java/com/airbnb/deeplinkdispatch/DeepLinkAnnotatedElement.java

-68
This file was deleted.

0 commit comments

Comments
 (0)