diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9a6ed6913..65c792c1a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ ### :thinking: DOD Checklist -- [ ] I did all relevant changes to the documentation and the [changelog](https://github.com/Foso/Ktorfit/blob/master/docs/CHANGELOG.md). +- [] I did all relevant changes to the documentation and the [changelog](https://github.com/Foso/Ktorfit/blob/master/docs/CHANGELOG.md). diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f0370dbd..bdbaed416 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,8 +29,8 @@ jobs: - name: Set up JDK uses: actions/setup-java@v4 with: - distribution: zulu - java-version: 17 + distribution: temurin + java-version: 21 - uses: gradle/actions/setup-gradle@v4 - name: API check run: ./gradlew ktLintCheck apiCheck @@ -38,11 +38,11 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: 17 - distribution: 'zulu' + java-version: 21 + distribution: 'temurin' - name: Cache Gradle and wrapper uses: actions/cache@v4 with: @@ -55,4 +55,4 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build and test with Gradle - run: ./gradlew licensee :ktorfit-annotations:publishToMavenLocal :ktorfit-ksp:test :ktorfit-lib-core:jvmTest :ktorfit-converters:call:publishToMavenLocal :ktorfit-converters:flow:publishToMavenLocal :ktorfit-converters:response:publishToMavenLocal + run: ./gradlew licensee :ktorfit-annotations:publishToMavenLocal :ktorfit-compiler-plugin:test :ktorfit-ksp:test :ktorfit-lib-core:jvmTest :ktorfit-converters:call:publishToMavenLocal :ktorfit-converters:flow:publishToMavenLocal :ktorfit-converters:response:publishToMavenLocal diff --git a/.github/workflows/publish-converters.yml b/.github/workflows/publish-converters.yml index 52f86ff53..db49bd42b 100644 --- a/.github/workflows/publish-converters.yml +++ b/.github/workflows/publish-converters.yml @@ -10,13 +10,13 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install JDK 11 + - name: Install JDK 21 uses: actions/setup-java@v4 with: - distribution: 'zulu' - java-version: 17 + distribution: 'temurin' + java-version: 21 - - uses: gradle/gradle-build-action@v3 + - uses: gradle/gradle-build-action@v4 - name: Publish release run: ./gradlew :ktorfit-converters:call:publishAllPublicationsToMavenCentralRepository :ktorfit-converters:flow:publishAllPublicationsToMavenCentralRepository :ktorfit-converters:response:publishAllPublicationsToMavenCentralRepository @@ -24,4 +24,4 @@ jobs: ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }} ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_IN_MEMORY }} - ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} \ No newline at end of file + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3ab5fbc6e..65eb190df 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,11 +10,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install JDK 11 + - name: Install JDK 21 uses: actions/setup-java@v4 with: - distribution: 'zulu' - java-version: 17 + distribution: 'temurin' + java-version: 21 - uses: gradle/gradle-build-action@v3 @@ -31,11 +31,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install JDK 11 + - name: Install JDK 21 uses: actions/setup-java@v4 with: - distribution: 'zulu' - java-version: 17 + distribution: 'temurin' + java-version: 21 - uses: gradle/gradle-build-action@v3 @@ -52,11 +52,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install JDK 11 + - name: Install JDK 21 uses: actions/setup-java@v4 with: - distribution: 'zulu' - java-version: 17 + distribution: 'temurin' + java-version: 21 - uses: gradle/gradle-build-action@v3 @@ -73,11 +73,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install JDK 11 + - name: Install JDK 21 uses: actions/setup-java@v4 with: - distribution: 'zulu' - java-version: 17 + distribution: 'temurin' + java-version: 21 - uses: gradle/gradle-build-action@v3 @@ -94,11 +94,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Install JDK 11 + - name: Install JDK 21 uses: actions/setup-java@v4 with: - distribution: 'zulu' - java-version: 17 + distribution: 'temurin' + java-version: 21 - uses: gradle/gradle-build-action@v3 diff --git a/README.md b/README.md index 635c3498b..2ae90bca7 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,30 @@ See https://foso.github.io/Ktorfit/#compatibility |-----------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| | Ktorfit Gradle Plugin | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/de.jensklingenberg.ktorfit.gradle.plugin)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/de.jensklingenberg.ktorfit.gradle.plugin) | | ktorfit-lib | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-lib) | -| compiler-plugin | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/compiler-plugin)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/compiler-plugin) | | ktorfit-lib-light | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib-light)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-lib-light) | +| compiler-plugin | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/compiler-plugin)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/compiler-plugin) | | ktorfit-ksp | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-ksp) | | ktorfit-converters-flow | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-flow)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-flow) | | ktorfit-converters-call | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-call)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-call) | | ktorfit-converters-response | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-response)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-response) | +## Ktorfit Ktor 3 Packages +The main dependencies will stay on Ktor 2.x till Ktor 3 is stable. +When you want to use Ktor 3 and WasmJs, you need to replace your dependecies with a "ktor3" version, you can use the following packages: + +| Project | Version | +|-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| ktorfit-lib-light-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib-light-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-lib-light-ktor-3.0.0-beta-2) | +| ktorfit-lib-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-lib-ktor-3.0.0-beta-2) | +| ktorfit-converters-flow-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-flow-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-flow-ktor-3.0.0-beta-2) | +| ktorfit-converters-call-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-call-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-call-ktor-3.0.0-beta-2) | +| ktorfit-converters-response-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-response-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-response-ktor-3.0.0-beta-2) | + +You can find all Ktorfit packages on [Maven Central](https://search.maven.org/search?q=de.jensklingenberg.ktorfit). + +🔎 Check the [latest changes](https://github.com/Foso/Ktorfit/blob/master/docs/CHANGELOG.md) to update your Koin project. + +🛠 Follow the [setup page](https://foso.github.io/Ktorfit/installation/) for more details ## 👷 Project Structure diff --git a/build.gradle.kts b/build.gradle.kts index 3611b0d0f..0a02c14b0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,8 +4,6 @@ plugins { id("org.jlleitschuh.gradle.ktlint") version "12.1.1" apply false } - - buildscript { repositories { mavenLocal() diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c3746e3af..fb4c22bac 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,21 +7,74 @@ and this project orients towards [Semantic Versioning](http://semver.org/spec/v2 Note: This project needs KSP to work and every new Ktorfit with an update of the KSP version is technically a breaking change. But there is no intent to bump the Ktorfit major version for every KSP update. +# [2.1.0]() + +* Supported Kotlin version: (min) 2.0.20 +* Supported KSP version: (min) 1.0.24 +* Ktor version: 2.3.12 + +## Added +- documentation page for [known issues](https://foso.github.io/Ktorfit/knownissues/) + +## Changed +- Allow Http Delete with Body [#647](https://github.com/Foso/Ktorfit/issues/647) +- By default, nullable response types will not throw an exception. You can now override this behavior by adding the **DontSwallowExceptionsConverterFactory** +or your own ConverterFactory to the converterFactories. [#618](https://github.com/Foso/Ktorfit/issues/618) + +## Fixed +- Task with path 'kspCommonMainKotlinMetadata' not found in project [#593](https://github.com/Foso/Ktorfit/issues/593) +- Ktorfit Gradle Plugin not compatible with Android Multiplatform Library plugin [#638](https://github.com/Foso/Ktorfit/issues/638) + +## Ktor3 +The "normal" dependencies will stay on Ktor 2.x till 3.0 is stable. But here are versions that you can use when want to use Ktor3 and WasmJs + +de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2:2.1.0 + +de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2:2.1.0 + +de.jensklingenberg.ktorfit:ktorfit-converters-flow-ktor-3.0.0-beta-2:2.1.0 + +de.jensklingenberg.ktorfit:ktorfit-converters-call-ktor-3.0.0-beta-2:2.1.0 + +de.jensklingenberg.ktorfit:ktorfit-converters-response-ktor-3.0.0-beta-2:2.1.0 + # [2.0.1]() -compiler-plugin:2.0.1-2.0.10 - 2024-08-10 -======================================== -- Kotlin 2.0.10 +* Supported Kotlin version: (min) 2.0.0 (max) 2.0.20 +* Supported KSP version: (min) 1.0.24 (max) 1.0.24 +* Ktor version: 2.3.12 2.0.1 - 2024-08-08 ======================================== -### Fixed -- #594 Endpoint with types from other module -- #591 Ktorfit plugin doesn't include correct generate source if build directory changes #591 -- #621 RequestConverter causing compile error +## Fixed +- Endpoint with types from other module #594 +- Ktorfit plugin doesn't include correct generate source if build directory changes #591 +- RequestConverter causing compile error #621 - Build with Ktor 2.3.12 +## ktorfit-annotations +- 2.0.1: The annotations are now also available for WasmJs + +## compilerPlugin +- Kotlin 2.0.0: 2.0.1-2.0.0 - 2024-08-08 +- Kotlin 2.0.10: 2.0.1-2.0.10 - 2024-08-10 +- Kotlin 2.0.20-RC: 2.0.1-2.0.20-RC - 2024-08-13 +- Kotlin 2.0.20-RC2: 2.0.1-2.0.20-RC2 - 2024-08-13 +- Kotlin 2.0.20: 2.0.1-2.0.20 - 2024-08-23 +## ktorfit-ksp +- KSP 1.0.24: ktorfit-ksp-2.0.1-1.0.24 - 2024-08-08 + +## Ktor3 +The "normal" dependencies will stay on Ktor 2.x till 3.0 is stable. But here are versions that you can use when want to use Ktor3 and WasmJs + +| Project | Version | +|-----------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| ktorfit-lib-light-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib-light-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-lib-light-ktor-3.0.0-beta-2) | +| ktorfit-lib-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-lib-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-lib-ktor-3.0.0-beta-2) | +| ktorfit-converters-flow-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-flow-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-flow-ktor-3.0.0-beta-2) | +| ktorfit-converters-call-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-call-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-call-ktor-3.0.0-beta-2) | +| ktorfit-converters-response-ktor-3.0.0-beta-2 | [![Maven Central](https://img.shields.io/maven-central/v/de.jensklingenberg.ktorfit/ktorfit-converters-response-ktor-3.0.0-beta-2)](https://central.sonatype.com/artifact/de.jensklingenberg.ktorfit/ktorfit-converters-response-ktor-3.0.0-beta-2) | # [2.0.0]() @@ -39,7 +92,8 @@ ktorfit-ksp-2.0.0-1.0.22 - 2024-06-06 2.0.0 - 2024-05-27 ======================================== -### Changed + +# Changed - Build with KSP 1.0.21, Kotlin 2.0.0, Ktor 2.3.11 - The needed dependencies for Ktorfit KSP processor are now included in the Ktorfit Gradle plugin. You can remove the ksp() block from your build.gradle.kts file. You still need to apply the KSP plugin. diff --git a/docs/android/proguard.md b/docs/android/proguard.md new file mode 100644 index 000000000..d4b0760f2 --- /dev/null +++ b/docs/android/proguard.md @@ -0,0 +1,5 @@ +proguard-rules.pro +``` +-keep class de.jensklingenberg.ktorfit.** { *; } +-keepclassmembers class de.jensklingenberg.ktorfit.** { *; } +``` \ No newline at end of file diff --git a/docs/architecture.md b/docs/architecture.md index 8f3451147..d412663d9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -34,7 +34,7 @@ Then it looks at the parent interfaces of that functions and generates, the sour public class _ExampleApiImpl( private val _ktorfit: Ktorfit, ) : ExampleApi { - public val _converter: KtorfitConverterHelper = KtorfitConverterHelper(_ktorfit) + private val _helper: KtorfitConverterHelper = KtorfitConverterHelper(_ktorfit) override suspend fun exampleGet(): People { val _ext: HttpRequestBuilder.() -> Unit = { @@ -43,14 +43,18 @@ public class _ExampleApiImpl( takeFrom(_ktorfit.baseUrl + "/test") } } - val _typeData = TypeData.createTypeData(qualifiedTypename = "com.example.model.People", - typeInfo = typeInfo()) - - return _converter.suspendRequest(_typeData,_ext)!! + val _typeData = TypeData.createTypeData( + typeInfo = typeInfo(), + ) + return _helper.suspendRequest(_typeData,_ext)!! } } -public fun Ktorfit.createExampleApi(): ExampleApi = this.create(_ExampleApiImpl(this)) +public class _ExampleApiProvider : ClassProvider { + override fun create(_ktorfit: Ktorfit): ExampleApi = _ExampleApiImpl(_ktorfit) +} + +public fun Ktorfit.createExampleApi(): ExampleApi = _ExampleApiImpl(this) ``` The next part is the compiler plugin which is added by the gradle plugin. diff --git a/docs/configuration.md b/docs/configuration.md index 19bbc6c4d..2379a9e4b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,4 +1,5 @@ -# Compile errors +# Gradle +## Compile errors By default, Ktorfit will throw compile error when it finds conditions under which it can't ensure that it will work correct. You can set it in the Ktorfit config to change this @@ -16,7 +17,7 @@ You can set it in your build.gradle.kts file, * WARNING: Turn errors into warnings -# QualifiedTypeName +## QualifiedTypeName By default, Ktorfit will keep qualifiedTypename for TypeData in the generated code empty. You can set it in the Ktorfit config to change this: ```kotlin @@ -42,9 +43,9 @@ val _typeData = TypeData.createTypeData( ... ``` +# Ktorfit Builder - -# Add your own Ktor client +## Add your own Ktor client You can set your Ktor client instance to the Ktorfit builder: ```kotlin diff --git a/docs/development.md b/docs/development.md index 90c64e52f..70fe44ec0 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1 +1,9 @@ -# Development \ No newline at end of file +# Development + +# Update Ktorfit for new Kotlin version +- Bump **kotlin** in libs.versions +- Change **ktorfitCompiler** in libs.versions to KTORFIT_VERSION-NEW_KOTLIN_VERSION +- Run tests in :ktorfit-compiler-plugin +- Create a PR against master +- Merge PR +- Run GitHub Actions "publish" workflow \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 552cd3193..a0626b557 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,17 +15,11 @@ inspired by [Retrofit](https://square.github.io/retrofit/) ## Compatibility -| Ktorfit-version | Kotlin | KSP | Ktor | -|-------------------|:-------------:|:-----------------------------:|:----------:| -| **_2.0.1_** | **>=2.0.0** | **>=1.0.24** | **2.3.12** | -| **_2.0.0_** | **2.0.0** | **1.0.21 (min) 1.0.24 (max)** | **2.3.11** | -| **_2.0.0-rc01_** | **2.0.0-RC3** | **1.0.20** | **2.3.11** | -| **_2.0.0-beta1_** | **2.0.0-RC1** | **1.0.20** | **2.3.10** | -| **_1.14.0_** | **2.0.0-RC1** | **1.0.20** | **2.3.10** | -| **_1.13.0_** | **1.9.23** | **1.0.20** | **2.3.10** | -| **_1.12.0_** | **1.9.22** | **1.0.16** | **2.3.6** | - - +| Ktorfit-version | +|-------------------------------------------------------------------------------| +| **_2.1.0_** https://github.com/Foso/Ktorfit/blob/master/docs/CHANGELOG.md#210 | +| **_2.0.1_** https://github.com/Foso/Ktorfit/blob/master/docs/CHANGELOG.md#201 | +| **_2.0.0_** https://github.com/Foso/Ktorfit/blob/master/docs/CHANGELOG.md#200 | # Installation diff --git a/docs/knownissues.md b/docs/knownissues.md new file mode 100644 index 000000000..d8474b12e --- /dev/null +++ b/docs/knownissues.md @@ -0,0 +1,17 @@ +# Known Issues + +## KMP project with single target + +* Unresolved reference for API class + +When you have a KMP project with a single target, IntelliJ will find the generated "create" extension function (e.g. +**ktorfit.createExampleApi()**) in your common module, but the compilation will fail +because of an "Unresolved reference" error. In that case, you have to use **ktorfit.create<ExampleApi>()** to make it work, even though it's already deprecated. + +Kotlin handles the compilation of a KMP project with a single target differently than with multiple targets. + +See: + +* https://youtrack.jetbrains.com/issue/KT-59129 + +* https://youtrack.jetbrains.com/issue/KT-52664/Multiplatform-projects-with-a-single-target \ No newline at end of file diff --git a/example/AndroidOnlyExample/app/build.gradle.kts b/example/AndroidOnlyExample/app/build.gradle.kts index 099eccc45..632922cbf 100644 --- a/example/AndroidOnlyExample/app/build.gradle.kts +++ b/example/AndroidOnlyExample/app/build.gradle.kts @@ -1,10 +1,10 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") - id("com.google.devtools.ksp") version "2.0.0-1.0.22" - id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" - id("de.jensklingenberg.ktorfit") version "2.0.0" - id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" + id("com.google.devtools.ksp") version "2.0.20-1.0.24" + id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" + id("de.jensklingenberg.ktorfit") version "2.0.1" + id("org.jetbrains.kotlin.plugin.compose") version "2.0.10" } ktorfit{ @@ -65,16 +65,16 @@ dependencies { implementation("de.jensklingenberg.ktorfit:ktorfit-converters-flow:$ktorfit") - implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.2") - implementation("androidx.activity:activity-compose:1.9.0") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4") + implementation("androidx.activity:activity-compose:1.9.1") implementation("androidx.compose.ui:ui:$compose_ui_version") implementation("androidx.compose.ui:ui-tooling-preview:$compose_ui_version") implementation("androidx.compose.material:material:1.6.7") debugImplementation("androidx.compose.ui:ui-tooling:$compose_ui_version") debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_ui_version") testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_ui_version") } diff --git a/example/AndroidOnlyExample/build.gradle b/example/AndroidOnlyExample/build.gradle index 697c0ee8d..ed6e58b01 100644 --- a/example/AndroidOnlyExample/build.gradle +++ b/example/AndroidOnlyExample/build.gradle @@ -2,5 +2,5 @@ plugins { id 'com.android.application' version '8.4.1' apply false id 'com.android.library' version '8.4.1' apply false - id 'org.jetbrains.kotlin.android' version '2.0.0' apply false + id 'org.jetbrains.kotlin.android' version '2.0.20' apply false } \ No newline at end of file diff --git a/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.jar b/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.jar index e6441136f..a4b76b953 100644 Binary files a/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.jar and b/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.properties b/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.properties index a4413138c..9355b4155 100644 --- a/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.properties +++ b/example/AndroidOnlyExample/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/example/AndroidOnlyExample/gradlew b/example/AndroidOnlyExample/gradlew index b740cf133..f5feea6d6 100755 --- a/example/AndroidOnlyExample/gradlew +++ b/example/AndroidOnlyExample/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/example/AndroidOnlyExample/gradlew.bat b/example/AndroidOnlyExample/gradlew.bat index 7101f8e46..9b42019c7 100644 --- a/example/AndroidOnlyExample/gradlew.bat +++ b/example/AndroidOnlyExample/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/example/MultiplatformExample/androidApp/build.gradle.kts b/example/MultiplatformExample/androidApp/build.gradle.kts index 7874e1209..4d1716bf6 100644 --- a/example/MultiplatformExample/androidApp/build.gradle.kts +++ b/example/MultiplatformExample/androidApp/build.gradle.kts @@ -12,6 +12,7 @@ android { targetSdk = 34 versionCode = 1 versionName = "1.0" + namespace = "com.example.myapplication.android" } buildTypes { getByName("release") { diff --git a/example/MultiplatformExample/build.gradle.kts b/example/MultiplatformExample/build.gradle.kts index 6b0a75157..8da991790 100644 --- a/example/MultiplatformExample/build.gradle.kts +++ b/example/MultiplatformExample/build.gradle.kts @@ -9,9 +9,9 @@ buildscript { } } dependencies { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.0") - classpath("com.android.tools.build:gradle:8.2.0") - classpath("org.jetbrains.kotlin:kotlin-serialization:2.0.10") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20") + classpath("com.android.tools.build:gradle:8.5.2") + classpath("org.jetbrains.kotlin:kotlin-serialization:2.0.20") } } diff --git a/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.jar b/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.jar index e6441136f..a4b76b953 100644 Binary files a/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.jar and b/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.properties b/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.properties index a4413138c..9355b4155 100644 --- a/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.properties +++ b/example/MultiplatformExample/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/example/MultiplatformExample/gradlew b/example/MultiplatformExample/gradlew index b740cf133..f5feea6d6 100755 --- a/example/MultiplatformExample/gradlew +++ b/example/MultiplatformExample/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/example/MultiplatformExample/gradlew.bat b/example/MultiplatformExample/gradlew.bat index 7101f8e46..9b42019c7 100644 --- a/example/MultiplatformExample/gradlew.bat +++ b/example/MultiplatformExample/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/example/MultiplatformExample/iosApp/Podfile.lock b/example/MultiplatformExample/iosApp/Podfile.lock index 11ec62e2d..919dca002 100644 --- a/example/MultiplatformExample/iosApp/Podfile.lock +++ b/example/MultiplatformExample/iosApp/Podfile.lock @@ -9,7 +9,7 @@ EXTERNAL SOURCES: :path: "../shared" SPEC CHECKSUMS: - shared: 2d3b24a8fe27b7d9e65b8d075a9672fbc6a1aa10 + shared: 90ed35de669e9fcb63a61e6b4bb0521eb732cc7a PODFILE CHECKSUM: f282da88f39e69507b0a255187c8a6b644477756 diff --git a/example/MultiplatformExample/person/build.gradle.kts b/example/MultiplatformExample/person/build.gradle.kts new file mode 100644 index 000000000..092634140 --- /dev/null +++ b/example/MultiplatformExample/person/build.gradle.kts @@ -0,0 +1,73 @@ +plugins { + kotlin("multiplatform") + id("com.android.library") + id("kotlinx-serialization") +} + +version = "1.0" +val ktorVersion = "2.3.11" + +kotlin { + jvmToolchain(8) + applyDefaultHierarchyTemplate() + + jvm() + androidTarget() + iosX64() + iosArm64() + iosSimulatorArm64() + macosX64() + js(IR) { + this.nodejs() + binaries.executable() + } + + sourceSets { + val commonMain by getting { + dependencies { + // Only needed when you want to use Kotlin Serialization + implementation("io.ktor:ktor-client-serialization:$ktorVersion") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val androidMain by getting + val jvmMain by getting + val jsMain by getting + val iosMain by getting + val macosX64Main by getting + } +} + +android { + compileSdk = 34 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 21 + targetSdk = 34 + namespace = "com.example.person" + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +tasks.withType { + kotlinOptions { + jvmTarget = "1.8" + allWarningsAsErrors = false + } +} + +allprojects { + repositories { + maven { + url = uri("https://oss.sonatype.org/content/repositories/snapshots/") + } + } +} diff --git a/example/MultiplatformExample/person/src/androidMain/AndroidManifest.xml b/example/MultiplatformExample/person/src/androidMain/AndroidManifest.xml new file mode 100644 index 000000000..b4adbb2cf --- /dev/null +++ b/example/MultiplatformExample/person/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/People.kt b/example/MultiplatformExample/person/src/commonMain/kotlin/com/example/ktorfittest/Person.kt similarity index 99% rename from example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/People.kt rename to example/MultiplatformExample/person/src/commonMain/kotlin/com/example/ktorfittest/Person.kt index ecf1764a2..10993cef6 100644 --- a/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/People.kt +++ b/example/MultiplatformExample/person/src/commonMain/kotlin/com/example/ktorfittest/Person.kt @@ -16,4 +16,3 @@ data class Person( val name: String? = null, val height: String? = null ) - diff --git a/example/MultiplatformExample/settings.gradle.kts b/example/MultiplatformExample/settings.gradle.kts index 020bc916a..23937e29b 100644 --- a/example/MultiplatformExample/settings.gradle.kts +++ b/example/MultiplatformExample/settings.gradle.kts @@ -1,6 +1,6 @@ pluginManagement { repositories { - // mavenLocal() + mavenLocal() google() gradlePluginPortal() mavenCentral() @@ -13,4 +13,5 @@ pluginManagement { rootProject.name = "KtorfitMultiplatformExample" include(":androidApp") -include(":shared") \ No newline at end of file +include(":shared") +include(":person") diff --git a/example/MultiplatformExample/shared/build.gradle.kts b/example/MultiplatformExample/shared/build.gradle.kts index 231c42ae9..3bbca1145 100644 --- a/example/MultiplatformExample/shared/build.gradle.kts +++ b/example/MultiplatformExample/shared/build.gradle.kts @@ -4,7 +4,7 @@ plugins { kotlin("multiplatform") kotlin("native.cocoapods") id("com.android.library") - id("com.google.devtools.ksp") version "2.0.0-1.0.24" + id("com.google.devtools.ksp") version "2.0.20-1.0.24" id("kotlinx-serialization") id("de.jensklingenberg.ktorfit") version "2.0.1" } @@ -15,11 +15,10 @@ ktorfit { } version = "1.0" -val ktorVersion = "3.0.0-beta-2" +val ktorVersion = "2.3.11" val ktorfitVersion = "2.0.1" kotlin { - wasmJs() jvmToolchain(8) targetHierarchy.default() @@ -46,12 +45,13 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - implementation("de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2:$ktorfitVersion") + implementation(project(":person")) + implementation("de.jensklingenberg.ktorfit:ktorfit-lib:$ktorfitVersion") // implementation("de.jensklingenberg.ktorfit:ktorfit-lib-light:$ktorfitVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") - implementation("de.jensklingenberg.ktorfit:ktorfit-converters-response-ktor-3.0.0-beta-2:$ktorfitVersion") - implementation("de.jensklingenberg.ktorfit:ktorfit-converters-call-ktor-3.0.0-beta-2:$ktorfitVersion") - implementation("de.jensklingenberg.ktorfit:ktorfit-converters-flow-ktor-3.0.0-beta-2:$ktorfitVersion") + implementation("de.jensklingenberg.ktorfit:ktorfit-converters-response:$ktorfitVersion") + implementation("de.jensklingenberg.ktorfit:ktorfit-converters-call:$ktorfitVersion") + implementation("de.jensklingenberg.ktorfit:ktorfit-converters-flow:$ktorfitVersion") // Only needed when you want to use Kotlin Serialization implementation("io.ktor:ktor-client-serialization:$ktorVersion") @@ -76,9 +76,9 @@ android { compileSdk = 34 sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") defaultConfig { - namespace = "com.example.myapplication.shared" minSdk = 21 targetSdk = 34 + namespace = "com.example.ktorfittest" } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/example/MultiplatformExample/shared/shared.podspec b/example/MultiplatformExample/shared/shared.podspec index c043d7ee5..f7d96aa32 100644 --- a/example/MultiplatformExample/shared/shared.podspec +++ b/example/MultiplatformExample/shared/shared.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |spec| spec.summary = 'Some description for the Shared Module' spec.vendored_frameworks = 'build/cocoapods/framework/shared.framework' spec.libraries = 'c++' - spec.ios.deployment_target = '14.1' + spec.ios.deployment_target = '14.1' if !Dir.exist?('build/cocoapods/framework/shared.framework') || Dir.empty?('build/cocoapods/framework/shared.framework') @@ -22,6 +22,10 @@ Pod::Spec.new do |spec| Alternatively, proper pod installation is performed during Gradle sync in the IDE (if Podfile location is set)" end + spec.xcconfig = { + 'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO', + } + spec.pod_target_xcconfig = { 'KOTLIN_PROJECT_PATH' => ':shared', 'PRODUCT_MODULE_NAME' => 'shared', diff --git a/example/MultiplatformExample/shared/src/androidMain/kotlin/com/example/ktorfittest/Test.kt b/example/MultiplatformExample/shared/src/androidMain/kotlin/com/example/ktorfittest/Test.kt new file mode 100644 index 000000000..1cb08dc30 --- /dev/null +++ b/example/MultiplatformExample/shared/src/androidMain/kotlin/com/example/ktorfittest/Test.kt @@ -0,0 +1,11 @@ +package com.example.ktorfittest + +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Path + +interface Test { + @GET("people/{id}") + suspend fun getPeopleById( + @Path("id") id: Int + ): Person +} diff --git a/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/Greeting.kt b/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/Greeting.kt index b255e8c01..646652302 100644 --- a/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/Greeting.kt +++ b/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/Greeting.kt @@ -1,6 +1,5 @@ package com.example.ktorfittest - import de.jensklingenberg.ktorfit.converter.CallConverterFactory import de.jensklingenberg.ktorfit.converter.FlowConverterFactory import de.jensklingenberg.ktorfit.ktorfit @@ -12,30 +11,34 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.serialization.json.Json -val ktorfit = ktorfit { - baseUrl(StarWarsApi.baseUrl) - httpClient(HttpClient { - install(ContentNegotiation) { - json(Json { isLenient = true; ignoreUnknownKeys = true }) - } - }) - converterFactories( - FlowConverterFactory(), - CallConverterFactory() - ) -} - +val ktorfit = + ktorfit { + baseUrl(StarWarsApi.baseUrl) + httpClient( + HttpClient { + install(ContentNegotiation) { + json( + Json { + isLenient = true + ignoreUnknownKeys = true + } + ) + } + } + ) + converterFactories( + FlowConverterFactory(), + CallConverterFactory() + ) + } -val starWarsApi = ktorfit.createStarWarsApi() +val starWarsApi = ktorfit.create() class Greeting { fun greeting(): String { - loadData() return "Hello, ${Platform().platform}! Look in the LogCat" } - - } @OptIn(DelicateCoroutinesApi::class) @@ -44,4 +47,4 @@ fun loadData() { val response = starWarsApi.getPersonByIdResponse(3) println("Ktorfit:" + Platform().platform + ":" + response) } -} \ No newline at end of file +} diff --git a/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/StarWarsApi.kt b/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/StarWarsApi.kt index a65f02ee0..cad2d1ae2 100644 --- a/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/StarWarsApi.kt +++ b/example/MultiplatformExample/shared/src/commonMain/kotlin/com/example/ktorfittest/StarWarsApi.kt @@ -13,18 +13,29 @@ interface StarWarsApi { } @GET("people/{id}/") - suspend fun getPersonByIdResponse(@Path("id") peopleId: Int): Person + suspend fun getPersonByIdResponse( + @Path("id") peopleId: Int + ): Person @GET("people/{id}/") - fun getPeopleByIdFlowResponse(@Path("id") peopleId: Int, @Query("hello") world: String?): Flow + fun getPeopleByIdFlowResponse( + @Path("id") peopleId: Int, + @Query("hello") world: String? + ): Flow @GET("people/{id}/") - fun getPeopleByIdCallResponse(@Path("id") peopleId: Int): Call - + fun getPeopleByIdCallResponse( + @Path("id") peopleId: Int + ): Call @GET("people/{id}/") - fun queryTest(@Path("id") peopleId: Int, @Query("hello") world: String?): Call + fun queryTest( + @Path("id") peopleId: Int, + @Query("hello") world: String? + ): Call @GET("people/{id}/") - suspend fun getPersonResponse(@Path("id") personId: Int): Response -} \ No newline at end of file + suspend fun getPersonResponse( + @Path("id") personId: Int + ): Response +} diff --git a/example/MultiplatformExample/shared/src/jvmMain/kotlin/JvmExampleClass.kt b/example/MultiplatformExample/shared/src/jvmMain/kotlin/JvmExampleClass.kt index d28ccc2fa..e780320fa 100644 --- a/example/MultiplatformExample/shared/src/jvmMain/kotlin/JvmExampleClass.kt +++ b/example/MultiplatformExample/shared/src/jvmMain/kotlin/JvmExampleClass.kt @@ -4,25 +4,23 @@ import de.jensklingenberg.ktorfit.Callback import io.ktor.client.statement.* import kotlinx.coroutines.runBlocking - fun main() { - - starWarsApi.getPeopleByIdCallResponse(3).onExecute(object : Callback { - override fun onError(exception: Throwable) { - exception - } - - override fun onResponse(call: Person, response: HttpResponse) { - println("onResponse" + call) + starWarsApi.getPeopleByIdCallResponse(3).onExecute( + object : Callback { + override fun onError(exception: Throwable) { + } + + override fun onResponse( + call: Person, + response: HttpResponse + ) { + println("onResponse" + call) + } } - - }) + ) runBlocking { val response = starWarsApi.getPersonByIdResponse(3) println(response) - } - - -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7fbce7ed1..e3f3811b4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,33 +1,33 @@ [versions] autoService = "1.1.1" autoServiceKsp = "1.10" -binaryCompatibilityValidator = "0.14.0" +binaryCompatibilityValidator = "0.16.3" coroutines = "1.8.1" detekt = "1.23.6" junit = "4.13.2" -kctfork = "0.4.1" -kotlin = "2.0.0" +kctfork = "0.5.1" +kotlin = "2.0.20" kotlinPoet = "1.18.1" -kspVersion = "2.0.10-1.0.24" +kspVersion = "2.0.20-1.0.24" groupId = "de.jensklingenberg.ktorfit" -ktorfit = "2.0.1" -ktorfitKsp = "2.0.1-1.0.24" -ktorfitCompiler = "2.0.1-2.0.10" +ktorfit = "2.1.0" +ktorfitKsp = "2.1.0-1.0.24" +ktorfitCompiler = "2.1.0-2.0.20" ktorfitCallConverter = "2.0.1" ktorfitFlowConverter = "2.0.1" ktorfitResponseConverter = "2.0.1" -ktorfitGradle = "2.0.1" +ktorfitGradle = "2.1.0" -ktorfitGradlePlugin = "2.0.0" +ktorfitGradlePlugin = "2.0.1" ktorVersion = "3.0.0-beta-2" -mockk = "1.13.11" +mockk = "1.13.12" mockito-kotlin = "4.1.0" gradleMavenPublishPlugin = "0.28.0" vannikMavenPublish = "0.28.0" [libraries] -android-build-gradle = "com.android.tools.build:gradle:8.2.2" +android-build-gradle = "com.android.tools.build:gradle:8.5.2" auto-service-ksp = { module = "dev.zacsweers.autoservice:auto-service-ksp", version.ref = "autoServiceKsp" } autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } gradle-maven-publish-plugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "gradleMavenPublishPlugin" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f..a4b76b953 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..9355b4155 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf133..f5feea6d6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 7101f8e46..9b42019c7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/ktorfit-annotations/src/androidMain/AndroidManifest.xml b/ktorfit-annotations/src/androidMain/AndroidManifest.xml index 568741e54..1d26c87a1 100644 --- a/ktorfit-annotations/src/androidMain/AndroidManifest.xml +++ b/ktorfit-annotations/src/androidMain/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/DELETE.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/DELETE.kt index d634eb093..6373fdfe4 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/DELETE.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/DELETE.kt @@ -10,4 +10,6 @@ package de.jensklingenberg.ktorfit.http * */ @Target(AnnotationTarget.FUNCTION) -annotation class DELETE(val value: String = "") +annotation class DELETE( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Field.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Field.kt index f2a842951..f4f33dbe5 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Field.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Field.kt @@ -8,4 +8,7 @@ package de.jensklingenberg.ktorfit.http * @see FieldMap */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Field(val value: String = "KTORFIT_DEFAULT_VALUE", val encoded: Boolean = false) +annotation class Field( + val value: String = "KTORFIT_DEFAULT_VALUE", + val encoded: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/FieldMap.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/FieldMap.kt index 32c8d11d9..94e0b42e0 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/FieldMap.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/FieldMap.kt @@ -5,4 +5,6 @@ package de.jensklingenberg.ktorfit.http * @param encoded true means that this value is already URL encoded and will not be encoded again */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class FieldMap(val encoded: Boolean = false) +annotation class FieldMap( + val encoded: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/GET.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/GET.kt index f036448fd..42bd9f0ac 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/GET.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/GET.kt @@ -8,4 +8,6 @@ package de.jensklingenberg.ktorfit.http * @param value relative url path, if empty, you need to have a parameter with [Url] * */ @Target(AnnotationTarget.FUNCTION) -annotation class GET(val value: String = "") +annotation class GET( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HEAD.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HEAD.kt index 25ea0854b..05d6a8def 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HEAD.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HEAD.kt @@ -4,4 +4,6 @@ package de.jensklingenberg.ktorfit.http * @param value relative url path, if empty, you need to have a parameter with [Url] * */ @Target(AnnotationTarget.FUNCTION) -annotation class HEAD(val value: String = "") +annotation class HEAD( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HTTP.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HTTP.kt index 3fefa9925..8961267cf 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HTTP.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/HTTP.kt @@ -10,4 +10,8 @@ package de.jensklingenberg.ktorfit.http * @param hasBody * */ @Target(AnnotationTarget.FUNCTION) -annotation class HTTP(val method: String, val path: String = "", val hasBody: Boolean = false) +annotation class HTTP( + val method: String, + val path: String = "", + val hasBody: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Header.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Header.kt index 9cdc57f2c..96a8f8f25 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Header.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Header.kt @@ -14,4 +14,6 @@ package de.jensklingenberg.ktorfit.http * @see HeaderMap */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Header(val value: String) +annotation class Header( + val value: String +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Headers.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Headers.kt index f5ca90ca5..27f3350a9 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Headers.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Headers.kt @@ -10,4 +10,6 @@ package de.jensklingenberg.ktorfit.http * ``` */ @Target(AnnotationTarget.FUNCTION) -annotation class Headers(vararg val value: String) +annotation class Headers( + vararg val value: String +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/OPTIONS.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/OPTIONS.kt index 2cc263152..9ea2d7c35 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/OPTIONS.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/OPTIONS.kt @@ -5,4 +5,6 @@ package de.jensklingenberg.ktorfit.http * @param value relative url path, if empty, you need to have a parameter with [Url] * */ @Target(AnnotationTarget.FUNCTION) -annotation class OPTIONS(val value: String = "") +annotation class OPTIONS( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PATCH.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PATCH.kt index a4dc9b318..01cbbb38d 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PATCH.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PATCH.kt @@ -9,4 +9,6 @@ package de.jensklingenberg.ktorfit.http * */ @Target(AnnotationTarget.FUNCTION) -annotation class PATCH(val value: String = "") +annotation class PATCH( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/POST.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/POST.kt index e7e25e4fd..ab19ffc55 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/POST.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/POST.kt @@ -9,4 +9,6 @@ package de.jensklingenberg.ktorfit.http * */ @Target(AnnotationTarget.FUNCTION) -annotation class POST(val value: String = "") +annotation class POST( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PUT.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PUT.kt index 4bc76c228..226dd60a4 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PUT.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PUT.kt @@ -9,4 +9,6 @@ package de.jensklingenberg.ktorfit.http * */ @Target(AnnotationTarget.FUNCTION) -annotation class PUT(val value: String = "") +annotation class PUT( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Part.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Part.kt index 4a3f84269..db6886c9f 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Part.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Part.kt @@ -11,4 +11,6 @@ package de.jensklingenberg.ktorfit.http * Part parameters type may not be nullable. */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Part(val value: String = "") +annotation class Part( + val value: String = "" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PartMap.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PartMap.kt index 8ce38bbef..94e2c15d5 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PartMap.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/PartMap.kt @@ -4,4 +4,6 @@ package de.jensklingenberg.ktorfit.http * If the type is List the value will be used directly with its content type. */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class PartMap(val encoding: String = "binary") +annotation class PartMap( + val encoding: String = "binary" +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Path.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Path.kt index c95d06925..88c8938a8 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Path.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Path.kt @@ -17,4 +17,7 @@ package de.jensklingenberg.ktorfit.http */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Path(val value: String = "KTORFIT_DEFAULT_VALUE", val encoded: Boolean = false) +annotation class Path( + val value: String = "KTORFIT_DEFAULT_VALUE", + val encoded: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Query.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Query.kt index e7476250c..e0ca1b2e1 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Query.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Query.kt @@ -21,4 +21,7 @@ package de.jensklingenberg.ktorfit.http * @param encoded true means that this value is already URL encoded and will not be encoded again */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Query(val value: String = "KTORFIT_DEFAULT_VALUE", val encoded: Boolean = false) +annotation class Query( + val value: String = "KTORFIT_DEFAULT_VALUE", + val encoded: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryMap.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryMap.kt index 6e9aba91a..c89694be0 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryMap.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryMap.kt @@ -8,4 +8,6 @@ package de.jensklingenberg.ktorfit.http */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class QueryMap(val encoded: Boolean = false) +annotation class QueryMap( + val encoded: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryName.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryName.kt index 83c64004d..fec887302 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryName.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/QueryName.kt @@ -5,4 +5,6 @@ package de.jensklingenberg.ktorfit.http * @param encoded true means that this value is already URL encoded and will not be encoded again */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class QueryName(val encoded: Boolean = false) +annotation class QueryName( + val encoded: Boolean = false +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/RequestType.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/RequestType.kt index 8511437f2..a9c3c39c6 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/RequestType.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/RequestType.kt @@ -3,4 +3,6 @@ package de.jensklingenberg.ktorfit.http import kotlin.reflect.KClass @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class RequestType(val requestType: KClass<*>) +annotation class RequestType( + val requestType: KClass<*> +) diff --git a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Tag.kt b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Tag.kt index 4c053591b..ac4dc64b2 100644 --- a/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Tag.kt +++ b/ktorfit-annotations/src/commonMain/kotlin/de/jensklingenberg/ktorfit/http/Tag.kt @@ -14,4 +14,6 @@ package de.jensklingenberg.ktorfit.http * */ @Target(AnnotationTarget.VALUE_PARAMETER) -annotation class Tag(val value: String = "KTORFIT_DEFAULT_VALUE") +annotation class Tag( + val value: String = "KTORFIT_DEFAULT_VALUE" +) diff --git a/ktorfit-compiler-plugin/src/main/java/de/jensklingenberg/ktorfit/CreateFuncTransformer.kt b/ktorfit-compiler-plugin/src/main/java/de/jensklingenberg/ktorfit/CreateFuncTransformer.kt index 0d0ed6aed..5f2f4764a 100644 --- a/ktorfit-compiler-plugin/src/main/java/de/jensklingenberg/ktorfit/CreateFuncTransformer.kt +++ b/ktorfit-compiler-plugin/src/main/java/de/jensklingenberg/ktorfit/CreateFuncTransformer.kt @@ -2,15 +2,17 @@ package de.jensklingenberg.ktorfit import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI import org.jetbrains.kotlin.ir.types.classFqName import org.jetbrains.kotlin.ir.types.defaultType -import org.jetbrains.kotlin.ir.types.impl.originalKotlinType import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.dumpKotlinLike import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.js.descriptorUtils.getKotlinTypeFqName import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -42,10 +44,15 @@ internal class CreateFuncTransformer( // Find exampleKtorfit.create() (expression as? IrCall)?.let { irCall -> if (irCall.typeArgumentsCount > 0) { - if (!expression.symbol.owner.symbol.toString().contains(KTORFIT_PACKAGE)) { + if (!expression.symbol.owner.symbol + .toString() + .contains(KTORFIT_PACKAGE) + ) { return expression } - if (expression.symbol.owner.name.asString() != KTORFIT_CREATE) { + if (expression.symbol.owner.name + .asString() != KTORFIT_CREATE + ) { return expression } @@ -59,12 +66,14 @@ internal class CreateFuncTransformer( if (!argumentType.isInterface()) { throw IllegalStateException( - errorTypeArgumentNotInterface(argumentType.originalKotlinType.toString()), + errorTypeArgumentNotInterface(argumentType.dumpKotlinLike()), ) } if (classFqName == null) { - throw IllegalStateException(errorClassNotFound(argumentType.originalKotlinType.toString())) + throw IllegalStateException( + errorClassNotFound(argumentType.toIrBasedKotlinType().getKotlinTypeFqName(false)) + ) } val packageName = classFqName.packageName @@ -98,7 +107,9 @@ internal class CreateFuncTransformer( // Set _ExampleApiProvider() as argument for create() irCall.putValueArgument(0, newCall) debugLogger.log( - "Transformed " + argumentType.originalKotlinType.toString() + " to _$className" + "Provider", + "Transformed " + argumentType.toIrBasedKotlinType().getKotlinTypeFqName(false).substringAfterLast(".") + + " to _$className" + + "Provider", ) return super.visitExpression(irCall) } diff --git a/ktorfit-compiler-plugin/src/test/kotlin/de/jensklingenberg/ktorfit/FunctionTransformerTest.kt b/ktorfit-compiler-plugin/src/test/kotlin/de/jensklingenberg/ktorfit/FunctionTransformerTest.kt index 6d26310ec..acbfa97a1 100644 --- a/ktorfit-compiler-plugin/src/test/kotlin/de/jensklingenberg/ktorfit/FunctionTransformerTest.kt +++ b/ktorfit-compiler-plugin/src/test/kotlin/de/jensklingenberg/ktorfit/FunctionTransformerTest.kt @@ -4,6 +4,7 @@ import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.PluginOption import com.tschuchort.compiletesting.SourceFile +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi import org.jetbrains.kotlin.config.JvmTarget import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue @@ -11,6 +12,7 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder +@OptIn(ExperimentalCompilerApi::class) class FunctionTransformerTest { @Rule @JvmField @@ -59,7 +61,7 @@ interface ClassProvider assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode) - assertTrue(result.messages.contains("_TestServiceImpl")) + assertTrue(result.messages.contains("_TestServiceProvider")) } @Test @@ -109,8 +111,9 @@ fun Ktorfit.create(ktorfitService: ClassProvider? = null): T { assertTrue(result.messages.contains(CreateFuncTransformer.errorTypeArgumentNotInterface("T"))) } - private fun prepareCompilation(sourceFiles: List): KotlinCompilation { - return KotlinCompilation().apply { + private fun prepareCompilation(sourceFiles: List): KotlinCompilation = + KotlinCompilation().apply { + languageVersion = "1.9" workingDir = temporaryFolder.root compilerPluginRegistrars = listOf(CommonCompilerPluginRegistrar()) val processor = ExampleCommandLineProcessor() @@ -126,9 +129,6 @@ fun Ktorfit.create(ktorfitService: ClassProvider? = null): T { jvmTarget = JvmTarget.fromString(System.getProperty("rdt.jvmTarget", "1.8"))!!.description supportsK2 = false } - } - private fun compile(sourceFiles: List): JvmCompilationResult { - return prepareCompilation(sourceFiles).compile() - } + private fun compile(sourceFiles: List): JvmCompilationResult = prepareCompilation(sourceFiles).compile() } diff --git a/ktorfit-converters/call/src/jvmTest/kotlin/ConverterTest.kt b/ktorfit-converters/call/src/jvmTest/kotlin/ConverterDefaultResponseConverter.kt similarity index 96% rename from ktorfit-converters/call/src/jvmTest/kotlin/ConverterTest.kt rename to ktorfit-converters/call/src/jvmTest/kotlin/ConverterDefaultResponseConverter.kt index dfc3df12a..6d71b277e 100644 --- a/ktorfit-converters/call/src/jvmTest/kotlin/ConverterTest.kt +++ b/ktorfit-converters/call/src/jvmTest/kotlin/ConverterDefaultResponseConverter.kt @@ -19,7 +19,7 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull -class ConverterTest { +class ConverterDefaultResponseConverter { @Test fun whenCallConverterIsUsedThenRespondSuccessful() = runBlocking { @@ -39,7 +39,8 @@ class ConverterTest { val responseFunc = suspend { client.request("http://example.org/") } val converter = CallConverterFactory() val ktor = - Ktorfit.Builder() + Ktorfit + .Builder() .baseUrl("http://example.org/") .httpClient(client) .build() diff --git a/ktorfit-gradle-plugin/src/main/java/de/jensklingenberg/ktorfit/gradle/KtorfitGradlePlugin.kt b/ktorfit-gradle-plugin/src/main/java/de/jensklingenberg/ktorfit/gradle/KtorfitGradlePlugin.kt index a2390aae4..91e31b4de 100644 --- a/ktorfit-gradle-plugin/src/main/java/de/jensklingenberg/ktorfit/gradle/KtorfitGradlePlugin.kt +++ b/ktorfit-gradle-plugin/src/main/java/de/jensklingenberg/ktorfit/gradle/KtorfitGradlePlugin.kt @@ -2,10 +2,10 @@ package de.jensklingenberg.ktorfit.gradle import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.kotlin.dsl.dependencies import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.targets import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask import java.util.Locale.US @@ -15,10 +15,10 @@ class KtorfitGradlePlugin : Plugin { const val GROUP_NAME = "de.jensklingenberg.ktorfit" const val ARTIFACT_NAME = "compiler-plugin" const val COMPILER_PLUGIN_ID = "ktorfitPlugin" - const val KTORFIT_VERSION = "2.0.1" // remember to bump this version before any release! + const val KTORFIT_VERSION = "2.1.0" // remember to bump this version before any release! const val SNAPSHOT = "" const val MIN_KSP_VERSION = "1.0.24" - const val MIN_KOTLIN_VERSION = "2.0.0" + const val MIN_KOTLIN_VERSION = "2.0.20" } override fun apply(project: Project) { @@ -42,7 +42,6 @@ class KtorfitGradlePlugin : Plugin { .substringBefore(".jar") checkKSPVersion(kspVersion) - val kspExtension = extensions.findByName("ksp") ?: error("KSP config not found") val argMethod = kspExtension.javaClass.getMethod("arg", String::class.java, String::class.java) @@ -55,8 +54,29 @@ class KtorfitGradlePlugin : Plugin { "Ktorfit_QualifiedTypeName", config.generateQualifiedTypeName.toString(), ) - } + /** + * This is currently a workaround for a bug in KSP that causes the plugin + * to not work with multiplatform projects with only one target. + * https://github.com/google/ksp/issues/1525 + */ + val singleTarget = + project.kotlinExtension.targets + .toList() + .size == 2 + + if (kotlinExtension is KotlinMultiplatformExtension) { + if (singleTarget) { + argMethod.invoke(kspExtension, "Ktorfit_MultiplatformWithSingleTarget", true.toString()) + } else { + tasks.withType(KotlinCompilationTask::class.java).configureEach { + if (name != "kspCommonMainKotlinMetadata") { + dependsOn("kspCommonMainKotlinMetadata") + } + } + } + } + } val dependency = "$ktorfitKsp:$KTORFIT_VERSION-$kspVersion$SNAPSHOT" when (val kotlinExtension = kotlinExtension) { @@ -65,52 +85,31 @@ class KtorfitGradlePlugin : Plugin { } is KotlinMultiplatformExtension -> { - dependencies { - add("kspCommonMainMetadata", dependency) - } - kotlinExtension.targets.configureEach { - if (targetName == "metadata") return@configureEach - dependencies.add( - "ksp${ - targetName.replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase( - US, - ) - } else { - it.toString() - } - } - }", - dependency, - ) - - dependencies.add( - "ksp${ - targetName.replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase( - US, - ) - } else { - it.toString() - } + if (platformType.name == "common") { + dependencies.add("kspCommonMainMetadata", dependency) + return@configureEach + } + val capitalizedTargetName = + targetName.replaceFirstChar { + if (it.isLowerCase()) { + it.titlecase( + US, + ) + } else { + it.toString() } - }Test", - dependency, - ) + } + dependencies.add("ksp$capitalizedTargetName", dependency) + + if (this.compilations.any { it.name == "test" }) { + dependencies.add("ksp${capitalizedTargetName}Test", dependency) + } } kotlinExtension.sourceSets.named("commonMain").configure { kotlin.srcDir("${layout.buildDirectory.get()}/generated/ksp/metadata/commonMain/kotlin") } - - tasks.withType(KotlinCompilationTask::class.java).configureEach { - if (name != "kspCommonMainKotlinMetadata") { - dependsOn("kspCommonMainKotlinMetadata") - } - } } else -> Unit diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitLogger.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitLogger.kt index 7c2e8ae0e..9ebaa8446 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitLogger.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitLogger.kt @@ -3,7 +3,10 @@ package de.jensklingenberg.ktorfit import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.symbol.KSNode -class KtorfitLogger(private val kspLogger: KSPLogger, private val loggingType: Int) : KSPLogger by kspLogger { +class KtorfitLogger( + private val kspLogger: KSPLogger, + private val loggingType: Int +) : KSPLogger by kspLogger { override fun error( message: String, symbol: KSNode?, diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitOptions.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitOptions.kt index 6fde82809..b71652702 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitOptions.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitOptions.kt @@ -1,6 +1,8 @@ package de.jensklingenberg.ktorfit -class KtorfitOptions(options: Map) { +class KtorfitOptions( + options: Map +) { /** * 0: Turn off all Ktorfit related error checking * @@ -14,4 +16,9 @@ class KtorfitOptions(options: Map) { * If set to true, the generated code will contain qualified type names */ val setQualifiedType = options["Ktorfit_QualifiedTypeName"]?.toBoolean() ?: false + + /** + * If the compilation is multiplatform and has only one target, this will be true + */ + val multiplatformWithSingleTarget = options["Ktorfit_MultiplatformWithSingleTarget"]?.toBoolean() ?: false } diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitProcessor.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitProcessor.kt index 39723b9bb..d33fd9d0d 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitProcessor.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/KtorfitProcessor.kt @@ -19,13 +19,14 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.model.toClassData class KtorfitProcessorProvider : SymbolProcessorProvider { - override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { - return KtorfitProcessor(environment, KtorfitOptions(environment.options)) - } + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = + KtorfitProcessor(environment, KtorfitOptions(environment.options)) } -class KtorfitProcessor(private val env: SymbolProcessorEnvironment, private val ktorfitOptions: KtorfitOptions) : - SymbolProcessor { +class KtorfitProcessor( + private val env: SymbolProcessorEnvironment, + private val ktorfitOptions: KtorfitOptions +) : SymbolProcessor { private var invoked = false companion object { diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/generator/ClassGenerator.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/generator/ClassGenerator.kt index b0440b95f..413fa2ea3 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/generator/ClassGenerator.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/generator/ClassGenerator.kt @@ -17,7 +17,7 @@ fun generateImplClass( classDataList: List, codeGenerator: CodeGenerator, resolver: Resolver, - ktorfitOptions: KtorfitOptions, + ktorfitOptions: KtorfitOptions ) { classDataList.forEach { classData -> with(classData) { @@ -32,13 +32,15 @@ fun generateImplClass( "" } - if (moduleName.contains(commonMainModuleName)) { - if (!ksFile.filePath.contains(commonMainModuleName)) { - return@forEach - } - } else { - if (ksFile.filePath.contains(commonMainModuleName)) { - return@forEach + if (!ktorfitOptions.multiplatformWithSingleTarget) { + if (moduleName.contains(commonMainModuleName)) { + if (!ksFile.filePath.contains(commonMainModuleName)) { + return@forEach + } + } else { + if (ksFile.filePath.contains(commonMainModuleName)) { + return@forEach + } } } diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/FunctionData.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/FunctionData.kt index 575dcc4db..b1d5b54eb 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/FunctionData.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/FunctionData.kt @@ -2,7 +2,6 @@ package de.jensklingenberg.ktorfit.model import com.google.devtools.ksp.processing.KSPLogger import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import de.jensklingenberg.ktorfit.model.annotations.CustomHttp import de.jensklingenberg.ktorfit.model.annotations.FunctionAnnotation import de.jensklingenberg.ktorfit.model.annotations.HttpMethod import de.jensklingenberg.ktorfit.model.annotations.HttpMethodAnnotation @@ -53,7 +52,8 @@ fun KSFunctionDeclaration.toFunctionData(logger: KSPLogger): FunctionData { val functionName = funcDeclaration.simpleName.asString() val functionParameters = funcDeclaration.parameters.map { it.createParameterData(logger) } - val resolvedReturnType = funcDeclaration.returnType?.resolve() ?: throw IllegalStateException("Return type not found") + val resolvedReturnType = + funcDeclaration.returnType?.resolve() ?: throw IllegalStateException("Return type not found") val returnType = ReturnTypeData( @@ -152,12 +152,6 @@ fun KSFunctionDeclaration.toFunctionData(logger: KSPLogger): FunctionData { when (firstHttpMethodAnnotation.httpMethod) { HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH -> {} else -> { - if (firstHttpMethodAnnotation is CustomHttp && firstHttpMethodAnnotation.hasBody) { - // Do nothing - } else if (functionParameters.any { it.hasAnnotation() }) { - logger.error(KtorfitError.NON_BODY_HTTP_METHOD_CANNOT_CONTAIN_BODY, funcDeclaration) - } - if (functionAnnotationList.anyInstance()) { logger.error( KtorfitError.MULTIPART_CAN_ONLY_BE_SPECIFIED_ON_HTTPMETHODS, diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/KtorfitError.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/KtorfitError.kt index 74f0b7de4..85511f1e7 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/KtorfitError.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/KtorfitError.kt @@ -25,7 +25,6 @@ internal class KtorfitError { 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 = diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/annotations/FunctionAnnotation.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/annotations/FunctionAnnotation.kt index 32e35b7d7..bf5bbe509 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/annotations/FunctionAnnotation.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/model/annotations/FunctionAnnotation.kt @@ -1,6 +1,8 @@ package de.jensklingenberg.ktorfit.model.annotations -enum class HttpMethod(val keyword: String) { +enum class HttpMethod( + val keyword: String +) { GET("GET"), POST("POST"), PUT("PUT"), @@ -15,7 +17,9 @@ enum class HttpMethod(val keyword: String) { */ open class FunctionAnnotation -class Headers(val value: List) : FunctionAnnotation() +class Headers( + val value: List +) : FunctionAnnotation() class FormUrlEncoded : FunctionAnnotation() diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/AttributeCodeGenerator.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/AttributeCodeGenerator.kt index c019e00e2..8688358ee 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/AttributeCodeGenerator.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/AttributeCodeGenerator.kt @@ -7,7 +7,9 @@ fun getAttributeCode(parameterDataList: List): String = parameterDataList .filter { it.hasAnnotation() } .joinToString("\n") { - val tag = it.findAnnotationOrNull() ?: throw IllegalStateException("Tag annotation not found") + val tag = + it.findAnnotationOrNull() + ?: throw IllegalStateException("Tag annotation not found") if (it.type.parameterType.isMarkedNullable) { "${it.name}?.let{ attributes.put(io.ktor.util.AttributeKey(\"${tag.value}\"), it) }" } else { diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/BodyCodeGenerator.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/BodyCodeGenerator.kt index 8893a1e85..1679caed0 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/BodyCodeGenerator.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/BodyCodeGenerator.kt @@ -3,6 +3,10 @@ package de.jensklingenberg.ktorfit.reqBuilderExtension import de.jensklingenberg.ktorfit.model.ParameterData import de.jensklingenberg.ktorfit.model.annotations.ParameterAnnotation.Body -fun getBodyDataText(params: List): String { - return params.firstOrNull { it.hasAnnotation() }?.name?.let { "setBody($it)" }.orEmpty() -} +fun getBodyDataText(params: List): String = + params + .firstOrNull { + it.hasAnnotation() + }?.name + ?.let { "setBody($it)" } + .orEmpty() diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/CustomRequestBuilderCodeGeneration.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/CustomRequestBuilderCodeGeneration.kt index e78634679..cac2d3534 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/CustomRequestBuilderCodeGeneration.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/CustomRequestBuilderCodeGeneration.kt @@ -3,8 +3,9 @@ package de.jensklingenberg.ktorfit.reqBuilderExtension import de.jensklingenberg.ktorfit.model.ParameterData import de.jensklingenberg.ktorfit.model.annotations.ParameterAnnotation -fun getCustomRequestBuilderText(parameterDataList: List): String { - return parameterDataList.find { it.hasAnnotation() }?.let { - it.name + "(this)" - }.orEmpty() -} +fun getCustomRequestBuilderText(parameterDataList: List): String = + parameterDataList + .find { it.hasAnnotation() } + ?.let { + it.name + "(this)" + }.orEmpty() diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/UrlCodeGeneration.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/UrlCodeGeneration.kt index 424283e5e..e154730af 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/UrlCodeGeneration.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/reqBuilderExtension/UrlCodeGeneration.kt @@ -13,9 +13,11 @@ fun getUrlCode( ): String { var urlPath = methodAnnotation.path.ifEmpty { - params.firstOrNull { it.hasAnnotation() }?.let { - "\${${it.name}}" - }.orEmpty() + params + .firstOrNull { it.hasAnnotation() } + ?.let { + "\${${it.name}}" + }.orEmpty() } val baseUrl = diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/KSValueParameterExt.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/KSValueParameterExt.kt index 9d713c7ce..b34d62c49 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/KSValueParameterExt.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/KSValueParameterExt.kt @@ -128,11 +128,16 @@ fun KSValueParameter.getRequestTypeAnnotation(): RequestType? { val filteredAnnotations = this.annotations.filter { it.shortName.getShortName() == requestTypeClazz.simpleName && - it.annotationType.resolve().declaration.qualifiedName?.asString() == requestTypeClazz.qualifiedName + it.annotationType + .resolve() + .declaration.qualifiedName + ?.asString() == requestTypeClazz.qualifiedName } - return filteredAnnotations.mapNotNull { - it.arguments.map { arg -> - RequestType((arg.value as KSType)) + return filteredAnnotations + .mapNotNull { + it.arguments + .map { arg -> + RequestType((arg.value as KSType)) + }.firstOrNull() }.firstOrNull() - }.firstOrNull() } diff --git a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/Utils.kt b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/Utils.kt index aae786868..2d1ae72ee 100644 --- a/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/Utils.kt +++ b/ktorfit-ksp/src/main/kotlin/de/jensklingenberg/ktorfit/utils/Utils.kt @@ -10,28 +10,18 @@ fun KSType?.resolveTypeName(): String { return this.toString().removePrefix("[typealias ").removeSuffix("]") } -inline fun FunctionData.findAnnotationOrNull(): T? { - return this.annotations.firstOrNull { it is T } as? T -} +inline fun FunctionData.findAnnotationOrNull(): T? = this.annotations.firstOrNull { it is T } as? T -fun String.prefixIfNotEmpty(s: String): String { - return (s + this).takeIf { this.isNotEmpty() } ?: this -} +fun String.prefixIfNotEmpty(s: String): String = (s + this).takeIf { this.isNotEmpty() } ?: this -fun String.postfixIfNotEmpty(s: String): String { - return (this + s).takeIf { this.isNotEmpty() } ?: this -} +fun String.postfixIfNotEmpty(s: String): String = (this + s).takeIf { this.isNotEmpty() } ?: this fun String.surroundIfNotEmpty( prefix: String = "", postFix: String = "", -): String { - return this.prefixIfNotEmpty(prefix).postfixIfNotEmpty(postFix) -} +): String = this.prefixIfNotEmpty(prefix).postfixIfNotEmpty(postFix) -fun String.removeWhiteSpaces(): String { - return this.replace("\\s".toRegex(), "") -} +fun String.removeWhiteSpaces(): String = this.replace("\\s".toRegex(), "") fun FileSpec.Builder.addImports(imports: List): FileSpec.Builder { imports.forEach { @@ -47,10 +37,6 @@ fun FileSpec.Builder.addImports(imports: List): FileSpec.Builder { return this } -inline fun List<*>.anyInstance(): Boolean { - return this.filterIsInstance().isNotEmpty() -} +inline fun List<*>.anyInstance(): Boolean = this.filterIsInstance().isNotEmpty() -fun KSName?.safeString(): String { - return this?.asString() ?: "" -} +fun KSName?.safeString(): String = this?.asString() ?: "" diff --git a/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/BodyAnnotationsTest.kt b/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/BodyAnnotationsTest.kt index 1893f8742..01eb6392e 100644 --- a/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/BodyAnnotationsTest.kt +++ b/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/BodyAnnotationsTest.kt @@ -11,32 +11,6 @@ import org.junit.Test import java.io.File class BodyAnnotationsTest { - @Test - fun whenBodyUsedWithNonBodyMethod_ThrowCompilationError() { - val source = - SourceFile.kotlin( - "Source.kt", - """ - package com.example.api -import de.jensklingenberg.ktorfit.http.GET -import de.jensklingenberg.ktorfit.http.Body - -interface TestService { - - @GET("user") - suspend fun test(@Body id: String): String? - -} - """, - ) - - val compilation = getCompilation(listOf(source)) - - val result = compilation.compile() - assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, result.exitCode) - assertTrue(result.messages.contains(KtorfitError.NON_BODY_HTTP_METHOD_CANNOT_CONTAIN_BODY)) - } - @Test fun whenBodyUsedWithFormUrlEncoded_ThrowCompilationError() { val source = diff --git a/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/ReqBuilderAnnotationsTest.kt b/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/ReqBuilderAnnotationsTest.kt index a9226cd96..e916cb696 100644 --- a/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/ReqBuilderAnnotationsTest.kt +++ b/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/ReqBuilderAnnotationsTest.kt @@ -2,9 +2,7 @@ package de.jensklingenberg.ktorfit import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.SourceFile -import com.tschuchort.compiletesting.kspIncremental import com.tschuchort.compiletesting.kspSourcesDir -import com.tschuchort.compiletesting.symbolProcessorProviders import de.jensklingenberg.ktorfit.model.KtorfitError import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -79,13 +77,7 @@ interface TestService { val expectedRequestBuilderArgumentText = "builder(this)" - val compilation = - KotlinCompilation().apply { - sources = listOf(httpReqBuilderSource, source) - inheritClassPath = true - symbolProcessorProviders = listOf(KtorfitProcessorProvider()) - kspIncremental = true - } + val compilation = getCompilation(listOf(httpReqBuilderSource, source)) val result = compilation.compile() assertEquals(KotlinCompilation.ExitCode.OK, result.exitCode) @@ -120,13 +112,7 @@ interface TestService { """, ) - val compilation = - KotlinCompilation().apply { - sources = listOf(httpReqBuilderSource, source) - inheritClassPath = true - symbolProcessorProviders = listOf(KtorfitProcessorProvider()) - kspIncremental = true - } + val compilation = getCompilation(listOf(httpReqBuilderSource, source)) val result = compilation.compile() assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, result.exitCode) @@ -153,13 +139,7 @@ interface TestService { """, ) - val compilation = - KotlinCompilation().apply { - sources = listOf(httpReqBuilderSource, source) - inheritClassPath = true - symbolProcessorProviders = listOf(KtorfitProcessorProvider()) - kspIncremental = true - } + val compilation = getCompilation(listOf(httpReqBuilderSource, source)) val result = compilation.compile() assertEquals(KotlinCompilation.ExitCode.COMPILATION_ERROR, result.exitCode) diff --git a/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/Utils.kt b/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/Utils.kt index 5d339e688..4e6848c6b 100644 --- a/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/Utils.kt +++ b/ktorfit-ksp/src/test/kotlin/de/jensklingenberg/ktorfit/Utils.kt @@ -4,6 +4,7 @@ import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.SourceFile import com.tschuchort.compiletesting.kspArgs import com.tschuchort.compiletesting.kspIncremental +import com.tschuchort.compiletesting.kspProcessorOptions import com.tschuchort.compiletesting.symbolProcessorProviders import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi @@ -13,9 +14,10 @@ fun getCompilation( kspArgs: MutableMap = mutableMapOf(), ): KotlinCompilation = KotlinCompilation().apply { + languageVersion = "1.9" this.sources = sources inheritClassPath = true - symbolProcessorProviders = listOf(KtorfitProcessorProvider()) + symbolProcessorProviders = mutableListOf(KtorfitProcessorProvider()) kspIncremental = true - this.kspArgs = kspArgs + this.kspProcessorOptions = kspArgs } diff --git a/ktorfit-lib-core/api/android/ktorfit-lib-core.api b/ktorfit-lib-core/api/android/ktorfit-lib-core.api index f8270366c..f44ca7bfb 100644 --- a/ktorfit-lib-core/api/android/ktorfit-lib-core.api +++ b/ktorfit-lib-core/api/android/ktorfit-lib-core.api @@ -114,6 +114,13 @@ public final class de/jensklingenberg/ktorfit/converter/TypeData$Companion { public static synthetic fun createTypeData$default (Lde/jensklingenberg/ktorfit/converter/TypeData$Companion;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;ILjava/lang/Object;)Lde/jensklingenberg/ktorfit/converter/TypeData; } +public final class de/jensklingenberg/ktorfit/converter/builtin/DontSwallowExceptionsConverterFactory : de/jensklingenberg/ktorfit/converter/Converter$Factory { + public fun ()V + public fun requestParameterConverter (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;)Lde/jensklingenberg/ktorfit/converter/Converter$RequestParameterConverter; + public fun responseConverter (Lde/jensklingenberg/ktorfit/converter/TypeData;Lde/jensklingenberg/ktorfit/Ktorfit;)Lde/jensklingenberg/ktorfit/converter/Converter$ResponseConverter; + public fun suspendResponseConverter (Lde/jensklingenberg/ktorfit/converter/TypeData;Lde/jensklingenberg/ktorfit/Ktorfit;)Lde/jensklingenberg/ktorfit/converter/Converter$SuspendResponseConverter; +} + public abstract interface class de/jensklingenberg/ktorfit/internal/ClassProvider { public abstract fun create (Lde/jensklingenberg/ktorfit/Ktorfit;)Ljava/lang/Object; } diff --git a/ktorfit-lib-core/api/jvm/ktorfit-lib-core.api b/ktorfit-lib-core/api/jvm/ktorfit-lib-core.api index f8270366c..f44ca7bfb 100644 --- a/ktorfit-lib-core/api/jvm/ktorfit-lib-core.api +++ b/ktorfit-lib-core/api/jvm/ktorfit-lib-core.api @@ -114,6 +114,13 @@ public final class de/jensklingenberg/ktorfit/converter/TypeData$Companion { public static synthetic fun createTypeData$default (Lde/jensklingenberg/ktorfit/converter/TypeData$Companion;Ljava/lang/String;Lio/ktor/util/reflect/TypeInfo;ILjava/lang/Object;)Lde/jensklingenberg/ktorfit/converter/TypeData; } +public final class de/jensklingenberg/ktorfit/converter/builtin/DontSwallowExceptionsConverterFactory : de/jensklingenberg/ktorfit/converter/Converter$Factory { + public fun ()V + public fun requestParameterConverter (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;)Lde/jensklingenberg/ktorfit/converter/Converter$RequestParameterConverter; + public fun responseConverter (Lde/jensklingenberg/ktorfit/converter/TypeData;Lde/jensklingenberg/ktorfit/Ktorfit;)Lde/jensklingenberg/ktorfit/converter/Converter$ResponseConverter; + public fun suspendResponseConverter (Lde/jensklingenberg/ktorfit/converter/TypeData;Lde/jensklingenberg/ktorfit/Ktorfit;)Lde/jensklingenberg/ktorfit/converter/Converter$SuspendResponseConverter; +} + public abstract interface class de/jensklingenberg/ktorfit/internal/ClassProvider { public abstract fun create (Lde/jensklingenberg/ktorfit/Ktorfit;)Ljava/lang/Object; } diff --git a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/Ktorfit.kt b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/Ktorfit.kt index e7ebbffeb..3aa7be2eb 100644 --- a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/Ktorfit.kt +++ b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/Ktorfit.kt @@ -202,13 +202,12 @@ public class Ktorfit private constructor( /** * Creates an instance of Ktorfit with specified baseUrl and HttpClient. */ - public fun build(): Ktorfit { - return Ktorfit( + public fun build(): Ktorfit = + Ktorfit( baseUrl = _baseUrl, httpClient = _httpClient ?: HttpClient(), converterFactories = _factories.toList() + listOf(DefaultSuspendResponseConverterFactory()), ) - } } } diff --git a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/Converter.kt b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/Converter.kt index 2ee17b0cd..71a7e8b68 100644 --- a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/Converter.kt +++ b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/Converter.kt @@ -48,9 +48,7 @@ public interface Converter { public fun getUpperBoundType( index: Int, type: TypeData, - ): TypeData? { - return type.typeArgs[index] - } + ): TypeData? = type.typeArgs[index] public interface Factory { /** diff --git a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/KtorfitResult.kt b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/KtorfitResult.kt index 7969b8d3d..e9cecea8e 100644 --- a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/KtorfitResult.kt +++ b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/KtorfitResult.kt @@ -9,11 +9,15 @@ public sealed interface KtorfitResult { * Represents a successful response. * @property response The HTTP response. */ - public class Success(public val response: HttpResponse) : KtorfitResult + public class Success( + public val response: HttpResponse + ) : KtorfitResult /** * Represents a failed response. * @property throwable The throwable associated with the failure. */ - public class Failure(public val throwable: Throwable) : KtorfitResult + public class Failure( + public val throwable: Throwable + ) : KtorfitResult } diff --git a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DefaultSuspendResponseConverterFactory.kt b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DefaultSuspendResponseConverterFactory.kt index 9cd5351f5..a6652c58d 100644 --- a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DefaultSuspendResponseConverterFactory.kt +++ b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DefaultSuspendResponseConverterFactory.kt @@ -11,25 +11,41 @@ import io.ktor.client.statement.HttpResponse * It is automatically applied last */ internal class DefaultSuspendResponseConverterFactory : Converter.Factory { - class DefaultSuspendResponseConverter(val typeData: TypeData) : - Converter.SuspendResponseConverter { - override suspend fun convert(result: KtorfitResult): Any { - return when (result) { + class DefaultSuspendResponseConverter( + val typeData: TypeData + ) : Converter.SuspendResponseConverter { + override suspend fun convert(result: KtorfitResult): Any? = + when (result) { is KtorfitResult.Failure -> { - throw result.throwable + if (typeData.isNullable) { + null + } else { + throw result.throwable + } } is KtorfitResult.Success -> { result.response.call.body(typeData.typeInfo) } } - } + } + + class DefaultResponseConverter : Converter.ResponseConverter { + override fun convert(getResponse: suspend () -> HttpResponse): Any? = null } override fun suspendResponseConverter( typeData: TypeData, ktorfit: Ktorfit, - ): Converter.SuspendResponseConverter { - return DefaultSuspendResponseConverter(typeData) - } + ): Converter.SuspendResponseConverter = DefaultSuspendResponseConverter(typeData) + + override fun responseConverter( + typeData: TypeData, + ktorfit: Ktorfit, + ): Converter.ResponseConverter? = + if (typeData.isNullable) { + DefaultResponseConverter() + } else { + null + } } diff --git a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DontSwallowExceptionsConverterFactory.kt b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DontSwallowExceptionsConverterFactory.kt new file mode 100644 index 000000000..158144ccb --- /dev/null +++ b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/converter/builtin/DontSwallowExceptionsConverterFactory.kt @@ -0,0 +1,29 @@ +package de.jensklingenberg.ktorfit.converter.builtin + +import de.jensklingenberg.ktorfit.Ktorfit +import de.jensklingenberg.ktorfit.converter.Converter +import de.jensklingenberg.ktorfit.converter.KtorfitResult +import de.jensklingenberg.ktorfit.converter.TypeData +import io.ktor.client.statement.HttpResponse + +public class DontSwallowExceptionsConverterFactory : Converter.Factory { + private class DefaultSuspendResponseConverter( + val typeData: TypeData + ) : Converter.SuspendResponseConverter { + override suspend fun convert(result: KtorfitResult): Any? = + when (result) { + is KtorfitResult.Failure -> { + throw result.throwable + } + + is KtorfitResult.Success -> { + result.response.call.body(typeData.typeInfo) + } + } + } + + override fun suspendResponseConverter( + typeData: TypeData, + ktorfit: Ktorfit, + ): Converter.SuspendResponseConverter = DefaultSuspendResponseConverter(typeData) +} diff --git a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/internal/KtorfitConverterHelper.kt b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/internal/KtorfitConverterHelper.kt index cd8cd7a96..2c338f135 100644 --- a/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/internal/KtorfitConverterHelper.kt +++ b/ktorfit-lib-core/src/commonMain/kotlin/de/jensklingenberg/ktorfit/internal/KtorfitConverterHelper.kt @@ -17,7 +17,9 @@ import kotlin.reflect.cast * Cant make this internal because it is used by generated code */ @InternalKtorfitApi -public class KtorfitConverterHelper(private val ktorfit: Ktorfit) { +public class KtorfitConverterHelper( + private val ktorfit: Ktorfit +) { private val httpClient: HttpClient = ktorfit.httpClient /** @@ -39,12 +41,7 @@ public class KtorfitConverterHelper(private val ktorfit: Ktorfit) { } as ReturnType? } - val typeIsNullable = returnTypeData.typeInfo.kotlinType?.isMarkedNullable ?: false - return if (typeIsNullable) { - null - } else { - throw IllegalStateException("Add a ResponseConverter for " + returnTypeData.typeInfo + " or make function suspend") - } + throw IllegalStateException("Add a ResponseConverter for " + returnTypeData.typeInfo + " or make function suspend") } /** @@ -55,36 +52,27 @@ public class KtorfitConverterHelper(private val ktorfit: Ktorfit) { typeData: TypeData, requestBuilder: HttpRequestBuilder.() -> Unit, ): ReturnType? { - try { - if (typeData.typeInfo.type == HttpStatement::class) { - return httpClient.prepareRequest { - requestBuilder(this) - } as ReturnType - } - - ktorfit.nextSuspendResponseConverter(null, typeData)?.let { - val result: KtorfitResult = - try { - KtorfitResult.Success( - httpClient.request { - requestBuilder(this) - }, - ) - } catch (exception: Exception) { - KtorfitResult.Failure(exception) - } - return it.convert(result) as ReturnType? - } + if (typeData.typeInfo.type == HttpStatement::class) { + return httpClient.prepareRequest { + requestBuilder(this) + } as ReturnType + } - throw IllegalStateException("No SuspendResponseConverter found to convert ${typeData.typeInfo}") - } catch (exception: Exception) { - val typeIsNullable = typeData.typeInfo.kotlinType?.isMarkedNullable ?: false - return if (typeIsNullable) { - null - } else { - throw exception - } + ktorfit.nextSuspendResponseConverter(null, typeData)?.let { + val result: KtorfitResult = + try { + KtorfitResult.Success( + httpClient.request { + requestBuilder(this) + }, + ) + } catch (throwable: Throwable) { + KtorfitResult.Failure(throwable) + } + return it.convert(result) as ReturnType? } + + throw IllegalStateException("No SuspendResponseConverter found to convert ${typeData.typeInfo}") } public fun convertParameterType( diff --git a/ktorfit-lib-core/src/commonTest/kotlin/de/jensklingenberg/ktorfit/KtorfitTest.kt b/ktorfit-lib-core/src/commonTest/kotlin/de/jensklingenberg/ktorfit/KtorfitTest.kt index eacda5384..3830dee6e 100644 --- a/ktorfit-lib-core/src/commonTest/kotlin/de/jensklingenberg/ktorfit/KtorfitTest.kt +++ b/ktorfit-lib-core/src/commonTest/kotlin/de/jensklingenberg/ktorfit/KtorfitTest.kt @@ -7,9 +7,7 @@ import de.jensklingenberg.ktorfit.converter.builtin.DefaultSuspendResponseConver import io.ktor.client.request.HttpRequestData import io.ktor.client.statement.HttpResponse import io.ktor.util.reflect.typeInfo -import kotlin.test.Ignore import kotlin.test.Test -import kotlin.test.assertEquals import kotlin.test.assertTrue class KtorfitTest { @@ -22,7 +20,8 @@ class KtorfitTest { } val ktorfit = - Ktorfit.Builder() + Ktorfit + .Builder() .httpClient(engine) .baseUrl("http://test.de/") .converterFactories(TestConverterFactory()) @@ -36,11 +35,18 @@ class KtorfitTest { assertTrue(nextConverter is TestConverterFactory.SuspendConverter) } - @Ignore() // "Will be activated when old converters are removed" @Test fun whenNoSuspendResponseConverterForStringAdded_FindDefaultConverter() { + val engine = + object : TestEngine() { + override fun getRequestData(data: HttpRequestData) { + } + } + val ktorfit = - Ktorfit.Builder() + Ktorfit + .Builder() + .httpClient(engine) .baseUrl("http://test.de/") .build() @@ -61,7 +67,8 @@ class KtorfitTest { } val ktorfit = - Ktorfit.Builder() + Ktorfit + .Builder() .httpClient(engine) .baseUrl("http://test.de/") .converterFactories(TestConverterFactory()) @@ -81,19 +88,22 @@ class KtorfitTest { } val ktorfit = - Ktorfit.Builder() + Ktorfit + .Builder() .httpClient(engine) .baseUrl("http://test.de/") .build() val nextConverter = ktorfit.nextResponseConverter(null, TypeData("kotlin.String", emptyList(), isNullable = true, typeInfo = typeInfo())) - assertEquals(null, nextConverter) + assertTrue(nextConverter is DefaultSuspendResponseConverterFactory.DefaultResponseConverter) } } private class TestConverterFactory : Converter.Factory { - class SuspendConverter(val typeData: TypeData) : Converter.SuspendResponseConverter { + class SuspendConverter( + val typeData: TypeData + ) : Converter.SuspendResponseConverter { override suspend fun convert(result: KtorfitResult): Any { when (result) { is KtorfitResult.Success -> { @@ -107,9 +117,7 @@ private class TestConverterFactory : Converter.Factory { } class ResponseConverter : Converter.ResponseConverter { - override fun convert(getKtorfitResponse: suspend () -> HttpResponse): Any { - return "" - } + override fun convert(getKtorfitResponse: suspend () -> HttpResponse): Any = "" } override fun suspendResponseConverter( diff --git a/ktorfit-lib-core/src/jvmTest/kotlin/de/jensklingenberg/ktorfit/BuilderTest.kt b/ktorfit-lib-core/src/jvmTest/kotlin/de/jensklingenberg/ktorfit/BuilderDefaultResponseConverter.kt similarity index 98% rename from ktorfit-lib-core/src/jvmTest/kotlin/de/jensklingenberg/ktorfit/BuilderTest.kt rename to ktorfit-lib-core/src/jvmTest/kotlin/de/jensklingenberg/ktorfit/BuilderDefaultResponseConverter.kt index 694d1466c..f8e7cb3b5 100644 --- a/ktorfit-lib-core/src/jvmTest/kotlin/de/jensklingenberg/ktorfit/BuilderTest.kt +++ b/ktorfit-lib-core/src/jvmTest/kotlin/de/jensklingenberg/ktorfit/BuilderDefaultResponseConverter.kt @@ -14,7 +14,7 @@ interface BuilderTestApi { suspend fun checkIfBaseUrlIsSetWhenUrlCheckIsDisabled(): String } -class BuilderTest { +class BuilderDefaultResponseConverter { @Test fun whenBaseUrlNotEndingWithSlashThrowError() { try { diff --git a/mkdocs.yml b/mkdocs.yml index e41b29cf2..b982427be 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,15 +7,15 @@ docs_dir: 'docs' edit_uri: 'tree/master/docs/' # Copyright -copyright: Copyright © Apache v2 License 2022-2023 Jens Klingenberg +copyright: Copyright © Apache v2 License 2022-2024 Jens Klingenberg extra: manifest: manifest.webmanifest site: images: '../../images' ktorfit: - release: "2.0.1" + release: "2.1.0" ktor: - release: "2.3.11" + release: "2.3.12" social: - icon: fontawesome/brands/github-alt link: 'https://github.com/foso' @@ -64,6 +64,9 @@ nav: - 'Example1': converters/example1.md - 'Migration': converters/migration.md - 'Configuration': configuration.md + - 'Android': + - 'proguard': android/proguard.md + - 'Known issues': knownissues.md - 'Fundamentals' : - 'Scope' : fundamentals/scope.md - 'Architecture': architecture.md diff --git a/sandbox/build.gradle.kts b/sandbox/build.gradle.kts index f64a27ab1..b0edb7a44 100644 --- a/sandbox/build.gradle.kts +++ b/sandbox/build.gradle.kts @@ -83,8 +83,7 @@ kotlin { dependencies { implementation(libs.ktor.client.core.jvm) - implementation(libs.kotlinx.coroutines.rx3) - implementation("io.reactivex.rxjava3:rxjava:3.1.8") + implementation("ch.qos.logback:logback-classic:1.2.3") implementation(libs.ktor.client.logging) implementation(libs.ktor.serialization.gson) implementation(libs.ktor.client.cio.jvm) diff --git a/sandbox/src/commonMain/kotlin/com/example/UserFactory.kt b/sandbox/src/commonMain/kotlin/com/example/UserFactory.kt index ef9fb16da..87d99ff70 100644 --- a/sandbox/src/commonMain/kotlin/com/example/UserFactory.kt +++ b/sandbox/src/commonMain/kotlin/com/example/UserFactory.kt @@ -10,21 +10,20 @@ import io.ktor.client.call.* import io.ktor.client.statement.* class UserFactory : Converter.Factory { - override fun suspendResponseConverter( typeData: TypeData, ktorfit: Ktorfit ): Converter.SuspendResponseConverter? { if (typeData.typeInfo.type == User::class) { return object : Converter.SuspendResponseConverter { - override suspend fun convert(result: KtorfitResult): Any { - when (result) { + when (result) { is KtorfitResult.Success -> { val response = result.response val envelope = response.body() return envelope.user } + is KtorfitResult.Failure -> { throw result.throwable } diff --git a/sandbox/src/commonMain/kotlin/com/example/api/GithubService.kt b/sandbox/src/commonMain/kotlin/com/example/api/GithubService.kt index 53f2b16be..a44da5bdb 100644 --- a/sandbox/src/commonMain/kotlin/com/example/api/GithubService.kt +++ b/sandbox/src/commonMain/kotlin/com/example/api/GithubService.kt @@ -4,11 +4,15 @@ import com.example.model.github.GithubFollowerResponseItem import com.example.model.github.Issuedata import com.example.model.github.TestReeeItem import de.jensklingenberg.ktorfit.Call -import de.jensklingenberg.ktorfit.http.* +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.Headers +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow interface GithubService { - companion object { const val baseUrl = "https://api.github.com/" } @@ -19,10 +23,16 @@ interface GithubService { "Content-Type: application/json" ) @POST("repos/foso/experimental/issues") - suspend fun createIssue(@Body body: Map<*,String>, @Header("Acci") headi: String?): String + suspend fun createIssue( + @Body body: Map<*, String>, + @Header("Acci") headi: String? + ): String @POST("repos/foso/experimental/issues") - suspend fun createIssue2(@Body body: Issuedata, @Header("Acci") headi: String?): Call> + suspend fun createIssue2( + @Body body: Issuedata, + @Header("Acci") headi: String? + ): Call> @Headers( "Accept: application/vnd.github.v3+json", @@ -38,6 +48,8 @@ interface GithubService { "Content-Type: application/json" ) @GET("repos/{owner}/{repo}/commits") - fun listCommits(@Path owner: String, @Path repo: String): Flow> - + fun listCommits( + @Path owner: String, + @Path repo: String + ): Flow> } diff --git a/sandbox/src/commonMain/kotlin/com/example/api/JsonPlaceHolderApi.kt b/sandbox/src/commonMain/kotlin/com/example/api/JsonPlaceHolderApi.kt index 0ce342cf5..0e5aa7391 100644 --- a/sandbox/src/commonMain/kotlin/com/example/api/JsonPlaceHolderApi.kt +++ b/sandbox/src/commonMain/kotlin/com/example/api/JsonPlaceHolderApi.kt @@ -11,7 +11,6 @@ import kotlinx.coroutines.Deferred import kotlinx.coroutines.flow.Flow interface JsonPlaceHolderApi { - companion object { const val baseUrl = "https://jsonplaceholder.typicode.com/" } @@ -22,7 +21,7 @@ interface JsonPlaceHolderApi { @GET("posts") fun callPosts(): Call> - @HTTP("GET2","posts") + @HTTP("GET2", "posts") fun callPostsCustomHttp(): Call> @GET("posts") @@ -30,31 +29,48 @@ interface JsonPlaceHolderApi { @Streaming @GET("docs/response.html#streaming") - suspend fun getPostsStreaming(@QueryMap test: Map): HttpStatement + suspend fun getPostsStreaming( + @QueryMap test: Map + ): HttpStatement @GET("posts/{postId}") - suspend fun getPostById(@Path postId: Int = 4): Post + suspend fun getPostById( + @Path postId: Int = 4 + ): Post @GET("posts/{postId}/comments") - fun getFlowCommentsByPostId(@Path("postId") postId: Int, @ReqBuilder builder : HttpRequestBuilder.() -> Unit): Flow>? + fun getFlowCommentsByPostId( + @Path("postId") postId: Int, + @ReqBuilder builder: HttpRequestBuilder.() -> Unit + ): Flow>? @GET("posts/{postId}/comments") - suspend fun getCommentsByPostId(@Path("postId") postId: Int): List? + suspend fun getCommentsByPostId( + @Path("postId") postId: Int + ): List? @GET("posts/{postId}/comments") - suspend fun getCommentsByPostIdResponse(@RequestType(Int::class) @Path("postId") postId: String): MyOwnResponse> + suspend fun getCommentsByPostIdResponse( + @RequestType(Int::class) @Path("postId") postId: String + ): MyOwnResponse> @Headers(value = ["Content-Type: application/json"]) @GET("posts/{postId}/comments") - fun callCommentsByPostId(@Path("postId") postId: Int): Call> + fun callCommentsByPostId( + @Path("postId") postId: Int + ): Call> @Headers(value = ["Content-Type: application/json"]) @GET("posts/{postId}/comments") - suspend fun resCommentsByPostId(@Path("postId") postId: Int): Response> + suspend fun resCommentsByPostId( + @Path("postId") postId: Int + ): Response> @Headers(value = ["Content-Type: application/json"]) @GET("posts/{postId}/comments") - fun deferedCommentsByPostId(@Path("postId") postId: Int): Deferred> + fun deferedCommentsByPostId( + @Path("postId") postId: Int + ): Deferred> @Headers(value = ["Content-Type: application/json"]) @GET("comments") @@ -64,19 +80,25 @@ interface JsonPlaceHolderApi { @Headers(value = ["Content-Type: application/json"]) @POST("posts") - suspend fun postPosts(@Body post: Post): Post + suspend fun postPosts( + @Body post: Post + ): Post @Headers(value = ["Content-Type: application/json"]) @POST("posts") - suspend fun putPosts(@Body post: Post): Post + suspend fun putPosts( + @Body post: Post + ): Post @Headers(value = ["Content-Type: application/json"]) @PATCH("posts/{postId}/{number}") - suspend fun patchPosts(@Path("postId") postId: Int): Post + suspend fun patchPosts( + @Path("postId") postId: Int + ): Post @Headers(value = ["Content-Type: application/json"]) @DELETE("posts/{postId}") - suspend fun deletePosts(@Path("postId") postId: Int): String - + suspend fun deletePosts( + @Path("postId") postId: Int + ): String } - diff --git a/sandbox/src/commonMain/kotlin/com/example/api/KtorSamplesApi.kt b/sandbox/src/commonMain/kotlin/com/example/api/KtorSamplesApi.kt index 283c024e1..0cb551dd5 100644 --- a/sandbox/src/commonMain/kotlin/com/example/api/KtorSamplesApi.kt +++ b/sandbox/src/commonMain/kotlin/com/example/api/KtorSamplesApi.kt @@ -10,7 +10,6 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable interface KtorSamplesApi { - companion object { const val baseUrl = "http://localhost:8080/" } @@ -20,9 +19,11 @@ interface KtorSamplesApi { val test1: String @POST("signup") - suspend fun sendReg(@Body param: Parameters): String + suspend fun sendReg( + @Body param: Parameters + ): String - //client-submit-form + // client-submit-form @POST("signup") @FormUrlEncoded suspend fun signup( @@ -31,11 +32,9 @@ interface KtorSamplesApi { @Field("password") password: String, @Field("confirmation") confirmation: String, @Field("names") names: List - ): String - - //client-submit-form + // client-submit-form @POST("signup") @FormUrlEncoded suspend fun signup( @@ -45,35 +44,43 @@ interface KtorSamplesApi { @Multipart @POST("upload") - suspend fun uploadFile(@Part("description") description: String, @Part("list") file: List,@PartMap() map : Map): String + suspend fun uploadFile( + @Part("description") description: String, + @Part("list") file: List, + @PartMap() map: Map + ): String @POST("upload") - suspend fun upload(@Body map: MultiPartFormDataContent) + suspend fun upload( + @Body map: MultiPartFormDataContent + ) } - data class Query( val working: Working ) { data class Working( - val data: String + val data: String ) - data class NotWorking( - val reponse: String + val reponse: String ) } - interface API { - data class JensTest(val names: List) + data class JensTest( + val names: List + ) @Headers( - "Content-Type: application/json", "Accept: application/json" + "Content-Type: application/json", + "Accept: application/json" ) @POST("example/request") - suspend fun query(@Body query: Query): List // not sure if non-list works, haven't tested + suspend fun query( + @Body query: Query + ): List // not sure if non-list works, haven't tested } class KtorfitTest { @@ -87,4 +94,4 @@ class KtorfitTest { interface ITest { @GET("test") fun test(): KtorfitTest.TestData -} \ No newline at end of file +} diff --git a/sandbox/src/commonMain/kotlin/com/example/api/Response.kt b/sandbox/src/commonMain/kotlin/com/example/api/Response.kt index 889cae8cc..93b947e26 100644 --- a/sandbox/src/commonMain/kotlin/com/example/api/Response.kt +++ b/sandbox/src/commonMain/kotlin/com/example/api/Response.kt @@ -1,11 +1,17 @@ package com.example.api sealed class Response { - data class Success(val data: T) : Response() - class Error(val ex:Throwable) : Response() + data class Success( + val data: T + ) : Response() + + class Error( + val ex: Throwable + ) : Response() companion object { fun success(data: T) = Success(data) + fun error(ex: Throwable) = Error(ex) } } diff --git a/sandbox/src/commonMain/kotlin/com/example/api/StarWarsApi.kt b/sandbox/src/commonMain/kotlin/com/example/api/StarWarsApi.kt index 57edb3ea8..4ba91f5e0 100644 --- a/sandbox/src/commonMain/kotlin/com/example/api/StarWarsApi.kt +++ b/sandbox/src/commonMain/kotlin/com/example/api/StarWarsApi.kt @@ -6,12 +6,12 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path interface StarWarsApi { - - companion object{ + companion object { const val baseUrl = "https://swapi.dev/api/" } @GET("people/{id}/") - fun getPersonById(@Path("id") peopleId: Int): Call + fun getPersonById( + @Path("id") peopleId: Int + ): Call } - diff --git a/sandbox/src/commonMain/kotlin/com/example/model/CommonClient.kt b/sandbox/src/commonMain/kotlin/com/example/model/CommonClient.kt index 7b97c2d5e..613774f58 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/CommonClient.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/CommonClient.kt @@ -9,26 +9,28 @@ import io.ktor.client.plugins.contentnegotiation.* import io.ktor.serialization.kotlinx.json.* import kotlinx.serialization.json.Json - -val commonClient = HttpClient() { - - install(ContentNegotiation) { - json(Json { isLenient = true; ignoreUnknownKeys = true }) +val commonClient = + HttpClient { + + install(ContentNegotiation) { + json( + Json { + isLenient = true + ignoreUnknownKeys = true + } + ) + } } -} - - - -val commonKtorfit = ktorfit { - baseUrl(JsonPlaceHolderApi.baseUrl) - httpClient(commonClient) - converterFactories( - CallConverterFactory(), - StringToIntRequestConverterFactory(), - MyOwnResponseConverterFactory() - ) -} +val commonKtorfit = + ktorfit { + baseUrl(JsonPlaceHolderApi.baseUrl) + httpClient(commonClient) + converterFactories( + CallConverterFactory(), + StringToIntRequestConverterFactory(), + MyOwnResponseConverterFactory() + ) + } val jsonPlaceHolderApi = commonKtorfit.createJsonPlaceHolderApi() - diff --git a/sandbox/src/commonMain/kotlin/com/example/model/Envelope.kt b/sandbox/src/commonMain/kotlin/com/example/model/Envelope.kt index 5fd2635f6..bb5c4f0ec 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/Envelope.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/Envelope.kt @@ -1,7 +1,13 @@ package com.example.model @kotlinx.serialization.Serializable -data class Envelope(val success: Boolean, val user: User) +data class Envelope( + val success: Boolean, + val user: User +) @kotlinx.serialization.Serializable -data class User(val id: Int, val name: String) \ No newline at end of file +data class User( + val id: Int, + val name: String +) diff --git a/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponse.kt b/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponse.kt index 29f8051ef..bd99ef81d 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponse.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponse.kt @@ -4,11 +4,17 @@ import kotlinx.serialization.Serializable @Serializable sealed class MyOwnResponse { - data class Success(val data: T) : MyOwnResponse() - class Error(val ex: Throwable) : MyOwnResponse() + data class Success( + val data: T + ) : MyOwnResponse() + + class Error( + val ex: Throwable + ) : MyOwnResponse() companion object { fun success(data: T) = Success(data) + fun error(ex: Throwable) = Error(ex) } -} \ No newline at end of file +} diff --git a/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponseConverter.kt b/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponseConverterFactory.kt similarity index 72% rename from sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponseConverter.kt rename to sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponseConverterFactory.kt index b8d056ab8..33a039b6a 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponseConverter.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/MyOwnResponseConverterFactory.kt @@ -4,20 +4,16 @@ import de.jensklingenberg.ktorfit.Ktorfit import de.jensklingenberg.ktorfit.converter.Converter import de.jensklingenberg.ktorfit.converter.KtorfitResult import de.jensklingenberg.ktorfit.converter.TypeData -import io.ktor.client.call.* -import io.ktor.client.statement.* - +import io.ktor.client.call.body +import io.ktor.client.statement.HttpResponse class MyOwnResponseConverterFactory : Converter.Factory { - override fun suspendResponseConverter( typeData: TypeData, ktorfit: Ktorfit ): Converter.SuspendResponseConverter? { if (typeData.typeInfo.type == MyOwnResponse::class) { - return object : Converter.SuspendResponseConverter { - override suspend fun convert(result: KtorfitResult): Any { return when (result) { is KtorfitResult.Failure -> { @@ -27,11 +23,13 @@ class MyOwnResponseConverterFactory : Converter.Factory { is KtorfitResult.Success -> { val response = result.response return try { - val convertedBody = ktorfit.nextSuspendResponseConverter( - null, - typeData.typeArgs.first() - )?.convert(result) - ?: response.body(typeData.typeArgs.first().typeInfo) + val convertedBody = + ktorfit + .nextSuspendResponseConverter( + null, + typeData.typeArgs.first() + )?.convert(result) + ?: response.body(typeData.typeArgs.first().typeInfo) MyOwnResponse.success(convertedBody) } catch (ex: Throwable) { MyOwnResponse.error(ex) @@ -43,4 +41,4 @@ class MyOwnResponseConverterFactory : Converter.Factory { } return null } -} \ No newline at end of file +} diff --git a/sandbox/src/commonMain/kotlin/com/example/model/People.kt b/sandbox/src/commonMain/kotlin/com/example/model/People.kt index 817fb876c..0f3b13c02 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/People.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/People.kt @@ -1,7 +1,6 @@ package com.example.model @kotlinx.serialization.Serializable - data class People( val films: List? = null, val homeworld: String? = null, @@ -10,14 +9,13 @@ data class People( val edited: String? = null, val created: String? = null, val mass: String? = null, - //val vehicles: List? = null, + // val vehicles: List? = null, val url: String? = null, val hairColor: String? = null, val birthYear: String? = null, val eyeColor: String? = null, - //val species: List? = null, - //val starships: List? = null, + // val species: List? = null, + // val starships: List? = null, val name: String? = null, val height: String? = null ) - diff --git a/sandbox/src/commonMain/kotlin/com/example/model/Post.kt b/sandbox/src/commonMain/kotlin/com/example/model/Post.kt index f5afa4f30..3efc25c34 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/Post.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/Post.kt @@ -3,7 +3,18 @@ package com.example.model import kotlinx.serialization.Serializable @Serializable -data class Post(val userId: Int, val id: Int, val title: String, val body: String) +data class Post( + val userId: Int, + val id: Int, + val title: String, + val body: String +) @Serializable -data class Comment(val postId: Int, val id: Int, val name: String, val body: String, val email: String) +data class Comment( + val postId: Int, + val id: Int, + val name: String, + val body: String, + val email: String +) diff --git a/sandbox/src/commonMain/kotlin/com/example/model/Specie.kt b/sandbox/src/commonMain/kotlin/com/example/model/Specie.kt index b5f791f36..29e4fde9e 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/Specie.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/Specie.kt @@ -1,7 +1,6 @@ package com.example.model @kotlinx.serialization.Serializable - data class Specie( val films: List? = null, val skinColors: String? = null, @@ -19,4 +18,3 @@ data class Specie( val designation: String? = null, val averageLifespan: String? = null ) - diff --git a/sandbox/src/commonMain/kotlin/com/example/model/StringToIntRequestConverter.kt b/sandbox/src/commonMain/kotlin/com/example/model/StringToIntRequestConverter.kt index 6dd32cb86..47844b0c8 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/StringToIntRequestConverter.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/StringToIntRequestConverter.kt @@ -3,16 +3,15 @@ package com.example.model import de.jensklingenberg.ktorfit.converter.Converter import kotlin.reflect.KClass - class StringToIntRequestConverterFactory : Converter.Factory { - class StringToIntRequestConverter : Converter.RequestParameterConverter { - override fun convert(data: Any): Any { - return (data as String).toInt() - } + override fun convert(data: Any): Any = (data as String).toInt() } - private fun supportedType(parameterType: KClass<*>, requestType: KClass<*>): Boolean { + private fun supportedType( + parameterType: KClass<*>, + requestType: KClass<*> + ): Boolean { val parameterIsString = parameterType == String::class val requestIsInt = requestType == Int::class return parameterIsString && requestIsInt @@ -24,11 +23,9 @@ class StringToIntRequestConverterFactory : Converter.Factory { ): Converter.RequestParameterConverter? { if (supportedType(parameterType, requestType)) { return object : Converter.RequestParameterConverter { - override fun convert(data: Any): Any { - return (data as String).toInt() - } + override fun convert(data: Any): Any = (data as String).toInt() } } return null } -} \ No newline at end of file +} diff --git a/sandbox/src/commonMain/kotlin/com/example/model/github/GithubFollowerResponse.kt b/sandbox/src/commonMain/kotlin/com/example/model/github/GithubFollowerResponse.kt index c9f679c88..e28905e6b 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/github/GithubFollowerResponse.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/github/GithubFollowerResponse.kt @@ -2,23 +2,22 @@ package com.example.model.github @kotlinx.serialization.Serializable data class GithubFollowerResponseItem( - val gistsUrl: String? = null, - val reposUrl: String? = null, - val followingUrl: String? = null, - val starredUrl: String? = null, - val login: String? = null, - val followersUrl: String? = null, - val type: String? = null, - val url: String? = null, - val subscriptionsUrl: String? = null, - val receivedEventsUrl: String? = null, - val avatarUrl: String? = null, - val eventsUrl: String? = null, - val htmlUrl: String? = null, - val siteAdmin: Boolean? = null, - val id: Int? = null, - val gravatarId: String? = null, - val nodeId: String? = null, - val organizationsUrl: String? = null + val gistsUrl: String? = null, + val reposUrl: String? = null, + val followingUrl: String? = null, + val starredUrl: String? = null, + val login: String? = null, + val followersUrl: String? = null, + val type: String? = null, + val url: String? = null, + val subscriptionsUrl: String? = null, + val receivedEventsUrl: String? = null, + val avatarUrl: String? = null, + val eventsUrl: String? = null, + val htmlUrl: String? = null, + val siteAdmin: Boolean? = null, + val id: Int? = null, + val gravatarId: String? = null, + val nodeId: String? = null, + val organizationsUrl: String? = null ) - diff --git a/sandbox/src/commonMain/kotlin/com/example/model/github/Issuedata.kt b/sandbox/src/commonMain/kotlin/com/example/model/github/Issuedata.kt index b6dda7674..2ed441aaf 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/github/Issuedata.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/github/Issuedata.kt @@ -1,4 +1,7 @@ package com.example.model.github @kotlinx.serialization.Serializable -data class Issuedata(val title: String, val body: String) \ No newline at end of file +data class Issuedata( + val title: String, + val body: String +) diff --git a/sandbox/src/commonMain/kotlin/com/example/model/github/TestReee.kt b/sandbox/src/commonMain/kotlin/com/example/model/github/TestReee.kt index 801923123..389e8b8a4 100644 --- a/sandbox/src/commonMain/kotlin/com/example/model/github/TestReee.kt +++ b/sandbox/src/commonMain/kotlin/com/example/model/github/TestReee.kt @@ -1,96 +1,100 @@ package com.example.model.github data class TestReee( - val testReee: List? = null + val testReee: List? = null ) -@kotlinx.serialization.Serializable +@kotlinx.serialization.Serializable data class Author( - val date: String? = null, - val name: String? = null, - val email: String? = null, - val gistsUrl: String? = null, - val reposUrl: String? = null, - val followingUrl: String? = null, - val starredUrl: String? = null, - val login: String? = null, - val followersUrl: String? = null, - val type: String? = null, - val url: String? = null, - val subscriptionsUrl: String? = null, - val receivedEventsUrl: String? = null, - val avatarUrl: String? = null, - val eventsUrl: String? = null, - val htmlUrl: String? = null, - val siteAdmin: Boolean? = null, - val id: Int? = null, - val gravatarId: String? = null, - val nodeId: String? = null, - val organizationsUrl: String? = null + val date: String? = null, + val name: String? = null, + val email: String? = null, + val gistsUrl: String? = null, + val reposUrl: String? = null, + val followingUrl: String? = null, + val starredUrl: String? = null, + val login: String? = null, + val followersUrl: String? = null, + val type: String? = null, + val url: String? = null, + val subscriptionsUrl: String? = null, + val receivedEventsUrl: String? = null, + val avatarUrl: String? = null, + val eventsUrl: String? = null, + val htmlUrl: String? = null, + val siteAdmin: Boolean? = null, + val id: Int? = null, + val gravatarId: String? = null, + val nodeId: String? = null, + val organizationsUrl: String? = null ) -@kotlinx.serialization.Serializable +@kotlinx.serialization.Serializable data class Tree( - val sha: String? = null, - val url: String? = null + val sha: String? = null, + val url: String? = null ) + @kotlinx.serialization.Serializable data class TestReeeItem( - val committer: Committer? = null, - val author: Author? = null, - val htmlUrl: String? = null, - val commit: Commit? = null, - val commentsUrl: String? = null, - val sha: String? = null, - val url: String? = null, - val nodeId: String? = null, - val parents: List? = null + val committer: Committer? = null, + val author: Author? = null, + val htmlUrl: String? = null, + val commit: Commit? = null, + val commentsUrl: String? = null, + val sha: String? = null, + val url: String? = null, + val nodeId: String? = null, + val parents: List? = null ) + @kotlinx.serialization.Serializable data class Verification( - val reason: String? = null, - val signature: String? = null, - val payload: String? = null, - val verified: Boolean? = null + val reason: String? = null, + val signature: String? = null, + val payload: String? = null, + val verified: Boolean? = null ) + @kotlinx.serialization.Serializable data class Committer( - val date: String? = null, - val name: String? = null, - val email: String? = null, - val gistsUrl: String? = null, - val reposUrl: String? = null, - val followingUrl: String? = null, - val starredUrl: String? = null, - val login: String? = null, - val followersUrl: String? = null, - val type: String? = null, - val url: String? = null, - val subscriptionsUrl: String? = null, - val receivedEventsUrl: String? = null, - val avatarUrl: String? = null, - val eventsUrl: String? = null, - val htmlUrl: String? = null, - val siteAdmin: Boolean? = null, - val id: Int? = null, - val gravatarId: String? = null, - val nodeId: String? = null, - val organizationsUrl: String? = null + val date: String? = null, + val name: String? = null, + val email: String? = null, + val gistsUrl: String? = null, + val reposUrl: String? = null, + val followingUrl: String? = null, + val starredUrl: String? = null, + val login: String? = null, + val followersUrl: String? = null, + val type: String? = null, + val url: String? = null, + val subscriptionsUrl: String? = null, + val receivedEventsUrl: String? = null, + val avatarUrl: String? = null, + val eventsUrl: String? = null, + val htmlUrl: String? = null, + val siteAdmin: Boolean? = null, + val id: Int? = null, + val gravatarId: String? = null, + val nodeId: String? = null, + val organizationsUrl: String? = null ) + @kotlinx.serialization.Serializable data class ParentsItem( - val htmlUrl: String? = null, - val sha: String? = null, - val url: String? = null + val htmlUrl: String? = null, + val sha: String? = null, + val url: String? = null ) + @kotlinx.serialization.Serializable data class Commit( - val commentCount: Int? = null, - val committer: Committer? = null, - val author: Author? = null, - val tree: Tree? = null, - val message: String? = null, - val url: String? = null, - val verification: Verification? = null + val commentCount: Int? = null, + val committer: Committer? = null, + val author: Author? = null, + val tree: Tree? = null, + val message: String? = null, + val url: String? = null, + val verification: Verification? = null ) - diff --git a/sandbox/src/jsMain/kotlin/JsMain.kt b/sandbox/src/jsMain/kotlin/JsMain.kt index dcdb1181c..7c41327a9 100644 --- a/sandbox/src/jsMain/kotlin/JsMain.kt +++ b/sandbox/src/jsMain/kotlin/JsMain.kt @@ -1,5 +1,3 @@ - - import com.example.model.Comment import com.example.model.MyOwnResponse import com.example.model.jsonPlaceHolderApi @@ -7,15 +5,13 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch - fun main() { - GlobalScope.launch { println("Launch") when (val test = jsonPlaceHolderApi.getCommentsByPostIdResponse("3")) { is MyOwnResponse.Success -> { - val list = test.data as List + val list = test.data as List println(list.size) } @@ -26,9 +22,5 @@ fun main() { } delay(3000) - } - - } - diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/CreateIssue.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/CreateIssue.kt index ea665c2b6..71be0d292 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/CreateIssue.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/CreateIssue.kt @@ -10,40 +10,36 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.Json - fun main() { - - val jvmClient = HttpClient() { - install(ContentNegotiation) { - - json(Json { isLenient = true; ignoreUnknownKeys = true; }) + val jvmClient = + HttpClient { + install(ContentNegotiation) { + json( + Json { + isLenient = true + ignoreUnknownKeys = true + } + ) + } + expectSuccess = false } - expectSuccess = false - - - } - - val jvmKtorfit = ktorfit { - baseUrl(GithubService.baseUrl) - httpClient(jvmClient) - } + val jvmKtorfit = + ktorfit { + baseUrl(GithubService.baseUrl) + httpClient(jvmClient) + } val testApi = jvmKtorfit.createGithubService() - runBlocking { - - testApi.listCommits("foso","Experimental").collect{ + testApi.listCommits("foso", "Experimental").collect { println(it.first().author) } - - // println( testApi.createIsseu(Issuedata("hey","ho"))) -//BODY {"title":"title","body":"This is a test"} - // BODY Issuedata(title=Hallo, body=hhhh) + // println( testApi.createIsseu(Issuedata("hey","ho"))) +// BODY {"title":"title","body":"This is a test"} + // BODY Issuedata(title=Hallo, body=hhhh) delay(3000) - } - -} \ No newline at end of file +} diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/HeaderTestApi.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/HeaderTestApi.kt index bffe751f3..1a6953395 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/HeaderTestApi.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/HeaderTestApi.kt @@ -1,26 +1,41 @@ package de.jensklingenberg.ktorfit.demo import com.example.model.People -import de.jensklingenberg.ktorfit.http.* +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Header +import de.jensklingenberg.ktorfit.http.HeaderMap +import de.jensklingenberg.ktorfit.http.Headers +import de.jensklingenberg.ktorfit.http.Path interface HeaderTestApi { - @GET("people/{id}/") - suspend fun multipleHeader(@Path("id") peopleId: Int, @Header("huhu") name: Array,@Header("hey") name2: String): People + suspend fun multipleHeader( + @Path("id") peopleId: Int, + @Header("huhu") name: Array, + @Header("hey") name2: String + ): People @GET("people/{id}/") - suspend fun testHeaderWithArray(@Path("id") peopleId: Int, @Header("huhu") name: Array): People + suspend fun testHeaderWithArray( + @Path("id") peopleId: Int, + @Header("huhu") name: Array + ): People @GET("people/{id}/") - suspend fun testHeaderWithList(@Path("id") peopleId: Int, @Header("huhu") name: List): People - + suspend fun testHeaderWithList( + @Path("id") peopleId: Int, + @Header("huhu") name: List + ): People - @Headers("Accept2: application/json","Accept: application/json2") + @Headers("Accept2: application/json", "Accept: application/json2") @GET("people/{id}/") - suspend fun testHeaders(@Path("id") peopleId: Int ): People + suspend fun testHeaders( + @Path("id") peopleId: Int + ): People @GET("people/{id}/") - suspend fun testHeaderMap(@Path("id") peopleId: Int, @HeaderMap() name: Map?): People - - -} \ No newline at end of file + suspend fun testHeaderMap( + @Path("id") peopleId: Int, + @HeaderMap() name: Map? + ): People +} diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvMMain.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvMMain.kt index 8e4de637e..9a82704e4 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvMMain.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvMMain.kt @@ -1,15 +1,11 @@ package de.jensklingenberg.ktorfit.demo - import com.example.UserFactory -import com.example.api.API import com.example.api.JsonPlaceHolderApi -import com.example.api._APIImpl import com.example.model.ExampleApi import com.example.model.MyOwnResponse import com.example.model.MyOwnResponseConverterFactory import com.example.model.createExampleApi -import de.jensklingenberg.ktorfit.Ktorfit import de.jensklingenberg.ktorfit.converter.CallConverterFactory import de.jensklingenberg.ktorfit.converter.FlowConverterFactory import de.jensklingenberg.ktorfit.ktorfit @@ -23,60 +19,60 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.serialization.json.Json +val jvmClient = + HttpClient { -val jvmClient = HttpClient { + install(Logging) { + // level = LogLevel.ALL + } - install(Logging) { - //level = LogLevel.ALL - } + install(ContentNegotiation) { + json( + Json { + isLenient = true + ignoreUnknownKeys = true + } + ) + } - install(ContentNegotiation) { - json(Json { isLenient = true; ignoreUnknownKeys = true }) + this.developmentMode = true + expectSuccess = false } - this.developmentMode = true - expectSuccess = false -} - - -val jvmKtorfit = ktorfit { - baseUrl(JsonPlaceHolderApi.baseUrl) - httpClient(jvmClient) - -} - - -val userKtorfit = ktorfit { - baseUrl("https://foso.github.io/Ktorfit/") - httpClient(jvmClient) +val jvmKtorfit = + ktorfit { + baseUrl(JsonPlaceHolderApi.baseUrl) + httpClient(jvmClient) + } - converterFactories( - FlowConverterFactory(), - MyOwnResponseConverterFactory(), - UserFactory(), - CallConverterFactory() - ) -} +val userKtorfit = + ktorfit { + baseUrl("https://foso.github.io/Ktorfit/") + httpClient(jvmClient) + + converterFactories( + FlowConverterFactory(), + MyOwnResponseConverterFactory(), + UserFactory(), + CallConverterFactory() + ) + } -val api : ExampleApi = userKtorfit.createExampleApi() +val api: ExampleApi = userKtorfit.createExampleApi() fun main() { - runBlocking { - val user = api.getUserResponse() when (user) { is MyOwnResponse.Success -> { - println(user.data) + System.out.println(user.data) } is MyOwnResponse.Error<*> -> { - println(user.ex) + System.out.println(user.ex) } } delay(3000) } - } - diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvmPlaceHolderApi.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvmPlaceHolderApi.kt index 2bdb9b061..557558191 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvmPlaceHolderApi.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/JvmPlaceHolderApi.kt @@ -8,31 +8,48 @@ import de.jensklingenberg.ktorfit.http.* import io.ktor.client.statement.* internal interface JvmPlaceHolderApi : StarWarsApi { - @GET("people/{id}/") - suspend fun getPersonById2(@Path("id") peopleId: Int): People + suspend fun getPersonById2( + @Path("id") peopleId: Int + ): People @GET("people/{id}/") - suspend fun testQuery(@Path("id") peopleId: Int, @Query world: String? = "World"): People + suspend fun testQuery( + @Path("id") peopleId: Int, + @Query world: String? = "World" + ): People @GET("people/{id}/") - suspend fun testQueryName(@Path("id") peopleId: Int, @QueryName na : List?): People + suspend fun testQueryName( + @Path("id") peopleId: Int, + @QueryName na: List? + ): People @GET("people/{id}/") - suspend fun testQueryName2(@Path("id") peopleId: Int, @QueryName na : Map?, @QueryMap na2 : Map?): People + suspend fun testQueryName2( + @Path("id") peopleId: Int, + @QueryName na: Map?, + @QueryMap na2: Map? + ): People @Streaming @GET("people/1/") suspend fun getPostsStreaming(): HttpStatement @GET("people/{id}/") - fun getPersonById2AsResponse(@Path("id") peopleId: Int): Response + fun getPersonById2AsResponse( + @Path("id") peopleId: Int + ): Response @Headers(value = ["Content-Type: application/json"]) - @GET("people/{id}/") - suspend fun callPersonById2AsResponse(@Path("id") peopleId: Int): Call> + suspend fun callPersonById2AsResponse( + @Path("id") peopleId: Int + ): Call> @GET() - suspend fun getPersonByIdByUrl(@Url peopleId: String, @QueryMap name: Map?): People -} \ No newline at end of file + suspend fun getPersonByIdByUrl( + @Url peopleId: String, + @QueryMap name: Map? + ): People +} diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/QueryTestApi.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/QueryTestApi.kt index ed9614afd..76aae9eba 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/QueryTestApi.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/QueryTestApi.kt @@ -1,11 +1,13 @@ package de.jensklingenberg.ktorfit.demo import com.example.model.People -import de.jensklingenberg.ktorfit.http.* -import ktorfit.Test +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query +import de.jensklingenberg.ktorfit.http.QueryMap +import de.jensklingenberg.ktorfit.http.QueryName interface QueryTestApi { - @GET("people/{id}/") suspend fun testQueryWithEncodedString( @Path("id") peopleId: Int, @@ -14,25 +16,46 @@ interface QueryTestApi { ): People @GET("people/{id}/") - suspend fun testQueryWithEncodedInt(@Path("id") peopleId: Int, @Query("huhu", true) name: Int): People + suspend fun testQueryWithEncodedInt( + @Path("id") peopleId: Int, + @Query("huhu", true) name: Int + ): People @GET("people/{id}/") - suspend fun testQueryWithString(@Path("id") peopleId: Int, @Query("huhu", false) name: String): People + suspend fun testQueryWithString( + @Path("id") peopleId: Int, + @Query("huhu", false) name: String + ): People @GET("people/{id}/") - suspend fun testQueryWithEncodedArray(@Path("id") peopleId: Int, @Query("huhu", true) name: Array): People + suspend fun testQueryWithEncodedArray( + @Path("id") peopleId: Int, + @Query("huhu", true) name: Array + ): People @GET("people/{id}/") - suspend fun testQueryWithList(@Path("id") peopleId: Int, @Query("huhu") name: List): People + suspend fun testQueryWithList( + @Path("id") peopleId: Int, + @Query("huhu") name: List + ): People @GET("people/{id}/") - suspend fun testQueryWithEncodedList(@Path("id") peopleId: Int, @Query("huhu", true) name: List): People + suspend fun testQueryWithEncodedList( + @Path("id") peopleId: Int, + @Query("huhu", true) name: List + ): People @GET("people/{id}/") - suspend fun testQueryName(@Path("id") peopleId: Int, @QueryName name: String): People + suspend fun testQueryName( + @Path("id") peopleId: Int, + @QueryName name: String + ): People @GET("people/{id}/") - suspend fun testQueryNameList(@Path("id") peopleId: Int, @QueryName(false) name: List): People + suspend fun testQueryNameList( + @Path("id") peopleId: Int, + @QueryName(false) name: List + ): People @GET("people/{id}/") suspend fun testQueryEncodedMap( @@ -40,6 +63,4 @@ interface QueryTestApi { @QueryMap name: Map?, @QueryMap(true) name2: Map? ): People - - -} \ No newline at end of file +} diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi.kt index 64de238ba..b0cbef91f 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi.kt @@ -2,41 +2,39 @@ package de.jensklingenberg.ktorfit.demo import com.example.model.Post import de.jensklingenberg.ktorfit.Call -import de.jensklingenberg.ktorfit.http.* -import io.ktor.client.request.forms.* -import io.reactivex.rxjava3.core.Observable +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Headers +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path +import io.ktor.client.request.forms.MultiPartFormDataContent import kotlinx.coroutines.flow.Flow - - - -interface TestApi { - +interface TestApi { @GET("pos4ts") fun getPosts(): Call> @GET("posts/{userId}") - suspend fun getPost(@Path("userId") myUserId: Int = 4): Post + suspend fun getPost( + @Path("userId") myUserId: Int = 4 + ): Post @POST("posts") - suspend fun postPost(@Body otherID: Post): Post + suspend fun postPost( + @Body otherID: Post + ): Post @GET("posts/{userId}") - suspend fun getPostsByUserId(@Path("userId") myUserId: Int): List + suspend fun getPostsByUserId( + @Path("userId") myUserId: Int + ): List @Headers(value = ["Accept: application/json"]) @GET("posts") fun getFlowPosts(): Flow> - @POST("upload") - suspend fun uppi(@Body map: MultiPartFormDataContent) - - @Headers(value = ["Accept: application/json"]) - @GET("posts") - fun getObserPosts(): Observable> - - - + suspend fun uppi( + @Body map: MultiPartFormDataContent + ) } - diff --git a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi2.kt b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi2.kt index 9b8e9b55f..54091ce50 100644 --- a/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi2.kt +++ b/sandbox/src/jvmMain/kotlin/de/jensklingenberg/ktorfit/demo/TestApi2.kt @@ -1,4 +1,4 @@ -package ktorfit +package de.jensklingenberg.ktorfit.demo import com.example.api.StarWarsApi import com.example.model.People @@ -6,22 +6,27 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import de.jensklingenberg.ktorfit.http.QueryName -interface TestApi2 : StarWarsApi, QueryNameTestApi { +interface TestApi2 : + StarWarsApi, + QueryNameTestApi { @GET("people/{id}/") fun tste() - } -data class Test(val name: String) - +data class Test( + val name: String +) interface QueryNameTestApi { - @GET("people/{id}/") - suspend fun testQueryName(@Path("id") peopleId: Int, @QueryName name: String): People + suspend fun testQueryName( + @Path("id") peopleId: Int, + @QueryName name: String + ): People @GET("people/{id}/") - suspend fun testQueryNameList(@Path("id") peopleId: Int, @QueryName(false) name: List): People - - -} \ No newline at end of file + suspend fun testQueryNameList( + @Path("id") peopleId: Int, + @QueryName(false) name: List + ): People +} diff --git a/sandbox/src/jvmTest/java/TestClass.kt b/sandbox/src/jvmTest/java/TestClass.kt deleted file mode 100644 index 039d09b93..000000000 --- a/sandbox/src/jvmTest/java/TestClass.kt +++ /dev/null @@ -1,22 +0,0 @@ -import com.example.api.createGithubService -import de.jensklingenberg.ktorfit.Ktorfit -import de.jensklingenberg.ktorfit.ktorfit -import org.junit.Assert -import org.junit.Test - -class TestClass { - - private val ktorfit: Ktorfit by lazy { - ktorfit { - baseUrl("https://localhost/") - - } - } - - @Test - fun addition_isCorrect() { - ktorfit.createGithubService() - Assert.assertEquals(4, 2 + 2) - } - -} \ No newline at end of file diff --git a/sandbox/src/linuxX64Main/kotlin/LinuxMain.kt b/sandbox/src/linuxX64Main/kotlin/LinuxMain.kt index 757fca078..051ab0699 100644 --- a/sandbox/src/linuxX64Main/kotlin/LinuxMain.kt +++ b/sandbox/src/linuxX64Main/kotlin/LinuxMain.kt @@ -1,13 +1,17 @@ import com.example.api.JsonPlaceHolderApi import de.jensklingenberg.ktorfit.Ktorfit - -import io.ktor.client.* +import de.jensklingenberg.ktorfit.converter.FlowConverterFactory +import io.ktor.client.HttpClient import kotlinx.coroutines.runBlocking fun main() { - - val linuxKtorfit = Ktorfit.Builder().baseUrl(JsonPlaceHolderApi.baseUrl).httpClient(HttpClient()) - .responseConverter(FlowResponseConverter()).build() + val linuxKtorfit = + Ktorfit + .Builder() + .baseUrl(JsonPlaceHolderApi.baseUrl) + .httpClient(HttpClient()) + .converterFactories(FlowConverterFactory()) + .build() val api = linuxKtorfit.create() runBlocking {