Skip to content
Draft

K2 #371

Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 7 additions & 5 deletions deeplinkdispatch-base/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'org.jmailen.kotlinter'

sourceCompatibility = 11

// apply plugin: 'org.jmailen.kotlinter'
Copy link
Author

Choose a reason for hiding this comment

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

Note to self: revert.

apply plugin: 'checkstyle'
apply from: '../publishing.gradle'
// apply from: '../publishing.gradle'

dependencies {
implementation deps.okio
Expand All @@ -21,3 +18,8 @@ checkstyle {
configProperties = ['checkstyle.cache.file': rootProject.file('build/checkstyle.cache')]
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlin {
jvmToolchain(17)
}
}
15 changes: 7 additions & 8 deletions deeplinkdispatch-processor/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'org.jmailen.kotlinter'

sourceCompatibility = 11

// apply plugin: 'org.jmailen.kotlinter'
apply plugin: 'checkstyle'
apply from: '../publishing.gradle'
// apply from: '../publishing.gradle'

dependencies {
implementation project(':deeplinkdispatch-base')
Expand All @@ -24,7 +21,7 @@ dependencies {
testImplementation deps.compileTesting
testImplementation deps.compileTestingKsp
testImplementation deps.mockk
testImplementation deps.kotlinReflect
testImplementation deps.kotlin.reflect
}

checkstyle {
Expand All @@ -34,9 +31,11 @@ checkstyle {
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlin {
jvmToolchain(17)
}
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-Xopt-in=androidx.room.compiler.processing.ExperimentalProcessingApi"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ abstract class BaseProcessor(val symbolProcessorEnvironment: SymbolProcessorEnvi
abstract fun process(
annotations: Set<XTypeElement>?,
environment: XProcessingEnv,
round: XRoundEnv
round: XRoundEnv,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
} else {
annotations?.filterAnnotatedAnnotations(DeepLinkSpec::class) ?: emptySet()
}

val allDeepLinkAnnotatedElements =
customAnnotations.flatMap { round.getElementsAnnotatedWith(it.qualifiedName) } +
round.getElementsAnnotatedWith(DEEP_LINK_CLASS)
Expand Down Expand Up @@ -178,14 +179,14 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
if (e is DeepLinkProcessorException) {
logError(
element = e.element,
message = e.errorMessage
message = "DeepLinkProcessorException: ${e.errorMessage}"
)
} else {
// if it is an unexpected crash then the cause can get lost by KAPT unless we manually
// catch and print the trace so that it is possible to debug.
logError(
element = null,
message = "${e.javaClass.simpleName}: ${e.localizedMessage}\n${e.stackTraceToString()}"
message = "Unexpected error: ${e.javaClass.simpleName}: ${e.localizedMessage}\n${e.stackTraceToString()}"
)
}
}
Expand Down Expand Up @@ -222,18 +223,21 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
uri = uri,
element = element
)

element is XTypeElement && element.isActivity() ->
DeepLinkAnnotatedElement.ActivityAnnotatedElement(
uri = uri,
element = element
)

element is XTypeElement && element.isHandler() -> {
verifyHandlerMatchArgs(element, uri)
DeepLinkAnnotatedElement.HandlerAnnotatedElement(
uri = uri,
element = element
)
}

else -> error(
"Internal error: Elements can only be 'MethodAnnotatedElement', " +
"'ActivityAnnotatedElement' or 'HandlerAnnotatedElement'"
Expand All @@ -252,10 +256,10 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
element: XElement,
prefixes: Map<XType, Array<String>>
): List<String> {
return getAllDeeplinkUrIsFromCustomDeepLinksOnElement(
element = element,
prefixesMap = prefixes
) + (element.getAnnotation(DEEP_LINK_CLASS)?.value?.value?.toList() ?: emptyList())
val stringList = element.getAnnotation(DEEP_LINK_CLASS)?.getAsStringList("value")
val customUris = getAllDeeplinkUrIsFromCustomDeepLinksOnElement(element, prefixes)

return customUris + (stringList ?: emptyList())
}

private fun verifyCass(classElement: XTypeElement) {
Expand Down Expand Up @@ -324,13 +328,17 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
errorMessage = "Argument class must be public."
)
}
val argsConstructor = argsTypeElement.getConstructors().singleOrNull() ?: run {

val argsConstructors = argsTypeElement.getConstructors()

val argsConstructor = argsConstructors.singleOrNull() ?: run {
throw DeepLinkProcessorException(
element = argsTypeElement,
errorMessage = "Argument class for deeplink handler can only have a single constructor"
)
}
val allArgParameters = argsConstructor.parameters

val allPathParameters = allArgParameters.filterAnnotationType(DeepLinkParamType.Path)
val allQueryParameters = allArgParameters.filterAnnotationType(DeepLinkParamType.Query)
if (allPathParameters.size + allQueryParameters.size != allArgParameters.size) {
Expand All @@ -344,7 +352,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
val deepLinkUriTemplate = DeepLinkUri.parseTemplate(uriTemplate)
val templateHostPathSchemePlaceholders = deepLinkUriTemplate.schemeHostPathPlaceholders
val annotatedPathParameterNames = allPathParameters.mapNotNull {
it.getAnnotation(DeeplinkParam::class)?.value?.name
it.getAnnotation(DeeplinkParam::class)?.getAsString("name")
}.toSet()
val annotatedPathParametersThatAreNotInUrlTemplate =
annotatedPathParameterNames.filter { !templateHostPathSchemePlaceholders.contains(it) }
Expand All @@ -360,14 +368,23 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?

private fun List<XExecutableParameterElement>.filterAnnotationType(
deepLinkParamType: DeepLinkParamType
) =
filter { argParameter ->
argParameter.getAllAnnotations().find { annotation ->
annotation.qualifiedName == DeeplinkParam::class.qualifiedName
}?.annotationValues?.any { annotationValue ->
annotationValue.value.toString() == deepLinkParamType.toString()
} ?: false
}
) = filter { param ->
val deeplinkAnn = param.getAllAnnotations()
.firstOrNull { it.qualifiedName == DeeplinkParam::class.qualifiedName }
?: return@filter false

val enumArgValue = deeplinkAnn.annotationValues
.firstOrNull { it.name == "type" }
?.value
?.let { v ->
when (v) {
is Enum<*> -> v.name
else -> v.toString().substringAfterLast('.')
}
}

enumArgValue == deepLinkParamType.name
}

private fun verifyObjectElement(element: XTypeElement) {
if (!element.isHandler()) {
Expand All @@ -377,10 +394,12 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
" with @${DEEP_LINK_CLASS.simpleName} or any custom deep link annotation"
)
}
if (element.getAllMethods()

val handlerMethods = element.getAllMethods()
.filter { it.name == deepLinkHandlerHandleDeepLinkMethodName && it.parameters.size == 2 }
.count() != 1
) {


if (handlerMethods.count() != 1) {
throw DeepLinkProcessorException(
element = element,
errorMessage = "More than one method with two parameters and" +
Expand All @@ -390,7 +409,8 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
}

private fun customAnnotationPrefixes(customAnnotations: Set<XTypeElement>): Map<XType, Array<String>> {
return customAnnotations.map { customAnnotationTypeElement ->

return customAnnotations.associate { customAnnotationTypeElement ->
if (!customAnnotationTypeElement.isAnnotationClass()) {
logError(
element = customAnnotationTypeElement,
Expand All @@ -399,7 +419,9 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
}
val prefix: Array<String> =
customAnnotationTypeElement.getAnnotation(DEEP_LINK_SPEC_CLASS)
?.let { it.value.prefix } ?: emptyArray()
?.let { it.getAsStringList("prefix").toTypedArray() } ?: emptyArray()


if (prefix.hasEmptyOrNullString()) {
logError(
element = customAnnotationTypeElement,
Expand All @@ -411,7 +433,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
message = "Prefix property cannot be empty"
)
customAnnotationTypeElement.type to prefix
}.toMap()
}
}

private fun verifyAnnotatedType(
Expand Down Expand Up @@ -443,7 +465,7 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
logError(
element = it.value.first().enclosingTypeElement,
message = "Only one @DeepLinkHandler annotated element allowed per package!" +
" ${it.key} has ${it.value.joinToString { it.qualifiedName }}.",
" ${it.key} has ${it.value.joinToString { it.qualifiedName }}.",
)
}
return false
Expand Down Expand Up @@ -866,11 +888,11 @@ class DeepLinkProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?
prefixesMap: Map<XType, Array<String>>
): List<String> {
return element.findAnnotatedAnnotation<DeepLinkSpec>().flatMap { customAnnotation ->
val suffixes = customAnnotation.getAsList<String>("value")
val suffixes = customAnnotation.getAsStringList("value")
val prefixes = prefixesMap[customAnnotation.type]
?: throw DeepLinkProcessorException(
"Unable to find annotation '${customAnnotation.qualifiedName}' you must " +
"update 'deepLink.customAnnotations' within the build.gradle"
"update 'deepLink.customAnnotations' within the build.gradle"
)
prefixes.flatMap { prefix -> suffixes.map { suffix -> prefix + suffix } }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,11 @@ fun XTypeElement.directlyImplementsInterfaces(fqnList: List<String>): Boolean {
}

inline fun <reified T> XAnnotation.getAsList(method: String): List<T> {
val originalList = get<List<T>>(method)
// In new XProcessing versions List values are wrapped in XAnnotationValue but in old versions
// they are the raw type.
return if (originalList.firstOrNull() is XAnnotationValue) {
// TODO: In the next full release of xprocessing we should be able to safely assume
// the list type is always XAnnotationValue and can remove this if/else.
(originalList as List<XAnnotationValue>).map { xAnnotationValue ->
check(xAnnotationValue.value is T) {
"Expected type ${T::class} but got ${xAnnotationValue.value?.javaClass}"
}
xAnnotationValue.value as T
}
val annotationValue = get(method)
return if (annotationValue != null) {
@Suppress("UNCHECKED_CAST")
(annotationValue.value as? List<T>) ?: emptyList()
} else {
return originalList
emptyList()
}
}
23 changes: 14 additions & 9 deletions deeplinkdispatch/build.gradle
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
apply plugin: 'com.android.library'

sourceCompatibility = 11

apply plugin: 'checkstyle'

apply plugin: 'kotlin-android'
apply from: '../publishing.gradle'
apply plugin: 'org.jmailen.kotlinter'
// apply plugin: 'org.jmailen.kotlinter'

dependencies {
api project(':deeplinkdispatch-base')
implementation deps.okio
implementation deps.jsr305
implementation deps.localBroadcastManager
implementation deps.appCompat
implementation deps.androidx.localBroadcastManager
implementation deps.androidx.appCompat
testImplementation deps.mockk
testImplementation deps.junit
testImplementation deps.assertJ
Expand All @@ -26,15 +23,23 @@ checkstyle {
}

android {
compileSdk androidConfig.compileSdkVersion
compileSdk 35

defaultConfig {
minSdk androidConfig.minSdkVersion
targetSdk androidConfig.compileSdkVersion
minSdk 24
targetSdk 35
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'proguard-rules.pro'
}
testOptions {
unitTests.returnDefaultValues = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
namespace 'com.airbnb.android.deeplinkdispatch'
}
3 changes: 1 addition & 2 deletions deeplinkdispatch/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.airbnb.android.deeplinkdispatch"/>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
10 changes: 5 additions & 5 deletions dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
def versions = [
kotlinVersion : '1.8.10',
kotlinVersion : '2.1.21',
appCompatVersion : '1.4.1',
localBroadcastManagerVersion : '1.1.0',
roboelectricVersion : '4.9',
benchmarkVersion : '1.0.0',
compileTestingVersion : '1.5.0',
kspVersion : '1.8.10-1.0.9',
xProcessorVersion : '2.6.0-alpha01',
kspVersion : '2.1.21-2.0.2',
xProcessorVersion : '2.7.2',
mockkVersion : '1.12.3',
ktlintGradlePluginVersion : '3.8.0',
ktlintGradlePluginVersion : '5.1.0',
androidXTestingVersion : '1.4.0'
]

ext.versions = versions
ext.androidConfig = [
agpVersion : '7.4.0',
agpVersion : '8.12.1',
compileSdkVersion : 32,
minSdkVersion : 16,
targetSdkVersion : 30
Expand Down
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ android.enableR8.fullMode=true
# Publishing configuration for vanniktech/gradle-maven-publish-plugin
SONATYPE_HOST=DEFAULT
SONATYPE_AUTOMATIC_RELEASE=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 3 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#Mon Nov 18 16:19:47 PST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
Loading