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

Code cleanup #440

Merged
merged 2 commits into from
Oct 6, 2023
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build and test with Gradle
run: ./gradlew clean licensee :ktorfit-annotations:publishToMavenLocal :ktorfit-ksp:test :ktorfit-lib-common:jvmTest
run: ./gradlew licensee :ktorfit-annotations:publishToMavenLocal :ktorfit-ksp:test :ktorfit-lib-common:jvmTest :ktorfit-converters:call:publishToMavenLocal
2 changes: 1 addition & 1 deletion ktorfit-converters/call/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ licensee {
}


val enableSigning = true
val enableSigning = project.hasProperty("signingInMemoryKey")

mavenPublishing {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public class CallConverterFactory : Converter.Factory {
?: response.body(typeData.typeArgs.first().typeInfo)
callBack.onResponse(convertedBody, response)
} catch (ex: Exception) {
println(ex)
callBack.onError(ex)
}
}
Expand All @@ -40,16 +39,6 @@ public class CallConverterFactory : Converter.Factory {
}
}

override fun responseConverter(
typeData: TypeData,
ktorfit: Ktorfit
): Converter.ResponseConverter<HttpResponse, *>? {
if (typeData.typeInfo.type == Call::class) {
return CallResponseConverter(typeData, ktorfit)
}
return null
}

