Skip to content

Commit

Permalink
code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Foso committed May 14, 2023
1 parent 2b7f1df commit 83c5fd1
Show file tree
Hide file tree
Showing 12 changed files with 57 additions and 52 deletions.
2 changes: 1 addition & 1 deletion ktorfit-ksp/src/main/kotlin/KtorfitProcessor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class KtorfitProcessor(env: SymbolProcessorEnvironment, private val ktorf
classDec.toClassData(KtorfitLogger(logger, type))
}

generateImplClass(classDataList, codeGenerator)
generateImplClass(classDataList, codeGenerator, resolver)

return emptyList()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package de.jensklingenberg.ktorfit.generator

import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.Resolver
import de.jensklingenberg.ktorfit.model.ClassData
import de.jensklingenberg.ktorfit.model.getImplClassFileSource
import java.io.OutputStreamWriter
Expand All @@ -10,9 +11,9 @@ import java.io.OutputStreamWriter
/**
* Generate the Impl class for every interface used for Ktorfit
*/
fun generateImplClass(classDataList: List<ClassData>, codeGenerator: CodeGenerator) {
fun generateImplClass(classDataList: List<ClassData>, codeGenerator: CodeGenerator, resolver: Resolver) {
classDataList.forEach { classData ->
val fileSource = classData.getImplClassFileSource()
val fileSource = classData.getImplClassFileSource(resolver)

val packageName = classData.packageName
val className = classData.name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package de.jensklingenberg.ktorfit.model

import com.google.devtools.ksp.getDeclaredFunctions
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.*
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ksp.toKModifier
import com.squareup.kotlinpoet.ksp.toTypeName
import de.jensklingenberg.ktorfit.model.KtorfitError.Companion.PROPERTIES_NOT_SUPPORTED
import de.jensklingenberg.ktorfit.model.annotations.RequestType
import de.jensklingenberg.ktorfit.utils.addImports
import de.jensklingenberg.ktorfit.utils.getFileImports
Expand All @@ -30,7 +32,7 @@ const val WILDCARDIMPORT = "WILDCARDIMPORT"
/**
* Transform a [ClassData] to a [FileSpec] for KotlinPoet
*/
fun ClassData.getImplClassFileSource(): String {
fun ClassData.getImplClassFileSource(resolver: Resolver): String {
val classData = this
val optinAnnotation = AnnotationSpec.builder(ClassName("kotlin", "OptIn"))
.addMember("InternalKtorfitApi::class")
Expand All @@ -49,7 +51,7 @@ fun ClassData.getImplClassFileSource(): String {
.mutable(property.isMutable)
.getter(
FunSpec.getterBuilder()
.addStatement("throw IllegalStateException(\"Properties not supported by Ktorfit\")")
.addStatement(PROPERTIES_NOT_SUPPORTED)
.build()
)

Expand Down Expand Up @@ -84,7 +86,7 @@ fun ClassData.getImplClassFileSource(): String {
.addSuperinterface(ClassName(classData.packageName, classData.name))
.addSuperinterface(ktorfitServiceClassName)
.addKtorfitSuperInterface(classData.superClasses)
.addFunctions(classData.functions.map { it.toFunSpec() })
.addFunctions(classData.functions.map { it.toFunSpec(resolver) })
.addProperty(
clientProperty
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package de.jensklingenberg.ktorfit.model

import KtorfitProcessor
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
Expand All @@ -23,7 +24,7 @@ data class FunctionData(
val httpMethodAnnotation: HttpMethodAnnotation
) {

fun toFunSpec(): FunSpec {
fun toFunSpec(resolver: Resolver): FunSpec {
val returnTypeName = this.returnType.name
val innerReturnType = this.returnType.innerTypeName
val nullableText = if (this.returnType.isNullable) {
Expand All @@ -45,6 +46,7 @@ data class FunctionData(
.addStatement(
getReqBuilderExtensionText(
this,
resolver
)
)
.addStatement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class KtorfitError {
"@Body parameters cannot be used with form or multi-part encoding"
const val FOR_STREAMING_THE_RETURN_TYPE_MUST_BE_HTTP_STATEMENT =
"For streaming the return type must be io.ktor.client.statement.HttpStatement"
const val COULD_NOT_FIND_ANY_KTORFIT_ANNOTATIONS_IN_CLASS = "Could not find any Ktorfit annotations in class"
fun MISSING_EITHER_KEYWORD_URL_OrURL_PARAMETER(keyword: String) =
"Missing either @$keyword URL or @Url parameter"

Expand All @@ -58,5 +57,7 @@ class KtorfitError {
fun NO_HTTP_ANNOTATION_AT(functionName: String) = "No Http annotation at $functionName"
fun URL_CAN_ONLY_BE_USED_WITH_EMPY(keyword: String) = "@Url can only be used with empty @${keyword} URL value"
const val HEADERS_VALUE_MUST_BE_IN_FORM = "@Headers value must be in the form \"Name: Value\". Found: "
const val PROPERTIES_NOT_SUPPORTED = "throw IllegalStateException(\"Properties not supported by Ktorfit\")"

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ import de.jensklingenberg.ktorfit.utils.surroundIfNotEmpty

fun getFieldArgumentsText(params: List<ParameterData>, listType: KSType, arrayType: KSType): String {

val text = params.filter { it.hasAnnotation<Field>() }.joinToString("") { parameterData ->
val fieldText = params.filter { it.hasAnnotation<Field>() }.joinToString("") { parameterData ->
val field = parameterData.annotations.filterIsInstance<Field>().first()
val encoded = field.encoded
val paramName = parameterData.name
val fieldKey = field.value
val fieldValue = field.value
val starProj = parameterData.type.parameterType?.resolve()?.starProjection()

val isList = starProj?.isAssignableFrom(listType!!) ?: false
val isList = starProj?.isAssignableFrom(listType) ?: false
val isArray = starProj?.isAssignableFrom(arrayType) ?: false

when {
isList || isArray -> {
"%s?.filterNotNull()?.forEach { append(\"%s\", \"\$it\"%s) }\n".format(paramName, fieldKey,if (encoded) {
"$paramName?.filterNotNull()?.forEach { append(\"$fieldValue\", \"\$it\"%s) }\n".format(if (encoded) {
/**
* This is a workaround.
* Ktor encodes parameters by default and I don't know
Expand All @@ -36,15 +36,8 @@ fun getFieldArgumentsText(params: List<ParameterData>, listType: KSType, arrayTy
}

else -> {
"$paramName?.let{ append(\"$fieldKey\", \"\${it}\"%s) }\n".format(
"$paramName?.let{ append(\"$fieldValue\", \"\${it}\"%s) }\n".format(
if (encoded) {
/**
* This is a workaround.
* Ktor encodes parameters by default and I don't know
* how to deactivate this.
* When the value is not encoded it will be given to Ktor unchanged.
* If it is encoded, it gets decoded, so Ktor can encode it again.
*/
".decodeURLQueryComponent(plusIsSpace = true)"
} else {
""
Expand All @@ -71,7 +64,7 @@ fun getFieldArgumentsText(params: List<ParameterData>, listType: KSType, arrayTy
)
}

return (text + fieldMapStrings).surroundIfNotEmpty(
return (fieldText + fieldMapStrings).surroundIfNotEmpty(
"val _formParameters = Parameters.build {\n", "}\nsetBody(FormDataContent(_formParameters))\n"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fun getHeadersCode(

when {
isList || isArray -> {
"%s?.filterNotNull()?.forEach { append(\"%s\", \"\$it\") }\n".format(paramName, headerName)
"$paramName?.filterNotNull()?.forEach { append(\"$headerName\", \"\$it\") }\n"
}

else -> {
Expand All @@ -56,7 +56,6 @@ fun getHeadersCode(
val headerMapAnnotationText = parameterDataList
.filter { it.hasAnnotation<HeaderMap>() }
.joinToString("") {

"${it.name}?.forEach { append(it.key, \"\${it.value}\") }\n"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,31 @@ import de.jensklingenberg.ktorfit.utils.surroundIfNotEmpty

fun getPartsCode(params: List<ParameterData>, listType: KSType, arrayType: KSType): String {

val text = params.filter { it.hasAnnotation<Part>() }.joinToString("") { parameterData ->
val field = parameterData.annotations.filterIsInstance<Part>().first()
val data = parameterData.name
val fieldKey = field.value
val partText = params.filter { it.hasAnnotation<Part>() }.joinToString("") { parameterData ->
val part = parameterData.annotations.filterIsInstance<Part>().first()
val name = parameterData.name
val partValue = part.value

val starProj = parameterData.type.parameterType?.resolve()?.starProjection()
val isList = starProj?.isAssignableFrom(listType) ?: false
val isArray = starProj?.isAssignableFrom(arrayType) ?: false

when {
isList || isArray -> {
"$data?.filterNotNull()?.forEach { append(\"$fieldKey\", \"\${it}\") }\n"
"$name?.filterNotNull()?.forEach { append(\"$partValue\", \"\${it}\") }\n"
}

else -> {
"$data?.let{ append(\"$fieldKey\", \"\${it}\") }\n"
"$name?.let{ append(\"$partValue\", \"\${it}\") }\n"
}
}
}

val fieldMapStrings = params.filter { it.hasAnnotation<PartMap>() }.joinToString("") { parameterData ->

val partMapStrings = params.filter { it.hasAnnotation<PartMap>() }.joinToString("") { parameterData ->
"${parameterData.name}?.forEach { entry -> entry.value?.let{ append(entry.key, \"\${entry.value}\") } }\n"
}

return (text + fieldMapStrings).surroundIfNotEmpty(
return (partText + partMapStrings).surroundIfNotEmpty(
"val _formData = formData {\n", "}\nsetBody(MultiPartFormDataContent(_formData))\n"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fun getQueryCode(params: List<ParameterData>, listType: KSType, arrayType: KSTyp
val query = parameterData.annotations.filterIsInstance<Query>().first()
val encoded = query.encoded
val starProj = parameterData.type.parameterType?.resolve()?.starProjection()
val isList = starProj?.isAssignableFrom(listType!!) ?: false
val isList = starProj?.isAssignableFrom(listType) ?: false
val isArray = starProj?.isAssignableFrom(arrayType) ?: false

if (isList || isArray) {
Expand All @@ -40,38 +40,38 @@ fun getQueryCode(params: List<ParameterData>, listType: KSType, arrayType: KSTyp
val queryNameText = params.filter { it.hasAnnotation<QueryName>() }.joinToString(separator = "") { parameterData ->
val queryName = parameterData.annotations.filterIsInstance<QueryName>().first()
val encoded = queryName.encoded
val data = parameterData.name
val name = parameterData.name

val starProj = parameterData.type.parameterType?.resolve()?.starProjection()
val isList = starProj?.isAssignableFrom(listType!!) ?: false
val isList = starProj?.isAssignableFrom(listType) ?: false
val isArray = starProj?.isAssignableFrom(arrayType) ?: false

if (isList || isArray) {
"%s?.filterNotNull()?.forEach { %s.appendAll(\"\$it\", emptyList()) }\n".format(
parameterData.name,
name,
if (encoded) {
"encodedParameters"
} else {
"parameters"
}
)
} else {/**/
} else {
"%s.appendAll(\"\$%s\", emptyList())\n"
.format(
if (encoded) {
"encodedParameters"
} else {
"parameters"
},
data
name
)
}
}

val queryMapStrings = params.filter { it.hasAnnotation<QueryMap>() }.joinToString(separator = "") { myParam ->
val queryMap = myParam.findAnnotationOrNull<QueryMap>()!!
val queryMapStrings = params.filter { it.hasAnnotation<QueryMap>() }.joinToString(separator = "") { parameterData ->
val queryMap = parameterData.findAnnotationOrNull<QueryMap>()!!
val encoded = queryMap.encoded
val data = myParam.name
val data = parameterData.name
"%s?.forEach { entry -> entry.value?.let{ %s(entry.key, \"\${entry.value}\") } }\n".format(
data,
if (encoded) {
Expand All @@ -86,5 +86,5 @@ fun getQueryCode(params: List<ParameterData>, listType: KSType, arrayType: KSTyp
return (queryText + queryNameText + queryMapStrings).surroundIfNotEmpty(
"url{\n",
"}"
)//myQueryStrings.joinToString { it.toString() }.surroundIfNotEmpty("queries = listOf(", ")")
)
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package de.jensklingenberg.ktorfit.reqBuilderExtension


import KtorfitProcessor
import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getKotlinClassByName
import com.google.devtools.ksp.processing.Resolver
import de.jensklingenberg.ktorfit.model.FunctionData

/**
* This will generate the code for the HttpRequestBuilder
*/
@OptIn(KspExperimental::class)
fun getReqBuilderExtensionText(functionData: FunctionData): String {
fun getReqBuilderExtensionText(functionData: FunctionData, resolver: Resolver): String {

val method = getMethodCode(functionData.httpMethodAnnotation)
val listType =
KtorfitProcessor.ktorfitResolver.getKotlinClassByName("kotlin.collections.List")?.asStarProjectedType()!!
resolver.getKotlinClassByName("kotlin.collections.List")?.asStarProjectedType()!!

val arrayType = resolver.builtIns.arrayType.starProjection()

val arrayType = KtorfitProcessor.ktorfitResolver.builtIns.arrayType.starProjection()
val headers = getHeadersCode(
functionData.annotations,
functionData.parameterDataList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ fun getUrlCode(params: List<ParameterData>, methodAnnotation: HttpMethodAnnotati
val baseUrl = if (methodAnnotation.path.startsWith("http")) {
""
} else {
params.firstOrNull { it.hasAnnotation<Url>() }?.let {
"(ktorfitClient.baseUrl.takeIf{ !${it.name}.startsWith(\"http\")} ?: \"\") + "
params.firstOrNull { it.hasAnnotation<Url>() }?.let { parameterData ->
"(ktorfitClient.baseUrl.takeIf{ !${parameterData.name}.startsWith(\"http\")} ?: \"\") + "
} ?: "ktorfitClient.baseUrl + "
}


params.filter { it.hasAnnotation<Path>() }.forEach { myParam ->
val paramName = myParam.name
val pathAnnotation = myParam.findAnnotationOrNull<Path>()!!
params.filter { it.hasAnnotation<Path>() }.forEach { parameterData ->
val paramName = parameterData.name
val pathAnnotation = parameterData.findAnnotationOrNull<Path>()!!
val pathEncoded = if (!pathAnnotation.encoded) {
".encodeURLPath()"
} else {
Expand Down
8 changes: 8 additions & 0 deletions ktorfit-lib-common/api/jvm/ktorfit-lib-common.api
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,16 @@ public final class de/jensklingenberg/ktorfit/internal/RequestData {
public final class de/jensklingenberg/ktorfit/internal/TypeData {
public fun <init> (Ljava/lang/String;Ljava/util/List;Z)V
public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/util/List;
public final fun component3 ()Z
public final fun copy (Ljava/lang/String;Ljava/util/List;Z)Lde/jensklingenberg/ktorfit/internal/TypeData;
public static synthetic fun copy$default (Lde/jensklingenberg/ktorfit/internal/TypeData;Ljava/lang/String;Ljava/util/List;ZILjava/lang/Object;)Lde/jensklingenberg/ktorfit/internal/TypeData;
public fun equals (Ljava/lang/Object;)Z
public final fun getQualifiedName ()Ljava/lang/String;
public final fun getTypeArgs ()Ljava/util/List;
public fun hashCode ()I
public final fun isNullable ()Z
public fun toString ()Ljava/lang/String;
}

0 comments on commit 83c5fd1

Please sign in to comment.