I have a problem with serializing data on response to an api call.
It's my first time using this.
Service is called with "Retrofit" and everything goes well, the logs report the request and the response exactly.
Al network is into NetworModule
#Module
#InstallIn(SingletonComponent::class)
object NetworkModule {
#Provides
#Singleton
fun provideHttpClient(): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
)
.addInterceptor { chain ->
val httpUrl: HttpUrl = chain.request().url.newBuilder().build()
val request: Request = chain.request().newBuilder().url(httpUrl).build()
chain.proceed(request)
}
.build()
#Provides
#Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.client(okHttpClient)
.build()
#Provides
fun provideApiNetwork(retrofit: Retrofit): RetrofitApiNetwork =
retrofit.create(RetrofitApiNetwork::class.java)
}
response in json is:
{
"response": {
"info": {
...
},
"body": {
...
}
}
}
the problem comes in constructing a generic model with generic type.
Interface of calls:
interface RetrofitApiNetwork {
#GET("....")
suspend fun getElements(): APINetworkResponse<Element>
}
Generic models is:
#Serializable
data class APINetworkResponse<T>(
val response: Response<T>
)
#Serializable
data class Response<T>(
val info: Info,
val body: T
)
The value of APINetworkResponse<Element> is APINetworkResponse(response=null)
Can someone help me understand why and give me the solution. Thanks
Update
add repository:
class DataRepository #Inject constructor(
private val retrofitApiNetwork: RetrofitApiNetwork
){
suspend fun getArtistChart(): Flow<Element> = flow {
val apiNetworkResponse: APINetworkResponse<Element> = retrofitApiNetwork.getElements()
println(apiNetworkResponse) /*APINetworkResponse(response=null)*/
}
}
add dependecies:
[versions]
androidGradlePlugin = "7.3.1"
kotlin = "1.7.10"
kotlinDsl = "2.3.3"
junit = "4.13.2"
junitExt = "1.1.4"
testCore = "1.5.0"
espresso = "3.5.0"
coreKtx = "1.9.0"
appcompat = "1.5.1"
material = "1.7.0"
retrofit = "2.9.0"
hilt = "2.44.2"
nav = "2.5.3"
[libraries]
android-pluginGradle = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
kotlin-pluginGradle = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitExt" }
espresso = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
androidx-test-core = { group = "androidx.test", name = "core", version.ref = "testCore" }
androidx-test-core-ktx = { group = "androidx.test", name = "core-ktx", version.ref = "testCore" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
android-material = { group = "com.google.android.material", name = "material", version.ref = "material" }
android-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
android-retrofit-converter = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
android-navigation = { group = "androidx.navigation", name = "navigation-fragment", version.ref = "nav" }
android-navigation-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "nav" }
android-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "nav" }
android-hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
android-hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-dsl = { id = "org.gradle.kotlin.kotlin-dsl", version.ref = "kotlinDsl" }
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
```
None of the answers were successful. I fixed it by adding rules to the application proguard-rules file.
I followed this documentation.
You are using a suspend function to get the results using Coroutines, so make sure you have these dependencies on your project:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
Check for the latest versions, I'm using 1.6.4 at the time of writing this response.
Without these dependencies, Retrofit doesn't know about transforming a coroutine function and when the code is compiled, the mapper is unaware of the models because of the suspend function.
The problem is that you are using the data keyword when defining the classes which creates the component1(), component2(), etc. automatically, but those functions do not support generics.
Instead, you should use the #Serializable annotation on the class, and use #SerialName on the variables.
Try changing your classes to this:
#Serializable
class APINetworkResponse<T> (
#SerialName("response") val response: Response<T>
)
#Serializable
class Response<T> (
#SerialName("info") val info: Info,
#SerialName("body") val body: T
)
Also, you should make sure that the Element class is serializable. You can use the #Serializable annotation on it too.
I want to create a script for publish a library on kotlin.
I am trying to convert this gradle config to gradle-kotlin (kts) following the gradle documentation (https://docs.gradle.org/current/userguide/publishing_maven.html#header) but I have this error when project builds:
FAILURE: Build failed with an exception.
Where:
Script '.../gradle-mvn-push.gradle.kts' line: 18
SourceSet with name 'main' not found.
Here is the script in kts:
Kotlin version : 1.6.10
Kotlin-gradle plugin version : 7.2.1
apply(plugin = "maven-publish")
var gitLabPrivateToken: String? = null
val secretPropertiesFile = rootProject.file("example.properties")
if (secretPropertiesFile.exists()) {
val secretProperties = java.util.Properties().apply {
load(java.io.FileInputStream(secretPropertiesFile))
}
gitLabPrivateToken = secretProperties["token"].toString()
}
val gitlabUrl = "exampleUrl"
lateinit var sourcesArtifact: PublishArtifact
tasks {
val sourcesJar by creating(Jar::class) {
archiveClassifier.set("sources")
from(project.the<SourceSetContainer>()["main"].allSource)
}
artifacts {
sourcesArtifact = add("archives", sourcesJar)
}
}
afterEvaluate {
configure<PublishingExtension> {
publications {
create<MavenPublication>("maven") {
artifact(sourcesArtifact) // Adds source as separate jar.
groupId = "com.example"
artifactId = "lib"
version = "0.1.0"
from(components["release"])
}
}
repositories {
maven {
name = "GitLabPersonal"
url = uri(gitlabUrl)
credentials(HttpHeaderCredentials::class) {
name = "Private-Token"
value = gitLabPrivateToken
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
maven {
name = "GitLabCi"
url = uri(gitlabUrl)
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
}
DataStore and preferencesDataStore are absent in this version(beta01).
To do this, you need to:
plugins {
id("com.google.protobuf")
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.17.3"
}
generateProtoTasks {
all().forEach { task ->
task.builtins {
create("java") {
option("lite")
}
}
}
}
implementation("androidx.datastore:datastore-core:1.0.0-beta01")
implementation("com.google.protobuf:protobuf-javalite:3.11.0")
implementation("androidx.preference:preference-ktx:1.1.1")
and initialize
val data: DataStore<SomeMessage> = DataStoreFactory.create(
serializer = SessionSerializer, // your Serializer
corruptionHandler = null,
migrations = emptyList(),
scope = CoroutineScope(Dispatchers.IO + Job())
And continue as before
data.updateData {
it.toBuilder().setAddress("address").build()
}
data.collect { ChargingSession ->
ChargingSession.address
}
Use the below dependency
implementation("androidx.datastore:datastore-preferences:1.0.0-beta01")
I am trying to get https://github.com/Kotlin/kotlinx.serialization to work with my android library I am building using kotlin mpp. This is my gradle file
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.multiplatform")
kotlin("plugin.serialization") version "1.3.61"
}
group = "org.greeting"
version = 1.0
android {
compileSdkVersion(27)
defaultConfig {
minSdkVersion(15)
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
dependencies {
// Specify Kotlin/JVM stdlib dependency.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7")
implementation(kotlin("stdlib", org.jetbrains.kotlin.config.KotlinCompilerVersion.VERSION)) // or "stdlib-jdk8"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0") // JVM dependency
testImplementation("junit:junit:4.12")
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
androidTestImplementation("junit:junit:4.12")
androidTestImplementation("org.jetbrains.kotlin:kotlin-test")
androidTestImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
kotlin {
android("androidLib")
val buildForDevice = project.findProperty("device") as? Boolean ?: false
val iosTarget = if (buildForDevice) iosArm64("ios") else iosX64("ios")
iosTarget.binaries {
framework {
// Disable bitcode embedding for the simulator build.
if (!buildForDevice) {
embedBitcode("disable")
}
}
}
sourceSets["androidLibMain"].dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0")
}
sourceSets {
commonMain {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.14.0")
}
}
commonTest {
dependencies {
implementation("org.jetbrains.kotlin:kotlin-test-common")
implementation("org.jetbrains.kotlin:kotlin-test-annotations-common")
}
}
}
}
tasks.register("copyFramework") {
val buildType = project.findProperty("kotlin.build.type") as? String ?: "DEBUG"
dependsOn("link${buildType.toLowerCase().capitalize()}FrameworkIos")
doLast {
val srcFile = (kotlin.targets["ios"] as KotlinNativeTarget).binaries.getFramework(buildType).outputFile
val targetDir = project.property("configuration.build.dir")!!
copy {
from(srcFile.parent)
into(targetDir)
include("greeting.framework/**")
include("greeting.framework.dSYM")
}
}
}
tasks.register("iosTest") {
val device = project.findProperty("iosDevice") as? String ?: "iPhone 8"
dependsOn("linkDebugTestIos")
group = JavaBasePlugin.VERIFICATION_GROUP
description = "Runs tests for target 'ios' on an iOS simulator"
doLast {
val binary = (kotlin.targets["ios"] as KotlinNativeTarget).binaries.getTest("DEBUG").outputFile
exec {
commandLine("xcrun", "simctl", "spawn", "--standalone", device, binary.absolutePath)
}
}
}
When I try to run build i get Unresolved reference: serialization on line import kotlinx.serialization.ImplicitReflectionSerializer; But if compile the androidTests the linking works fine. Strangely i have to do sourceSets["androidLibMain"] and can't include it in the sourceSet{} block not sure if this is related. Any ideas on why the build task is not linking my serialization library? Thanks
I wrote a library with Kotlin MultiPlatform (link)
I can add the library as a jar file to the project
But now I want to do this with bintray
I went ahead with the Link, but I had a problem
My problem was that the value of publicationName variable I was giving Gradle was wrong for me :
val publicationName = "MySharedCode"
publishing {
publications.invoke {
publicationName(MavenPublication::class) {
artifactId = artifactID
artifact(shadowJar)
pom.addDependencies()
}
}
}
Gradle Sync Error : Publication with name 'MySharedCode' not found.
My Kotlin Gradle DSL File :
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.jfrog.bintray.gradle.BintrayExtension
import org.gradle.api.publish.maven.MavenPom
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
`maven-publish`
id("com.jfrog.bintray") version "1.8.4"
id ("com.github.johnrengelman.shadow") version "5.2.0"
java
}
val ktorVersion = "1.3.0-rc2"
val serialization = "0.11.0"
val coroutines = "1.2.1"
project.group = "com.my.domain"
project.version = "0.0.3"
val artifactID = "my-shared-lib"
kotlin {
//select iOS target platform depending on the Xcode environment variables
val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
::iosArm64
else
::iosX64
iOSTarget("ios") {
binaries {
framework {
baseName = "MySharedCode"
}
}
}
jvm("android")
sourceSets["commonMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
// HTTP
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-json:$ktorVersion")
implementation("io.ktor:ktor-client-serialization:$ktorVersion")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutines")
}
sourceSets["androidMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// HTTP
implementation("io.ktor:ktor-client-android:$ktorVersion")
implementation("io.ktor:ktor-client-json-jvm:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-jvm:$ktorVersion")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines")
}
sourceSets["iosMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
// HTTP
implementation("io.ktor:ktor-client-ios:$ktorVersion")
implementation("io.ktor:ktor-client-json-native:$ktorVersion")
implementation("io.ktor:ktor-client-serialization-iosx64:$ktorVersion")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutines")
}
}
val packForXcode by tasks.creating(Sync::class) {
group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val framework = kotlin.targets.getByName<KotlinNativeTarget>("ios").binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
val targetDir = File(buildDir, "xcode-frameworks")
from({ framework.outputDirectory })
into(targetDir)
doLast {
val gradlew = File(targetDir, "gradlew")
gradlew.writeText("#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$#\n")
gradlew.setExecutable(true)
}
}
tasks.getByName("build").dependsOn(packForXcode)
val shadowJar: ShadowJar by tasks
shadowJar.apply {
baseName = artifactID
classifier = null
}
fun MavenPom.addDependencies() = withXml {
asNode().appendNode("dependencies").let { depNode ->
configurations.commonMainImplementation.allDependencies.forEach {
depNode.appendNode("dependency").apply {
appendNode("groupId", it.group)
appendNode("artifactId", it.name)
appendNode("version", it.version)
}
}
}
}
val publicationName = "MySharedCode"
publishing {
publications.invoke {
publicationName(MavenPublication::class) {
artifactId = artifactID
artifact(shadowJar)
pom.addDependencies()
}
}
}
fun findProperty(s: String) = project.findProperty(s) as String?
bintray {
user = "xxxx"
key = "xxxx"
publish = true
setPublications(publicationName)
pkg(delegateClosureOf<BintrayExtension.PackageConfig> {
repo = "lib"
name = "my repo name"
userOrg = "my user org"
websiteUrl = "https://my-domain.com/"
githubRepo = "myRepo"
vcsUrl = "myRepo url"
description = "my repo description"
setLabels("kotlin")
setLicenses("MIT")
desc = description
})
}
tasks {
withType(GradleBuild::class.java) {
dependsOn(shadowJar)
}
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
withType(Test::class.java) {
testLogging.showStandardStreams = true
}
withType<GenerateMavenPom> {
destination = file("$buildDir/libs/${shadowJar.name}.pom")
}
}
You should create a gradle script for publishing mechanism by bintray and apply that into build.gradle.kts of MMP project scope.
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.multiplatform")
}
apply(from = rootProject.file("publishSystem/publish.gradle"))
//
//
//
//
In the following put that it publishLibraryVariants in android extension into kotlin extension
kotlin {
android { publishLibraryVariants("release") }
//
//
//
//
}
This my first time seeing the "bintray" in Kotlin DSL.
But as per their documentation
bintray {
user = "xxxx"
key = "xxxx"
publish = true
publications = [publicationName] // this is an array
pkg {
repo = "lib"
name = "my repo name"
vcsUrl = "myRepo url"
licenses = ["MIT"]
version {
name = "1.0.0"
desc = "Release one Woraay ^_^"
released = new Date()
}
}
}
Personally, I'm using something else on my end. Why don't you try this one out?
publishing {
repositories.maven("https://api.bintray.com/maven/THE REST OF THE URL;publish=1") {
name = "bintray"
credentials {
username = "ADMIN"
password = "ADMIN"
}
}
publications {
register("plugin", MavenPublication::class) {
groupId = "com.example.MySharedCode"
artifactId = "MySharedCode"
version = "1.0.0"
from(components["java"])
}
}
}
gradlePlugin {
plugins {
create("Gradle-Plugin") {
this.id = "com.example.MySharedCode"
this.implementationClass = "com.example.MySharedCode.gradle.MainClassNameHere"
}
}
}