private class CallSuspendResponseConverter(val typeData: TypeData, val ktorfit: Ktorfit) :
Converter.SuspendResponseConverter<HttpResponse, Call<Any?>> {
override suspend fun convert(response: HttpResponse): Call<Any?> {
Expand All @@ -72,6 +61,17 @@ public class CallConverterFactory : Converter.Factory {
}
}

override fun responseConverter(
typeData: TypeData,
ktorfit: Ktorfit
): Converter.ResponseConverter<HttpResponse, *>? {
if (typeData.typeInfo.type == Call::class) {
return CallResponseConverter(typeData, ktorfit)
}
return null
}


override fun suspendResponseConverter(
typeData: TypeData,
ktorfit: Ktorfit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public class FlowConverterFactory : Converter.Factory {
override fun convert(getResponse: suspend () -> HttpResponse): Flow<Any?> {
val requestType = typeData.typeArgs.first()
return flow {
try {
val response = getResponse()
if (requestType.typeInfo.type == HttpResponse::class) {
emit(response)
Expand All @@ -35,13 +34,8 @@ public class FlowConverterFactory : Converter.Factory {
typeData.typeArgs.first()
)?.convert(response)
?: response.body(typeData.typeArgs.first().typeInfo)
Response.success(convertedBody, response)

emit(convertedBody)
}
} catch (exception: Exception) {
throw exception
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ fun ClassData.getImplClassFileSource(resolver: Resolver): String {
.addMember("InternalKtorfitApi::class")
.build()


val createExtensionFunctionSpec = getCreateExtensionFunctionSpec(classData)


val properties = classData.properties.map { property ->
val propBuilder = PropertySpec.builder(
property.simpleName.asString(),
Expand Down Expand Up @@ -108,7 +106,6 @@ fun ClassData.getImplClassFileSource(resolver: Resolver): String {
private fun getCreateExtensionFunctionSpec(
classData: ClassData
): FunSpec {

return FunSpec.builder("create${classData.name}")
.addModifiers(classData.modifiers)
.addStatement("return this.create(_${classData.name}Impl())")
Expand All @@ -125,11 +122,14 @@ private fun getCreateExtensionFunctionSpec(
*/
fun KSClassDeclaration.toClassData(logger: KSPLogger): ClassData {
val ksClassDeclaration = this
val imports = ksClassDeclaration.getFileImports().toMutableList().also {
it.add("io.ktor.util.reflect.*")
it.add("io.ktor.client.request.*")
it.add("io.ktor.http.*")
val imports = ksClassDeclaration.getFileImports().toMutableList().apply {
add("io.ktor.util.reflect.*")
add("io.ktor.client.request.*")
add("io.ktor.http.*")
add(ktorfitClass.packageName + "." + ktorfitClass.name)
add("de.jensklingenberg.ktorfit.internal.*")
}

val packageName = ksClassDeclaration.packageName.asString()
val className = ksClassDeclaration.simpleName.asString()

Expand All @@ -140,8 +140,10 @@ fun KSClassDeclaration.toClassData(logger: KSPLogger): ClassData {
return@map funcDeclaration.toFunctionData(logger)
}

if (functionDataList.any { it -> it.annotations.any { it is FormUrlEncoded || it is Multipart } ||
it.parameterDataList.any { param -> param.hasAnnotation<Field>() || param.hasAnnotation<Part>() } }) {
if (functionDataList.any { it ->
it.annotations.any { it is FormUrlEncoded || it is Multipart } ||
it.parameterDataList.any { param -> param.hasAnnotation<Field>() || param.hasAnnotation<Part>() }
}) {
imports.add("io.ktor.client.request.forms.*")
}

Expand All @@ -156,7 +158,6 @@ fun KSClassDeclaration.toClassData(logger: KSPLogger): ClassData {
}
val properties = ksClassDeclaration.getAllProperties().toList()


return ClassData(
name = className,
packageName = packageName,
Expand All @@ -165,19 +166,21 @@ fun KSClassDeclaration.toClassData(logger: KSPLogger): ClassData {
superClasses = filteredSupertypes,
properties = properties,
modifiers = ksClassDeclaration.modifiers.mapNotNull { it.toKModifier() },
ksFile = this.getKsFile()
ksFile = ksClassDeclaration.getKsFile()
)
}

private fun checkClassForErrors(ksClassDeclaration: KSClassDeclaration, logger: KSPLogger) {
val isJavaClass = ksClassDeclaration.origin.name == "JAVA"
if (isJavaClass) {
logger.error(KtorfitError.JAVA_INTERFACES_ARE_NOT_SUPPORTED, ksClassDeclaration)
return
}

val isInterface = ksClassDeclaration.classKind == ClassKind.INTERFACE
if (!isInterface) {
logger.error(KtorfitError.API_DECLARATIONS_MUST_BE_INTERFACES, ksClassDeclaration)
return
}

val hasTypeParameters = ksClassDeclaration.typeParameters.isNotEmpty()
Expand All @@ -186,10 +189,12 @@ private fun checkClassForErrors(ksClassDeclaration: KSClassDeclaration, logger:
KtorfitError.TYPE_PARAMETERS_ARE_UNSUPPORTED_ON + " ${ksClassDeclaration.simpleName.asString()}",
ksClassDeclaration
)
return
}

if (ksClassDeclaration.packageName.asString().isEmpty()) {
logger.error(KtorfitError.INTERFACE_NEEDS_TO_HAVE_A_PACKAGE, ksClassDeclaration)
return
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.jensklingenberg.ktorfit.model

class KtorfitError {
internal class KtorfitError {

companion object {
const val FUNCTION_OR_PARAMETERS_TYPES_MUST_NOT_INCLUDE_ATYPE_VARIABLE_OR_WILDCARD =
Expand All @@ -12,7 +12,6 @@ class KtorfitError {
const val QUERY_MAP_PARAMETER_TYPE_MUST_BE_MAP = "@QueryMap parameter type must be Map."
const val QUERY_MAP_KEYS_MUST_BE_OF_TYPE_STRING = "@QueryMap keys must be of type String:"
const val URL_PARAMETER_TYPE_MAY_NOT_BE_NULLABLE = "Url parameter type may not be nullable"

const val FIELD_MAP_PARAMETER_TYPE_MUST_BE_MAP = "@FieldMap parameter type must be Map."
const val FIELD_MAP_KEYS_MUST_BE_OF_TYPE_STRING = "@FieldMap keys must be of type String:"
const val ONLY_ONE_REQUEST_BUILDER_IS_ALLOWED = "Only one RequestBuilder is allowed."
Expand All @@ -26,22 +25,12 @@ class KtorfitError {
const val PART_PARAMETER_TYPE_MAY_NOT_BE_NULLABLE = "Part parameter type may not be nullable"
const val PATH_PARAMETER_TYPE_MAY_NOT_BE_NULLABLE = "Path parameter type may not be nullable"
const val API_DECLARATIONS_MUST_BE_INTERFACES = "API declarations must be interfaces."

const val PATH_CAN_ONLY_BE_USED_WITH_RELATIVE_URL_ON = "@Path can only be used with relative url on "
const val NON_BODY_HTTP_METHOD_CANNOT_CONTAIN_BODY = "Non-body HTTP method cannot contain @Body"
const val BODY_PARAMETERS_CANNOT_BE_USED_WITH_FORM_OR_MULTI_PART_ENCODING =
"@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"

fun MISSING_EITHER_KEYWORD_URL_OrURL_PARAMETER(keyword: String) =
"Missing either @$keyword URL or @Url parameter"

fun NO_KTORFIT_ANNOTATION_FOUND_AT(parameterName: String): String {
return "No Ktorfit Annotation found at $parameterName"
}

fun MISSING_X_IN_RELATIVE_URL_PATH(keyword: String) = "Missing {${keyword}} in relative url path"
const val JAVA_INTERFACES_ARE_NOT_SUPPORTED = "Java Interfaces are not supported"
const val INTERFACE_NEEDS_TO_HAVE_A_PACKAGE = "Interface needs to have a package"
const val ONLY_ONE_HTTP_METHOD_IS_ALLOWED = "Only one HTTP method is allowed."
Expand All @@ -53,11 +42,13 @@ class KtorfitError {
const val MULTIPART_CAN_ONLY_BE_SPECIFIED_ON_HTTPMETHODS =
"Multipart can only be specified on HTTP methods with request body (e.g., @POST)"
const val VARARG_NOT_SUPPORTED_USE_LIST_OR_ARRAY = "vararg not supported use List or Array"
const val NULLABLE_PARAMETERS_ARE_NOT_SUPPORTED = "Nullable Parameters Are Not Supported"
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\")"

fun MISSING_EITHER_KEYWORD_URL_OrURL_PARAMETER(keyword: String) = "Missing either @$keyword URL or @Url parameter"
fun NO_KTORFIT_ANNOTATION_FOUND_AT(parameterName: String): String = "No Ktorfit Annotation found at $parameterName"
fun MISSING_X_IN_RELATIVE_URL_PATH(keyword: String) = "Missing {${keyword}} in relative url path"
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"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package de.jensklingenberg.ktorfit.model.annotations

enum class HttpMethod(val keyword: String) {
GET("GET"), POST("POST"), PUT("PUT"), DELETE("DELETE"), HEAD("HEAD"), PATCH("PATCH"), CUSTOM("")
GET("GET"),
POST("POST"),
PUT("PUT"),
DELETE("DELETE"),
HEAD("HEAD"),
PATCH("PATCH"),
CUSTOM("")
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ import de.jensklingenberg.ktorfit.model.ParameterData
import de.jensklingenberg.ktorfit.model.annotations.ParameterAnnotation.Body

fun getBodyDataText(params: List<ParameterData>): String {
return params.firstOrNull { it.hasAnnotation<Body>() }?.let {
"setBody(%s)".format(it.name)
} ?: ""
return params.firstOrNull { it.hasAnnotation<Body>() }?.name?.let { "setBody($it)" } ?: ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@ import com.google.devtools.ksp.symbol.KSType
import com.squareup.kotlinpoet.FileSpec
import de.jensklingenberg.ktorfit.model.FunctionData
import de.jensklingenberg.ktorfit.model.WILDCARDIMPORT
import de.jensklingenberg.ktorfit.model.ktorfitClass
import java.io.File

fun KSType?.resolveTypeName(): String {
//TODO: Find better way to handle type alias Types
return this.toString().removePrefix("[typealias ").removeSuffix("]")
}


inline fun <reified T> FunctionData.findAnnotationOrNull(): T? {
return this.annotations.firstOrNull { it is T } as? T
}


fun String.prefixIfNotEmpty(s: String): String {
return (s + this).takeIf { this.isNotEmpty() } ?: this
}
Expand All @@ -32,28 +29,17 @@ fun String.surroundIfNotEmpty(prefix: String = "", postFix: String = ""): String
return this.prefixIfNotEmpty(prefix).postfixIfNotEmpty(postFix)
}


fun String.surroundWith(s: String): String {
return s + this + s
}

/**
* Gets the imports of a class by reading the imports from the file
* which contains the class
* TODO: Find better way to get imports
*/
fun KSClassDeclaration.getFileImports(): List<String> {
val importList =
File(this.containingFile!!.filePath)
.readLines()
.filter { it.trimStart().startsWith("import") }
.filter { !it.startsWith("import de.jensklingenberg.ktorfit.http.") }
.toMutableSet()

importList.add(ktorfitClass.packageName + "." + ktorfitClass.name)
importList.add("de.jensklingenberg.ktorfit.internal.*")

return importList.map { it.removePrefix("import ") }
return File(this.containingFile!!.filePath)
.readLines()
.filter { it.trimStart().startsWith("import") && !it.startsWith("import de.jensklingenberg.ktorfit.http.") }
.toMutableSet()
.map { it.removePrefix("import ") }
}


Expand Down
4 changes: 0 additions & 4 deletions ktorfit-lib-common/api/android/ktorfit-lib-common.api
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,10 @@ public final class de/jensklingenberg/ktorfit/internal/RequestData {
public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lkotlin/jvm/functions/Function1;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Lio/ktor/util/reflect/TypeInfo;
public final fun copy (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;)Lde/jensklingenberg/ktorfit/internal/RequestData;
public static synthetic fun copy$default (Lde/jensklingenberg/ktorfit/internal/RequestData;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;ILjava/lang/Object;)Lde/jensklingenberg/ktorfit/internal/RequestData;
public fun equals (Ljava/lang/Object;)Z
public final fun getKtorfitRequestBuilder ()Lkotlin/jvm/functions/Function1;
public final fun getReturnTypeInfo ()Lio/ktor/util/reflect/TypeInfo;
public final fun getReturnTypeName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down
4 changes: 0 additions & 4 deletions ktorfit-lib-common/api/jvm/ktorfit-lib-common.api
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,10 @@ public final class de/jensklingenberg/ktorfit/internal/RequestData {
public fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;)V
public synthetic fun <init> (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lkotlin/jvm/functions/Function1;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()Lio/ktor/util/reflect/TypeInfo;
public final fun copy (Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;)Lde/jensklingenberg/ktorfit/internal/RequestData;
public static synthetic fun copy$default (Lde/jensklingenberg/ktorfit/internal/RequestData;Lkotlin/jvm/functions/Function1;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;ILjava/lang/Object;)Lde/jensklingenberg/ktorfit/internal/RequestData;
public fun equals (Ljava/lang/Object;)Z
public final fun getKtorfitRequestBuilder ()Lkotlin/jvm/functions/Function1;
public final fun getReturnTypeInfo ()Lio/ktor/util/reflect/TypeInfo;
public final fun getReturnTypeName ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down
Loading