From dbd33df026fe861a447eb86c3f08342eadbe2edf Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <mail@justjanne.de> Date: Wed, 30 Aug 2023 21:06:43 +0200 Subject: [PATCH] fix: serialization issues --- README.md | 2 - app/build.gradle.kts | 4 +- app/proguard-rules.pro | 2 - app/sampledata/libraries.json | 9 ---- .../quasseldroid/QuasseldroidGlideModule.kt | 29 +++++++------ .../kuschku/quasseldroid/dagger/AppModule.kt | 17 +++----- .../quasseldroid/defaults/DefaultNetwork.kt | 5 ++- .../defaults/DefaultNetworkServer.kt | 5 ++- .../quasseldroid/defaults/DefaultNetworks.kt | 11 +++-- .../ui/clientsettings/about/AboutFragment.kt | 5 --- .../ui/clientsettings/crash/CrashFragment.kt | 15 +------ .../quasseldroid/util/AndroidEmojiProvider.kt | 11 +++-- .../util/avatars/MatrixAvatarInfo.kt | 1 + .../util/avatars/MatrixAvatarResponse.kt | 6 ++- .../util/avatars/MatrixModelLoader.kt | 2 +- .../quasseldroid/util/embed/EmbedHelper.kt | 35 --------------- .../quasseldroid/util/helper/GsonHelper.kt | 43 ------------------- .../quasseldroid/util/emoji/EmojiDataTest.kt | 26 ++++------- build.gradle.kts | 1 + .../main/kotlin/KotlinAndroidConvention.kt | 1 + .../src/main/kotlin/KotlinConvention.kt | 1 + gradle/libs.versions.toml | 10 +++-- malheur/build.gradle.kts | 2 +- malheur/proguard-rules.pro | 20 --------- .../java/de/kuschku/malheur/CrashHandler.kt | 9 ++-- ui_spinner/proguard-rules.pro | 20 --------- viewmodel/build.gradle.kts | 3 +- .../quasseldroid/util/emoji/EmojiHandler.kt | 2 + 28 files changed, 80 insertions(+), 217 deletions(-) delete mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/embed/EmbedHelper.kt delete mode 100644 app/src/main/java/de/kuschku/quasseldroid/util/helper/GsonHelper.kt diff --git a/README.md b/README.md index 0b45d9fb4..50e67f570 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,6 @@ Authors of legacy Quasseldroid: Apache-2.0 * [**Glide**](https://bumptech.github.io/glide/) Apache-2.0 -* [**Gson**](https://github.com/google/gson) - Apache-2.0 * [**JavaPoet**](https://github.com/square/javapoet) Apache-2.0 * [**JetBrains Java Annotations**](https://github.com/JetBrains/java-annotations) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f05695102..d73edfeb8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -89,11 +89,11 @@ dependencies { artifact { classifier = "no-tzdb" } } implementation(libs.annotations.jetbrains) - implementation(libs.gson) implementation(libs.commons.codec) implementation(libs.reactivenetwork) implementation(libs.retrofit.core) - implementation(libs.retrofit.converter.gson) + implementation(libs.retrofit.converter.kotlinx) + implementation(libs.kotlinx.serialization.json) // Quassel implementation(project(":viewmodel")) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 88a5604d1..3f3b15881 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -41,8 +41,6 @@ -dontnote org.apache.http.** # Kotlin stuff -dontnote kotlin.** -# Gson --dontnote com.google.gson.** # Dagger -dontwarn com.google.errorprone.annotations.* # Retrofit diff --git a/app/sampledata/libraries.json b/app/sampledata/libraries.json index 2a3b2c1fe..3c281ff69 100644 --- a/app/sampledata/libraries.json +++ b/app/sampledata/libraries.json @@ -60,15 +60,6 @@ }, "url": "https://bumptech.github.io/glide/" }, - { - "name": "Gson", - "version": "2.8.2", - "license": { - "short_name": "Apache-2.0", - "full_name": "Apache License" - }, - "url": "https://github.com/google/gson" - }, { "name": "Gruvbox", "license": { diff --git a/app/src/main/java/de/kuschku/quasseldroid/QuasseldroidGlideModule.kt b/app/src/main/java/de/kuschku/quasseldroid/QuasseldroidGlideModule.kt index 3e5ef854b..da4eb4481 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/QuasseldroidGlideModule.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/QuasseldroidGlideModule.kt @@ -29,12 +29,13 @@ import com.bumptech.glide.load.model.ModelLoader import com.bumptech.glide.load.model.ModelLoaderFactory import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.module.AppGlideModule -import com.google.gson.GsonBuilder +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import de.kuschku.quasseldroid.util.avatars.MatrixApi import de.kuschku.quasseldroid.util.avatars.MatrixModelLoader import de.kuschku.quasseldroid.viewmodel.data.Avatar +import kotlinx.serialization.json.Json +import okhttp3.MediaType import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory import java.io.InputStream @GlideModule @@ -43,22 +44,26 @@ class QuasseldroidGlideModule : AppGlideModule() { if (!BuildConfig.DEBUG) builder.setLogLevel(Log.ERROR) } + override fun isManifestParsingEnabled() = false + override fun registerComponents(context: Context, glide: Glide, registry: Registry) { val matrixApi = Retrofit.Builder() .baseUrl("https://matrix.org/") - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create())) + .addConverterFactory(Json.asConverterFactory(MediaType.get("application/json"))) .build() .create(MatrixApi::class.java) - registry.append(Avatar.MatrixAvatar::class.java, - InputStream::class.java, - object : ModelLoaderFactory<Avatar.MatrixAvatar, InputStream> { - override fun build( - multiFactory: MultiModelLoaderFactory): ModelLoader<Avatar.MatrixAvatar, InputStream> { - return MatrixModelLoader(matrixApi) - } + registry.append( + Avatar.MatrixAvatar::class.java, + InputStream::class.java, + object : ModelLoaderFactory<Avatar.MatrixAvatar, InputStream> { + override fun build( + multiFactory: MultiModelLoaderFactory + ): ModelLoader<Avatar.MatrixAvatar, InputStream> { + return MatrixModelLoader(matrixApi) + } - override fun teardown() = Unit - }) + override fun teardown() = Unit + }) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/dagger/AppModule.kt b/app/src/main/java/de/kuschku/quasseldroid/dagger/AppModule.kt index 00d0edbbb..1741b19e0 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/dagger/AppModule.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/dagger/AppModule.kt @@ -20,35 +20,30 @@ package de.kuschku.quasseldroid.dagger import android.app.Application -import android.content.Context -import androidx.fragment.app.FragmentActivity -import com.google.gson.Gson -import com.google.gson.GsonBuilder +import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import dagger.Module import dagger.Provides import de.kuschku.quasseldroid.Quasseldroid import de.kuschku.quasseldroid.util.AndroidEmojiProvider import de.kuschku.quasseldroid.util.avatars.MatrixApi import de.kuschku.quasseldroid.util.emoji.EmojiProvider +import kotlinx.serialization.json.Json +import okhttp3.MediaType import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory @Module object AppModule { @Provides fun bindApplication(app: Quasseldroid): Application = app - @Provides - fun provideGson(): Gson = GsonBuilder().setPrettyPrinting().create() - @Provides fun provideMatrixApi(): MatrixApi = Retrofit.Builder() .baseUrl("https://matrix.org/") - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create())) + .addConverterFactory(Json.asConverterFactory(MediaType.get("application/json"))) .build() .create(MatrixApi::class.java) @Provides - fun provideEmojiProvider(context: Application, gson: Gson): EmojiProvider = - AndroidEmojiProvider(context.applicationContext, gson) + fun provideEmojiProvider(context: Application): EmojiProvider = + AndroidEmojiProvider(context.applicationContext) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetwork.kt b/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetwork.kt index fcf364f79..e4f382c9a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetwork.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetwork.kt @@ -19,11 +19,12 @@ package de.kuschku.quasseldroid.defaults -import java.io.Serializable +import kotlinx.serialization.Serializable +@Serializable data class DefaultNetwork( val name: String, val default: Boolean = false, val defaultChannels: List<String> = emptyList(), val servers: List<DefaultNetworkServer> -) : Serializable +) : java.io.Serializable diff --git a/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworkServer.kt b/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworkServer.kt index cca659e8f..9cb3eb78d 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworkServer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworkServer.kt @@ -19,10 +19,11 @@ package de.kuschku.quasseldroid.defaults -import java.io.Serializable +import kotlinx.serialization.Serializable +@Serializable data class DefaultNetworkServer( val host: String, val port: UInt, val secure: Boolean -) : Serializable +) : java.io.Serializable diff --git a/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworks.kt b/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworks.kt index b0f559d82..97aafde0f 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworks.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/defaults/DefaultNetworks.kt @@ -20,16 +20,19 @@ package de.kuschku.quasseldroid.defaults import android.content.Context -import com.google.gson.Gson -import de.kuschku.quasseldroid.util.helper.fromJsonList +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.DecodeSequenceMode +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeToSequence import java.io.IOException import javax.inject.Inject -class DefaultNetworks @Inject constructor(context: Context, gson: Gson) { +@OptIn(ExperimentalSerializationApi::class) +class DefaultNetworks @Inject constructor(context: Context) { val networks: List<DefaultNetwork> by lazy { try { context.assets.open("networks.json").use { - gson.fromJsonList(it.bufferedReader(Charsets.UTF_8)) + Json.decodeToSequence<DefaultNetwork>(it, DecodeSequenceMode.ARRAY_WRAPPED).toList() } } catch (e: IOException) { throw IllegalStateException("networks.json missing from assets.", e) diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt index d8022265c..f92dd3098 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/about/AboutFragment.kt @@ -147,11 +147,6 @@ class AboutFragment : DaggerFragment() { license = apache2, url = "https://bumptech.github.io/glide/" ), - Library( - name = "Gson", - license = apache2, - url = "https://github.com/google/gson" - ), Library( name = "Gruvbox", license = License( diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt index 4e2d2af83..2f594bfa6 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/clientsettings/crash/CrashFragment.kt @@ -30,17 +30,14 @@ import androidx.core.view.ViewCompat import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.google.gson.Gson -import com.google.gson.JsonSyntaxException import dagger.android.support.DaggerFragment import de.kuschku.malheur.CrashHandler import de.kuschku.malheur.data.Report import de.kuschku.quasseldroid.BuildConfig import de.kuschku.quasseldroid.R -import de.kuschku.quasseldroid.util.helper.fromJson import de.kuschku.quasseldroid.util.helper.visibleIf +import kotlinx.serialization.json.Json import java.io.File -import javax.inject.Inject class CrashFragment : DaggerFragment() { lateinit var list: RecyclerView @@ -49,9 +46,6 @@ class CrashFragment : DaggerFragment() { private lateinit var handlerThread: HandlerThread private lateinit var handler: Handler - @Inject - lateinit var gson: Gson - private var crashDir: File? = null private var adapter: CrashAdapter? = null @@ -69,7 +63,6 @@ class CrashFragment : DaggerFragment() { private fun reload() { val crashDir = this.crashDir - val gson = this.gson val context = this.context if (crashDir != null && context != null) { @@ -78,11 +71,7 @@ class CrashFragment : DaggerFragment() { .orEmpty() .map { Pair<Report?, Uri>( - try { - gson.fromJson<Report>(it.readText()) - } catch (e: JsonSyntaxException) { - null - }, + Json.decodeFromString<Report>(it.readText()), FileProvider.getUriForFile(context, "${BuildConfig.APPLICATION_ID}.fileprovider", it) ) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/AndroidEmojiProvider.kt b/app/src/main/java/de/kuschku/quasseldroid/util/AndroidEmojiProvider.kt index a7510c71a..818f301a1 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/AndroidEmojiProvider.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/AndroidEmojiProvider.kt @@ -20,16 +20,19 @@ package de.kuschku.quasseldroid.util import android.content.Context -import com.google.gson.Gson import de.kuschku.quasseldroid.util.emoji.EmojiHandler import de.kuschku.quasseldroid.util.emoji.EmojiProvider -import de.kuschku.quasseldroid.util.helper.fromJsonList +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.DecodeSequenceMode +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeToSequence import java.io.IOException -class AndroidEmojiProvider(context: Context, gson: Gson) : EmojiProvider { +@OptIn(ExperimentalSerializationApi::class) +class AndroidEmojiProvider(context: Context) : EmojiProvider { override val emoji: List<EmojiHandler.Emoji> = try { context.assets.open("emoji.json").use { - gson.fromJsonList(it.bufferedReader(Charsets.UTF_8)) + Json.decodeToSequence<EmojiHandler.Emoji>(it, DecodeSequenceMode.ARRAY_WRAPPED).toList() } } catch (e: IOException) { throw IllegalStateException("emoji.json missing from assets.", e) diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarInfo.kt b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarInfo.kt index 7a3f173c3..50fc6d4a4 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarInfo.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarInfo.kt @@ -19,6 +19,7 @@ package de.kuschku.quasseldroid.util.avatars + data class MatrixAvatarInfo( val avatarUrl: String, val size: Int? diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarResponse.kt b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarResponse.kt index 11cd0d2b3..badd4c342 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarResponse.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixAvatarResponse.kt @@ -19,10 +19,12 @@ package de.kuschku.quasseldroid.util.avatars -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +@Serializable data class MatrixAvatarResponse( - @SerializedName("avatar_url") + @SerialName("avatar_url") val avatarUrl: String? ) diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixModelLoader.kt b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixModelLoader.kt index 3e8f45cb6..11a5ea873 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixModelLoader.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/MatrixModelLoader.kt @@ -28,7 +28,7 @@ import java.io.InputStream class MatrixModelLoader(private val api: MatrixApi) : ModelLoader<Avatar.MatrixAvatar, InputStream> { override fun buildLoadData(model: Avatar.MatrixAvatar, width: Int, height: Int, - options: Options): ModelLoader.LoadData<InputStream>? { + options: Options): ModelLoader.LoadData<InputStream> { return ModelLoader.LoadData(ObjectKey(model), MatrixDataFetcher(model, api)) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/embed/EmbedHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/embed/EmbedHelper.kt deleted file mode 100644 index f93a8e8d5..000000000 --- a/app/src/main/java/de/kuschku/quasseldroid/util/embed/EmbedHelper.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Quasseldroid - Quassel client for Android - * - * Copyright (c) 2020 Janne Mareike Koschinski - * Copyright (c) 2020 The Quassel Project - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package de.kuschku.quasseldroid.util.embed - -import com.google.gson.GsonBuilder -import io.reactivex.Observable -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory - -class EmbedHelper(baseUrl: String) { - private val api = Retrofit.Builder() - .baseUrl(baseUrl) - .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create())) - .build() - .create(EmbedApi::class.java) - - fun embedCode(url: String): Observable<EmbedResponse> = api.embedData(url) -} diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/helper/GsonHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/helper/GsonHelper.kt deleted file mode 100644 index 6789a0c30..000000000 --- a/app/src/main/java/de/kuschku/quasseldroid/util/helper/GsonHelper.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Quasseldroid - Quassel client for Android - * - * Copyright (c) 2023 Janne Mareike Koschinski - * Copyright (c) 2023 The Quassel Project - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package de.kuschku.quasseldroid.util.helper - -import com.google.gson.Gson -import com.google.gson.JsonElement -import com.google.gson.reflect.TypeToken -import java.io.Reader - -inline fun <reified T> Gson.fromJsonList(jsonElement: JsonElement): T = - this.fromJson(jsonElement, object : TypeToken<T>() {}.type) - -inline fun <reified T> Gson.fromJsonList(reader: Reader): T = - this.fromJson(reader, object : TypeToken<T>() {}.type) - -inline fun <reified T> Gson.fromJsonList(text: String): T = - this.fromJson(text, object : TypeToken<T>() {}.type) - -inline fun <reified T> Gson.fromJson(jsonElement: JsonElement): T = - this.fromJson(jsonElement, T::class.java) - -inline fun <reified T> Gson.fromJson(reader: Reader): T = - this.fromJson(reader, T::class.java) - -inline fun <reified T> Gson.fromJson(text: String): T = - this.fromJson(text, T::class.java) diff --git a/app/src/test/java/de/kuschku/quasseldroid/util/emoji/EmojiDataTest.kt b/app/src/test/java/de/kuschku/quasseldroid/util/emoji/EmojiDataTest.kt index ee15c46fb..56a1b4bab 100644 --- a/app/src/test/java/de/kuschku/quasseldroid/util/emoji/EmojiDataTest.kt +++ b/app/src/test/java/de/kuschku/quasseldroid/util/emoji/EmojiDataTest.kt @@ -20,27 +20,18 @@ package de.kuschku.quasseldroid.util.emoji import android.os.Build -import android.text.Editable import android.text.SpannableStringBuilder -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.google.gson.reflect.TypeToken import de.kuschku.quasseldroid.QuasseldroidTest +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.DecodeSequenceMode +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeToSequence import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config -import java.io.Reader - -inline fun <reified T> Gson.fromJson(reader: Reader): T = - if (T::class.java.typeParameters.isEmpty()) { - this.fromJson(reader, T::class.java) - } else { - val type = object : TypeToken<T>() {}.type - this.fromJson(reader, type) - } fun EmojiHandler.replaceShortcodes(source: String): String = this.replaceShortcodes(SpannableStringBuilder(source)).toString() @@ -48,11 +39,12 @@ fun EmojiHandler.replaceShortcodes(source: String): String = @Config(application = QuasseldroidTest::class, sdk = [Build.VERSION_CODES.P]) @RunWith(RobolectricTestRunner::class) class EmojiDataTest { + @OptIn(ExperimentalSerializationApi::class) object TestEmojiProvider : EmojiProvider { - private val gson: Gson = GsonBuilder().create() - override val emoji: List<EmojiHandler.Emoji> = gson.fromJson( - TestEmojiProvider::class.java.getResourceAsStream("/emoji.json")!!.reader(Charsets.UTF_8) - ) + override val emoji: List<EmojiHandler.Emoji> = Json.decodeToSequence<EmojiHandler.Emoji>( + TestEmojiProvider::class.java.getResourceAsStream("/emoji.json"), + DecodeSequenceMode.ARRAY_WRAPPED + ).toList() override val shortcodes: Map<String, EmojiHandler.Emoji> = emoji.flatMap { entry -> entry.shortcodes.map { Pair(it, entry) } }.toMap() diff --git a/build.gradle.kts b/build.gradle.kts index 246daff18..b0c13fd03 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,5 +30,6 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kotlin.kapt) apply false + alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.ksp) apply false } diff --git a/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt b/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt index 0182e7b5d..6e035a976 100644 --- a/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt +++ b/gradle/convention/src/main/kotlin/KotlinAndroidConvention.kt @@ -19,6 +19,7 @@ class KotlinAndroidConvention : Plugin<Project> { apply("org.jetbrains.kotlin.android") apply("org.jetbrains.kotlin.kapt") apply("com.google.devtools.ksp") + apply("org.jetbrains.kotlin.plugin.serialization") } // Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947 diff --git a/gradle/convention/src/main/kotlin/KotlinConvention.kt b/gradle/convention/src/main/kotlin/KotlinConvention.kt index 79b5fb12d..69aeb152f 100644 --- a/gradle/convention/src/main/kotlin/KotlinConvention.kt +++ b/gradle/convention/src/main/kotlin/KotlinConvention.kt @@ -24,6 +24,7 @@ class KotlinConvention : Plugin<Project> { apply("org.jetbrains.kotlin.jvm") apply("org.jetbrains.kotlin.kapt") apply("com.google.devtools.ksp") + apply("org.jetbrains.kotlin.plugin.serialization") } // Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec50abdf6..52e2b01f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,9 +8,10 @@ androidx-test = "1.5.2" dagger = "2.47" glide = "4.16.0" kotlin = "1.9.10" +kotlinx-serialization = "1.6.0" ksp = "1.9.10-1.0.13" materialdialogs = "0.9.6.0" -retrofit = "2.6.1" +retrofit = "2.9.0" [libraries] androidx-annotation = { module = "androidx.annotation:annotation", version = "1.6.0" } @@ -57,11 +58,10 @@ flexbox = { module = "com.google.android.flexbox:flexbox", version = "3.0.0" } google-material = { module = "com.google.android.material:material", version = "1.9.0" } -glide-compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" } +glide-compiler = { module = "com.github.bumptech.glide:ksp", version.ref = "glide" } glide-core = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } glide-recyclerview = { module = "com.github.bumptech.glide:recyclerview-integration", version.ref = "glide" } -gson = { module = "com.google.code.gson:gson", version = "2.9.0" } hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" } junit-api = { module = "org.junit.jupiter:junit-jupiter-engine", version = "5.10.0" } junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version = "5.10.0" } @@ -75,8 +75,10 @@ materialdialogs-core = { module = "com.afollestad.material-dialogs:core", versio materialprogressbar = { module = "me.zhanghai.android.materialprogressbar:library", version = "1.6.1" } reactivenetwork = { module = "com.github.pwittchen:reactivenetwork-rx2", version = "3.0.8" } -retrofit-converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } retrofit-core = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +retrofit-converter-kotlinx = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version = "1.0.0" } + +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } robolectric = { module = "org.robolectric:robolectric", version = "4.7.3" } diff --git a/malheur/build.gradle.kts b/malheur/build.gradle.kts index 4281aee5e..4dc7f0707 100644 --- a/malheur/build.gradle.kts +++ b/malheur/build.gradle.kts @@ -26,6 +26,6 @@ android { } dependencies { - implementation(libs.gson) implementation(libs.androidx.annotation) + implementation(libs.kotlinx.serialization.json) } diff --git a/malheur/proguard-rules.pro b/malheur/proguard-rules.pro index 8c9db7a6d..9fd367499 100644 --- a/malheur/proguard-rules.pro +++ b/malheur/proguard-rules.pro @@ -1,21 +1 @@ -# Gson uses generic type information stored in a class file when working with fields. Proguard -# removes such information by default, so configure it to keep all of it. --keepattributes Signature - -# For using GSON @Expose annotation --keepattributes *Annotation* - -# Gson specific classes --dontwarn sun.misc.** -#-keep class com.google.gson.stream.** { *; } - -# Application classes that will be serialized/deserialized over Gson --keep class com.google.gson.examples.android.model.** { *; } - -# Prevent proguard from stripping interface information from TypeAdapterFactory, -# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) --keep class * implements com.google.gson.TypeAdapterFactory --keep class * implements com.google.gson.JsonSerializer --keep class * implements com.google.gson.JsonDeserializer - -keep class **.BuildConfig { *; } diff --git a/malheur/src/main/java/de/kuschku/malheur/CrashHandler.kt b/malheur/src/main/java/de/kuschku/malheur/CrashHandler.kt index a6f5f21d3..b740237d8 100644 --- a/malheur/src/main/java/de/kuschku/malheur/CrashHandler.kt +++ b/malheur/src/main/java/de/kuschku/malheur/CrashHandler.kt @@ -24,15 +24,14 @@ import android.os.Handler import android.os.HandlerThread import android.util.Log import android.widget.Toast -import com.google.gson.GsonBuilder import de.kuschku.malheur.collectors.ReportCollector import de.kuschku.malheur.config.ReportConfig +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import java.io.File -import java.util.* +import java.util.Date object CrashHandler { - private val gson = GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create() - private val startTime = Date() private var originalHandler: Thread.UncaughtExceptionHandler? = null private var myHandler: ((Thread, Throwable) -> Unit)? = null @@ -62,7 +61,7 @@ object CrashHandler { Toast.makeText(application, "Creating crash report", Toast.LENGTH_LONG).show() } try { - val json = gson.toJson( + val json = Json.encodeToString( reportCollector.collect( CrashContext( application = application, diff --git a/ui_spinner/proguard-rules.pro b/ui_spinner/proguard-rules.pro index 8c9db7a6d..9fd367499 100644 --- a/ui_spinner/proguard-rules.pro +++ b/ui_spinner/proguard-rules.pro @@ -1,21 +1 @@ -# Gson uses generic type information stored in a class file when working with fields. Proguard -# removes such information by default, so configure it to keep all of it. --keepattributes Signature - -# For using GSON @Expose annotation --keepattributes *Annotation* - -# Gson specific classes --dontwarn sun.misc.** -#-keep class com.google.gson.stream.** { *; } - -# Application classes that will be serialized/deserialized over Gson --keep class com.google.gson.examples.android.model.** { *; } - -# Prevent proguard from stripping interface information from TypeAdapterFactory, -# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) --keep class * implements com.google.gson.TypeAdapterFactory --keep class * implements com.google.gson.JsonSerializer --keep class * implements com.google.gson.JsonDeserializer - -keep class **.BuildConfig { *; } diff --git a/viewmodel/build.gradle.kts b/viewmodel/build.gradle.kts index 1fb805a14..2395e8684 100644 --- a/viewmodel/build.gradle.kts +++ b/viewmodel/build.gradle.kts @@ -37,9 +37,10 @@ dependencies { implementation(libs.threetenbp) { artifact { classifier = "no-tzdb" } } - implementation(libs.annotations.jetbrains) + implementation(libs.annotations.jetbrains) implementation(libs.annotations.inject) + implementation(libs.kotlinx.serialization.json) // Quassel implementation(project(":persistence")) diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/util/emoji/EmojiHandler.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/util/emoji/EmojiHandler.kt index 8aeab3382..ff5f3d2f9 100644 --- a/viewmodel/src/main/java/de/kuschku/quasseldroid/util/emoji/EmojiHandler.kt +++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/util/emoji/EmojiHandler.kt @@ -20,10 +20,12 @@ package de.kuschku.quasseldroid.util.emoji import android.text.Editable +import kotlinx.serialization.Serializable import java.util.* import javax.inject.Inject class EmojiHandler @Inject constructor(private val emojiProvider: EmojiProvider) { + @Serializable data class Emoji( val label: String, val tags: List<String>, -- GitLab