jsonkotlinserializationgsoncompose-desktop

Gson not working after packaging msi - Desktop compose


I'm having a little trouble working on a small project in Desktop Compose. I have the 3 functions below:

package utilities

import com.google.gson.Gson
import serializables.Settings
import java.io.File

fun CheckSettingsFile () {
   if (!File("settings.json").exists()) {
       File("settings.json").createNewFile()
       with(File("settings.json")) {
           val settings = Settings("192.168.1.254","3344")
           val gson = Gson()
           gson.newBuilder().setPrettyPrinting()
           val toWrite = gson.toJson(settings)
           this.writeText(toWrite)
       }
   }
}

fun SaveSettings (s : Settings) {
    val gson = Gson()
    gson.newBuilder().setPrettyPrinting()
    val serialized = gson.toJson(s)
    try {
        with(File("settings.json")) {
            this.writeText(serialized)
        }
    } catch (err :Exception) {
        println(err.message)
    }
}

fun LoadSettings () : Settings {
    val gson = Gson()
    return  gson.fromJson(File("settings.json").readText(), Settings::class.java)
}

While running from IntelliJ IDEA the code works perfectly, but after packaging as msi or exe for Windows I stumble in this error:

Unable to create instance of class serializables.Settings. Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.

I haven't tried to solve it like the error message suggests because I'd like to understand what causes the error in the first place.

Here's the gradle.settings.kts:

import org.jetbrains.compose.desktop.application.dsl.TargetFormat

plugins {
    kotlin("jvm")
    id("org.jetbrains.compose")

}

group = "com.eticket"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
    maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
    google()
}

dependencies {
    implementation("com.google.code.gson:gson:2.10.1")
    implementation(compose.desktop.currentOs)

}

compose.desktop {
    application {
        mainClass = "MainKt"
        nativeDistributions {
            targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb, TargetFormat.Exe)
            packageName = "eTicket"
            packageVersion = "1.0.0"
            windows {
                shortcut = true
                iconFile.set(project.file("stamp-icon.ico"))
                console = false
                menu = true
            }
        }
    }
}

Thanks to everyone who feels to share a hint!


Solution

  • Most likely your Settings class does not have a no-args constructor, so you are currently implicitly relying on sun.misc.Unsafe which is used by Gson to create an instance of this class, see GsonBuilder.disableJdkUnsafe() for more details.

    The class sun.misc.Unsafe is part of the module jdk.unsupported, so you can probably solve this by adding the following to your Gradle settings:

    compose.desktop {
        application {
            ...
            nativeDistributions {
                ...
                modules("jdk.unsupported")
            }
        }
    }
    

    (based on this comment)

    However, note that Gson does not fully support Kotlin (see for example this issue), so it might be better to switch to a library with explicit Kotlin support, such as Moshi, Jackson or kotlinx-serialization.